【问题标题】:Saving M2M relationship via inline formset通过内联表单集保存 M2M 关系
【发布时间】:2016-01-01 07:12:37
【问题描述】:

我花了很多时间来寻找一个我认为应该是 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

我有一个联系人模型的表单,并在其中包含了一个用于地址的内联表单集。这个想法是我在联系人表单中有一个地址多选小部件(从已保存的地址中选择)并通过内联表单集动态添加新地址。

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

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

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

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

  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()

请帮帮我,这太疯狂了。一定有办法让这项工作,对吧?我没看到什么?

【问题讨论】:

  • “顺便说一下,地址模型与联系人模型有外键关系,否则我无法使用内联表单集” - 这是否意味着您在 Contact 之间有两种关系和Address(在Contact 模型中指定的ManyToMany 和Address 模型中的ForeignKey)?
  • 没错。这没有多大意义,但是 - 正如我所说 - 否则我在查看创建/更新表单时收到 Django 错误,指出地址模型需要联系人模型的外键。我刚刚更新了上面的模型描述。
  • 现在在重置我的迁移(需要)并尝试进行初始迁移(使用现有表)之后,我在循环依赖 Django 错误中再次运行:django.db.migrations.graph.CircularDependencyError: address.0001_initial,contacts.0001_initial 我以前有过这个,不知怎的,当我发布我的问题时,我让它工作了。但总的来说,拥有 ForeignKey ManyToMany 关系似乎不起作用。但是,我仍然无法相信 Django 无法实现图示的用例,它对我来说只是一个基本功能。解决办法是什么?

标签: django formset inline-formset m2m


【解决方案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,所以我不能肯定地说。

【讨论】:

  • 嗨,丹尼,感谢您的帮助。事实上,我已经在使用“字符串映射”来避免循环依赖。上面的例子只是我真实模型的抽象。出于某种原因,我让带有外键的多线程再次工作而没有循环依赖错误(不要问我这里发生了什么;)但是:主要问题仍然存在:我通过内联表单集创建的地址实例保存在addresses.address 表 - 但不是 manytomany-relationship(意味着通过自动创建的表在 contacts_contact_addresses 中没有条目):(
猜你喜欢
  • 1970-01-01
  • 2011-03-05
  • 2015-12-13
  • 2020-04-13
  • 1970-01-01
  • 1970-01-01
  • 2013-04-07
  • 2016-05-07
  • 1970-01-01
相关资源
最近更新 更多