Django使用提交的模型表单数据创建不同模型的新实例



我有一个Topic模型,它在Tag模型中有一个ManyToManyField。类似于堆栈溢出,您可以在提问时提交新标签。我希望在创建主题时能够创建新标签。

我脑海中浮现出一个棘手的解决方案。

Class TopicCreateView(CreateView):
model = Topic
template_name = 'blah'
fields = [
'blah'
]
def form_valid(self, form):
tags = self.request.POST.getlist(tags)
for tag in tags:
if not Tag.objects.filter(tag_string__iexact=tag):
try:
new_tag = Tag.objects.create(tag_string=tag)
except IntegrityError:
# stuff
return super().form_valid(form)

一般来说,我对Django和web框架都是新手,但这对我来说似乎真的很难(如果它真的有效的话(。考虑到我到目前为止所读到的关于FormSet之类的内容,没有更好的方法来实现这一点吗?

由于没有提供模型代码,我只是猜测您在想什么:

def form_valid(self, form):
tags = self.request.POST.getlist('tags')
existed_tags = Tag.objects 
.filter(tag_string__iexact=tags) 
.values_list('tag_string', flat=True)
new_tags = set(tags) - set(existed_tags)
for tag in new_tags:
Tag.objects.create(tag_string=tag)
return super().form_valid(form)

也许你的原始代码可以工作,但只需要改进(因此我不认为它是"黑客"(。您将TagQuerySet放在for循环中,这样数据库在每次迭代时都会被命中。先从数据库中获取所有标签值,然后比较差异并做进一步的工作可能是更好的方法。

此外,我认为标记创建不应该放在form_valid中,因为这是一个"模型过程"。替代Topic模型的save()方法或使用Signal可能是更好的选择。然而,这只是我的偏好,你仍然可以保持不变。

我提出了一个更可接受的解决方案,将模型创建保留在View()Form()之外,因为用CreateView()定义form_class仍然是可能的
我从堆栈溢出如何处理标记中获得了灵感,因为它们接受一个字符串并在'+'上拆分每个标记。

可能有一种方法可以进一步改进这一点,但在这种情况下,FormSets似乎不是可行的选择。

Class TopicCreateForm(forms.ModelForm)
submitted_tags = forms.CharField(max_length=256)
class Meta:
model = Blah
fields = ['blah']
def clean_submitted_tags(self):
tags = self.cleaned_data.get(
'submitted_tags').split("+")
# validation here
return tags
def save(self, *args, **kwargs):
# get author from form instance
author = self.instance.author 
tags = self.cleaned_data['submitted_tags']
existing_tags = Tag.objects.values_list(
'tag_string', flat=True)
for tag in [t for t in tags if t not in existing_tags]:
new_tag = Tag.objects.create(
tag_string=tag,
created_by=author)
new_tags = Tag.objects.filter(tag_string__in=tags)
new_tag_uuids = [t.pk for t in new_tags]
self.cleaned_data['tags'] = new_tag_uuids
return super().save(*args, **kwargs)

最新更新