Django使用模型的已提交表单数据创建其他模型的新实例

时间:2018-08-05 02:16:45

标签: django django-models django-forms

我有一个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的知识,还有没有更好的方法来实现这一点?

2 个答案:

答案 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)