Django中的多对一关系

时间:2014-03-31 19:00:13

标签: python django django-models django-forms django-views

我有两个型号

class Model_1(models.Model):
    foreign_key_field = models.ForeignKey(Model_2)

class Model_2(models.Model):
    number = models.IntegerField()

我需要一个ModelForm来编辑Model_2对象。在该表单中,我想要一个包含所有Model_1对象的列表,以及用于复选那些应该使用特定Model_2对象作为ForeignKey的Model_1字段的选项。

实际上,它应该像ManyToMany字段一样工作,但是在ManyToOne关系中。

也许ModelForm看起来像这样:

class SetForeignKeyForm(ModelForm):
    is_linked = BooleanField(required=False)

    class Meta:
        model = ModelName
        fields = ()

    def clean_is_linked(self):
        if self.cleaned_data['is_linked']:
            self.fields['foreign_key_field'] = self.object

和视图:

class Model2UpdateView(ModelFormSetView):
    model = Model_2
    form_class = SetForeignKeyForm

    def get_queryset(self):
        return Model_2.objects.all()

我不知道如何在我的自定义ModelForm中获取Model_2对象,所以我不知道如何保存Model_1对象是否链接到特定的Model_2对象。

我最终会看到类似

的输出
<h1>Model_2 object</h1>
<form method="post" action="">
  <tr>
    <td>Model1 object name</td>
    <td><input type="checkbox" name="model1_id_1" /></td>
  </td>
  <tr>
    <td>Model1 object name</td>
    <td><input type="checkbox" name="model1_id_2" checked="checked" /></td>
  </td>
  <tr>
    <td>Model1 object name</td>
    <td><input type="checkbox" name="model1_id_3" /></td>
  </tr>
  <input type="submit" />
</form>

修改1

我做了一些似乎有用的东西,但我不确定它是否正确完成。

我有一个观点

class Model2Detail(ModelFormSetView):
    model = Model1
    template_name = 'tpl.html'
    form_class = PairingForm
    extra = 0

    def get_queryset(self):
        self.object = get_object_or_404(Model2, slug=self.kwargs['slug'])
        return Model1.objects.all() # those objects with ForeignKey field

    def formset_valid(self, formset):
        for form in formset:
            form.instance.foreign_key_field = self.object # set Model1's ForeignKey field
            form.save()
        return HttpResponseRedirect(self.get_success_url())

    def get_success_url(self):
        return self.object.get_absolute_url()

和表格

class PairingForm(ModelForm):
    is_linked = BooleanField(required=False)

    class Meta:
        fields = ()
        model = Model2 # those objects __without__ ForeignKey field

    def __init__(self, *args, **kwargs):
        super(PairingForm, self).__init__(*args, **kwargs)
        if self.instance.foreign_key_field: # if object already paired
            self.fields['is_linked'].initial = True

    def save(self, commit=True, force_insert=False, force_update=False, *args, **kwargs):
        obj = super(PairingForm, self).save(commit=False, *args, **kwargs)
        if self.cleaned_data['is_linked']:
            obj.foreign_key_field = self.instance.entry
        else:
            obj.foreign_key_field = None # remove pairing
        obj.save()

对我而言,我尝试在视图和表单中设置ForeignKey字段似乎是错误的,但我不知道应该如何。

修改2

我的代码有效,但实际上我不知道为什么。如果我没有在formset_valid中设置外键字段,则它不再起作用,所以我觉得有些问题。我不应该在没有覆盖formset_valid的情况下使其工作吗?我是否在我的表单中使用Meta.model中的正确模型?

1 个答案:

答案 0 :(得分:0)

我认为在表单中仅修改一种类型的对象是一种好习惯。这样可以保持事物的分离,而且我相信,这会使预期的行为更加清晰。

考虑到这一点,我认为您应该将此视为“编辑Model_2对象”,而不是将其视为“编辑一堆Model_1对象”,方法是在每个对象上设置或取消设置值。在该体系结构中,您可以使用表单集,每个表单都有一个复选框字段(例如,is_linked)。在formset的save_newsave_existing方法中,您可以检查该字段并相应地在要保存的特定对象上设置外键。

您的更新版本看起来非常不错。我看到的唯一问题是你的formset_valid方法似乎为表单中的每个对象设置了外键字段,但你真的只想在is_linked为True时设置它,对吧?在我看来ParingForm实际上在保存时做了正确的事情,因此您不需要在formset_valid中设置值。