related_name用于什么?

664

related_name参数在ManyToManyFieldForeignKey字段上有什么用处?例如,鉴于以下代码,related_name = 'maps'的效果是什么?

class Map(db.Model):
    members = models.ManyToManyField(User, related_name='maps',
                                     verbose_name=_('members'))

19
在不需要反向关系的情况下使用related_name='+'对性能或最佳实践是否有好处? - lajarre
15
我很想知道 @lajarre 的问题的答案。 - 3cheesewheel
2
@lajarre - 我认为这不会影响性能。我曾经在FeinCMS内容类型中使用过它。我个人认为,始终指定related_name是一个好习惯,所以如果你知道自己不会使用它,那么我认为这是一件好事。当然,这只是个人意见。 - François Constant
3
@3cheesewheel,现在已经在文档中了:https://docs.djangoproject.com/en/2.0/ref/models/fields/#django.db.models.ForeignKey.related_name。`+` 表示不创建反向关系。 - Myer
6个回答

878
related_name 属性指定了从 User 模型返回到您的模型的反向关系的名称。
如果您没有指定 related_name,Django 会自动使用您的模型名称加上后缀 _set 创建一个名字,例如 User.map_set.all()
如果您指定了,例如在 User 模型上使用 related_name=mapsUser.map_set 仍然可以工作,但是 User.maps. 的语法更加简洁和清晰;因此,例如,如果您有一个用户对象 current_user,您可以使用 current_user.maps.all() 获取所有与 current_user 有关系的 Map 模型实例。 Django 文档 中提供了更多详细信息。

6
好的,我知道这是一个旧帖子。但我只是想找出答案——在相关名称末尾加上加号(+)的技巧是什么?例如,如果我在上面的示例中使用related_name='maps+'会发生什么? - Sidd
42
如果你在加号后面添加 + 符号,Django 会禁用映射。 - josephmisiti
11
对于OneToOneField,默认的related_name会是小写类名。例如,在给定的例子中,如果members是OneToOnefield,则"User.map"将起作用。 - ancho
如果您在django1.11>中指定了related_name,那么_set是否仍然有效? - E_K
31
我使用Django 2.1.3,我发现这两个是互斥的。一旦指定了“related_name”,“_set”就不再起作用了。 - stockersky

154

补充现有答案 - 如果模型中有两个指向同一张表的外键,那么相关名称是必须的。例如,在物料清单的情况下。

@with_author 
class BOM(models.Model): 
    name = models.CharField(max_length=200,null=True, blank=True)
    description = models.TextField(null=True, blank=True)
    tomaterial =  models.ForeignKey(Material, related_name = 'tomaterial')
    frommaterial =  models.ForeignKey(Material, related_name = 'frommaterial')
    creation_time = models.DateTimeField(auto_now_add=True, blank=True)
    quantity = models.DecimalField(max_digits=19, decimal_places=10)

因此,当您需要访问此数据时,只能使用相关名称。

 bom = material.tomaterial.all().order_by('-creation_time')

否则它将无法工作(至少我无法在两个外键指向同一张表的情况下跳过相关名称的使用。)


4
你必须至少为其中一个选择一个related_name。另一个不一定需要。 - Csaba Toth
63
related_name 应该是复数形式,因为 ForeignKey 关系会返回多个对象。 - Mesut Tasci
1
抱歉发帖较晚 =) Mesut的评论很有价值。他们提到的一个例子是 class Employee(models.Model): manager = models.ForeignKey('self', related_name='manages', on_delete=models.CASCADE, blank=False, null=False)。请搜索Google:“Django Tips #22 Designing Better Models”以了解更多详情。 - boar
1
@AdityaSingh 想象一个包含两个外键指向“位置”表的“产品”表 - 一个是“制造地点”,另一个是“仓库交付地点”。 - java-addict301
1
@AdityaSingh 想象一个包含两个外键指向“位置”表的“产品”表 - 一个是“制造地点”,一个是“仓库交付地点”。 - undefined
显示剩余6条评论

34

related_name参数在有更复杂的相关类名时也很有用。例如,如果你有一个外键关系:

class UserMapDataFrame(models.Model):
    user = models.ForeignKey(User) 

为了从相关的User访问UserMapDataFrame对象,通常的调用方式是User.usermapdataframe_set.all(),但这种方式不太易读。

使用related_name可以指定一个更简单或易读的名称来获取反向关系。在本例中,如果指定user = models.ForeignKey(User, related_name='map_data'),则调用将变为User.map_data.all()


15
您的问题要点如下: 由于您已经有了Map和User模型,并在Map模型中定义了ManyToManyField,如果您想访问Map中的成员,则可以使用map_instance.members.all()选项,因为您定义了members字段。 但是,如果您想访问用户所属的所有地图,则有什么选择?
默认情况下,Django为您提供了user_instance.modelname_set.all(),在这种情况下会转换为user.map_set.all()。
maps比map_set更好。
related_name使您能够让Django知道您将如何从User模型访问Map或者通常从哪些模型中访问反向模型,这是创建ManyToMany字段和使用ORM的整个意义。

2
访问 https://www.revsys.com/tidbits/tips-using-djangos-manytomanyfield/ 了解有关Django中ManyToMany字段的更多信息。 - Mr. Suryaa Jha

5
相关的name参数实际上是一个选项。如果我们不设置它,Django会自动为我们创建关系的另一侧。在Map模型的情况下,Django会创建一个map_set属性,允许通过m.map_set访问您的示例(m是您的类实例)。 Django使用的公式是模型名称后跟字符串_set。因此,related name参数仅覆盖Django的默认值,而不提供新行为。

1

prefetch_related 用于预取Many to many和many to one关系数据。 select_related 用于从单值关系中选择数据。 两者都用于从模型的关系中获取数据。例如,您建立了一个与其他模型有关系的模型。当请求到来时,您还将查询其关系数据,Django具有非常好的机制来访问其关系数据,例如book.author.name,但是当您迭代模型列表以获取其关系数据时,Django会为每个单个关系数据创建请求。为了克服这一点,我们有prefetchd_relatedselected_related


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接