我有一个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)
也许你的原始代码可以工作,但只需要改进(因此我不认为它是"黑客"(。您将Tag
QuerySet放在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)