通过内联formset保存M2M关系

时间:2015-10-04 15:03:00

标签: django formset inline-formset m2m

我花了很多时间寻找一个我认为应该是Django基本功能的功能。但是我无法让它工作,或者只是不可能使用Django - 这将是非常令人失望的......

好的,我有两个模型,让我们说一个Contact和一个Address模型。联系人可以有多个地址,地址可能属于多个联系人。经典的多对多关系。

class Contact(models.Model):
    ... (some other attributes)
    addresses = models.ManyToManyField(Address)

class Address(models.Model):
    ... (some attributes)
    contact = models.ForeignKey(Contact) # <- needed for inline formset

我有一个Contact模型的表单,其中包含一个Addresses的内联formset。我的想法是,我在联系表单中有一个Addresses MultiSelect小部件(从已保存的地址中选择),并通过内联formset动态添加新的地址。

但是,通过内联formset添加地址将保存地址实例,但不会保存直通表中的条目以标记联系人与新保存的地址之间的关系。这也意味着在使用EditView查看Contact实例时,MultiSelect字段中未选中此新保存的地址。

我在保存Address和Contact实例时使用save(commit=False),因为我需要在保存之前添加其他数据。我知道你必须以某种方式使用save_m2m(),但它不起作用。

顺便说一下,Address模型与Contact模型有外键关系,否则我无法使用内联formset。

当表单有效且即将保存时,我的一些代码:

  self.object = form.save(commit=False)
  self.object.someAttribute = theAttributeValue # just adding some attribute
  self.object.save()
  # In case there is a many-to-many relationship to another model, we need to use the save_m2m() method
  form.save_m2m()

  for formset in formsets:
      formset.instance = self.object
      saved_formset = formset.save(commit=False)

      """
      If you call formset.save(commit=False), objects will not be deleted automatically. You’ll need to call
      delete() on each of the formset.deleted_objects to actually delete them. See also: https://docs.djangoproject.com/en/1.8/topics/forms/formsets/#django.forms.formsets.BaseFormSet.can_delete
      """
      for obj in formset.deleted_objects:
          obj.delete()

      for form in saved_formset:
          form.someAttribute = theAttributeValue
          form.save()

      formset.save_m2m()

请帮帮我,这只是变得疯狂。必须有办法让这项工作,对吗?我没看到什么?

1 个答案:

答案 0 :(得分:1)

要管理您的循环相关性,我建议您从以下地址切换:

class Contact(models.Model):
    ... (some other attributes)
    addresses = models.ManyToManyField(Address)

class Address(models.Model):
    ... (some attributes)
    contact = models.ForeignKey(Contact) # <- needed for inline formset

为:

class Contact(models.Model):
    ... (some other attributes)
    addresses = models.ManyToManyField('myapp.Address')

class Address(models.Model):
    ... (some attributes)
    contact = models.ForeignKey('myapp.Contact') # <- needed for inline formset

你是否看到我如何定义关系的区别?我传入模型类的'字符串映射',而不是传入模型类。然后Django处理剩下的事情。

应该处理您的循环依赖问题。并且可能解决formsets带来的任何故障。但是,由于我倾向于远离formsets,我无法肯定地说。