我有一个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框架还是陌生的,但是对我来说,这似乎确实很麻烦(即使它可以工作)。鉴于我到目前为止所读的有关FormSets的知识,还有没有更好的方法来实现这一点?
答案 0 :(得分:1)
由于未提供模型代码,所以我只是在猜测您的想法:
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)
也许您的原始代码可以工作,但只需要改进即可(因此,我认为这不是“ hacky”)。您将Tag
QuerySet放入for循环中,以便在每次迭代时都将命中数据库。首先要从db获取所有标记值,然后比较差异,然后做进一步的工作可能是更好的方法。
此外,我认为不应将标签创建放入form_valid
中,因为这是一个“模型过程”。覆盖save()
模型的Topic
方法或使用Signal可能是更好的选择。但这只是我的选择,您仍然可以保持不变。
答案 1 :(得分:0)
我想出了一种更可接受的解决方案,将模型创建排除在View()
和Form()
中,因为form_class
仍然可以定义CreateView()
。
我从堆栈溢出处理标签的方式中汲取了灵感,因为它们接受一个字符串并在'+'
上拆分每个标签。
也许有一种方法可以进一步改善这一点,但是在这种情况下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)