【问题标题】:Many to one relationship in DjangoDjango中的多对一关系
【发布时间】:2014-03-31 19:00:12
【问题描述】:

我有两个模型

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 字段的选项。

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

也许 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 中使用了正确的模型?

【问题讨论】:

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


    【解决方案1】:

    我认为在表单中只修改一种类型的对象是一种很好的做法。这使事情分开,并且我相信会导致具有预期行为的更简洁的设计。

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

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

    【讨论】:

    • 好主意。但是,如果表单集中的对象和特定表单已链接,我如何将复选框标记为已选中?我浏览了文档,但似乎找不到方法。
    • 在表单集的情况下,initial 参数是一个字典列表,它可能会给你你想要的。您也可以考虑覆盖 add_field 方法。
    • 更新了我的答案。你的代码看起来很不错。它对你有用吗?
    猜你喜欢
    • 1970-01-01
    • 2015-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-05
    • 2011-06-22
    • 2018-08-28
    • 2013-04-06
    相关资源
    最近更新 更多