Django多对多(m2m)与同一模型的关系

Posted

技术标签:

【中文标题】Django多对多(m2m)与同一模型的关系【英文标题】:Django Many-to-Many (m2m) Relation to same model 【发布时间】:2012-07-28 02:25:09 【问题描述】:

我想在用户类对象之间创建多对多关系。

我有这样的事情:

class MyUser(models.Model):
    ...
    blocked_users = models.ManyToManyField(MyUser, blank=True, null=True)

问题是我是否可以在其内部使用类引用。或者我是否必须在ManyToManyField 中使用"self" 而不是"MyUser"?或者还有其他(更好的)方法吗?

【问题讨论】:

在同一个模型上定义多对多有什么用??任何人请 @ParaM 例如,如果你有一个树状结构。主产品有子产品等。 “在同一模型上定义多对多有什么用?” 允许每个用户拥有自己的已阻止(或关注)的其他用户列表。 最佳用例是模型的树形结构。 【参考方案1】:

从技术上讲,我很确定“MyUser”或“self”会起作用,只要它在任何一种情况下都是字符串。你只是不能通过MyUser,实际的课程。

但是,文档总是使用“self”。使用“self”不仅更明确地说明实际发生的事情,而且不受类名更改的影响。例如,如果您后来将MyUser 更改为SomethingElse,那么您还需要更新对“MyUser”的任何引用。问题是因为它是一个字符串,你的 IDE 不会提醒你错误,所以你错过它的可能性更大。无论现在或将来类的名称是什么,都可以使用“self”。

【讨论】:

在同一模型上定义多对多有什么用??任何人请 @ParaM 一个例子:您希望指定“相关文章”的文章模型 一个个人示例是一个代理,其字段指定招募他们的代理。【参考方案2】:
class MyUser(models.Model):
    ...
    blocked_users = models.ManyToManyField("self", blank=True)

【讨论】:

"self" 不起作用。使用blocked_users = models.ManyToManyField("MyUser", blank=True, null=True) 我没有说“MyUser”,我说的是“self”:docs.djangoproject.com/en/dev/ref/models/fields/… null=True 对 ManyToManyFields 没有影响【参考方案3】:

如果您对相关对象使用 .clear() 或 .add() 方法并且不想在关系的另一侧更新自己的关系字段中的数据,请不要忘记使用symmetric=False。

some_field = models.ManyToManyField('self', symmetrical=False)

【讨论】:

【参考方案4】:

我认为它应该是类名而不是自我。因为像这样使用 self

parent = models.ManyToManyField('self', null=True, blank=True)

当我添加父母时:

user1.parent.add(user2)

我在数据库中有 2 条记录,如下所示:

使用类名如下:

parent = models.ManyToManyField('User', null=True, blank=True)

我在数据库中有一条这样的记录:

请注意,我使用 uuid 进行 pk,我使用 django 3.1

编辑: 正如@shinra-tensei 在this answer 中的评论所解释的那样,如果我们使用self,我们必须将symmetrical 设置为False。记录在Django Documents: ManyToManyField.symmetrical

【讨论】:

您使用的是什么数据库适配器?那里可能是一个错误...... @Ron postgres 和 mysql【参考方案5】:

如果您使用 selfMyUser 在这两种情况下都会收到 NameError。您应该将 "self" 写为字符串。请看下面的例子:

class MyUser(models.Model):
    ...
    blocked_users = models.ManyToManyField("self", blank=True, null=True)

如果关系不对称,不要忘记将 symmetrical 属性设置为 False

更多详情请查看:https://docs.djangoproject.com/en/3.0/ref/models/fields/#django.db.models.ManyToManyField

【讨论】:

【参考方案6】:

在ManyToManyField中不要使用'self',当使用django表单提交时会导致你的对象相互链接

class Tag(models.Model):
    ...
    subTag = models.ManyToManyField("self", blank=True)

 ...
 aTagForm.save()

结果:

 a.subTag == b
 b.subTag == a

【讨论】:

有什么建议吗?我从来没有遇到过问题。 我在我的演示中发现了它,最后我使用 ManyToManyField("Tag", blank=True) 来修复它 如果您不希望对象相互链接,请在创建字段 docs.djangoproject.com/en/2.2/ref/models/fields/… 时使用参数 symmetrical = False ,它的存在允许您使用 'self' 名称而不是型号名称

以上是关于Django多对多(m2m)与同一模型的关系的主要内容,如果未能解决你的问题,请参考以下文章

具有外键和多对多关系的 Django 模型与同一模型

Django:如何聚合/注释多对多关系?

Django自引用多对多模型

当我使用中间模型时,如何建立强制唯一性的多对多关系?

TypeError:禁止直接分配到多对多集合的前向端。请改用 meeting.set()。 Django m2m 字段出错

使 ModelForm 与 Django 中的中间模型的多对多关系工作的步骤是啥?