赞
踩
ManyToManyField定义一个多对多的关联关系,使用 django.db.models.ManyToManyField 类。就和其他 Field 字段类型一样,只需要在你模型中添加一个值为该类的属性。
ManyToManyField requires a positional argument: the class to which the model is related.
例如:如果 Pizza 含有多种 Topping(配料) – 也就是一种 Topping 可能存在于多个 Pizza 中,并且每个 Pizza 含有多种 Topping --那么可以这样表示这种关系:
from django.db import models
class Topping(models.Model):
# ...
pass
class Pizza(models.Model):
# ...
toppings = models.ManyToManyField(Topping)
和 ForeignKey 类一样,你也可以创建 recursive relationships 关系(一个对象与他本身有着多对多的关系)和 relationships to models not yet defined 关系。
建议设置 ManyToManyField 字段(上例中的 toppings )名为一个复数名词,表示所要光联的模型对象的集合。
对于多对多光联关系的两个模型,可以在任何一个模型中添加 ManyToManyField 字段,但只能选择一个模型设置该字段,即不能同时在两模型中添加该字段。
Generally, ManyToManyField instances should go in the object that’s going to be edited on a form. In the above example, toppings is in Pizza (rather than Topping having a pizzas ManyToManyField ) because it’s more natural to think about a pizza having toppings than a topping being on multiple pizzas. The way it’s set up above, the Pizza form would let users select the toppings.
参见:
如要查看完整示例代码,详见 Many-to-many relationship model example。
ManyToManyField fields also accept a number of extra arguments which are explained in the model field reference. These options help define how the relationship should work; all are optional.
当您只处理简单的多对多关系时,例如混合和匹配比萨饼和浇头,您只需要一个标准的ManyToManyField即可。但是,有时您可能需要将数据与两个模型之间的关系相关联。
原:When you’re only dealing with simple many-to-many relationships such as mixing and matching pizzas and toppings, a standard
ManyToManyFieldis all you need. However, sometimes you may need to associate data with the relationship between two models.
例如,考虑应用程序跟踪音乐家所属的音乐组的情况。一个人和他们所属的群体之间有一种多对多的关系,因此您可以使用manytomanyfield 来表示这种关系。但是,关于您可能想要收集的成员身份有很多详细信息,例如此人加入该组的日期。
原:For example, consider the case of an application tracking the musical groups which musicians belong to. There is a many-to-many relationship between a person and the groups of which they are a member, so you could use a
ManyToManyFieldto represent this relationship. However, there is a lot of detail about the membership that you might want to collect, such as the date at which the person joined the group.
对于这些情况,Django允许您指定用于管理多对多关系的模型。然后可以在中间模型上放置额外的字段。中间模型与manytomanyfield关联,使用through参数指向充当中介的模型。对于我们的音乐家示例,代码如下所示:
原:For these situations, Django allows you to specify the model that will be used to govern the many-to-many relationship. You can then put extra fields on the intermediate model. The intermediate model is associated with the ManyToManyField using the through argument to point to the model that will act as an intermediary. For our musician example, the code would look something like this:
from django.db import models class Person(models.Model): name = models.CharField(max_length=128) def __str__(self): return self.name class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField(Person, through='Membership') def __str__(self): return self.name class Membership(models.Model): person = models.ForeignKey(Person, on_delete=models.CASCADE) group = models.ForeignKey(Group, on_delete=models.CASCADE) date_joined = models.DateField() invite_reason = models.CharField(max_length=64)
设置中间模型时,您明确指定多对多关系中涉及的模型的外键。此显式声明定义了两个模型的关联方式。
原: When you set up the intermediary model, you explicitly specify foreign keys to the models that are involved in the many-to-many relationship. This explicit declaration defines how the two models are related.
中间模型有一些限制:
原:There are a few restrictions on the intermediate model:
中间模型必须包含源模型的一个且只有一个外键(在我们的示例中,这将是组),或者您必须使用 ManyToManyField.through_fields 字段明确指定django应用于关系的外键。如果您有多个外键并且未指定“through_fields”字段,则将引发验证错误。类似的限制也适用于目标模型的外键(在我们的示例中,这将是 Person)。
原: Your intermediate model must contain one - and only one - foreign key to the source model (this would be
Groupin our example), or you must explicitly specify the foreign keys Django should use for the relationship usingManyToManyField.through_fields. If you have more than one foreign key andthrough_fieldsis not specified, a validation error will be raised. A similar restriction applies to the foreign key to the target model (this would bePersonin our example).
对于通过中介模型与自身具有多对多关系的模型,允许同一模型的两个外键,但它们将被视为多对多关系的两个(不同)面。但是,如果有两个以上的外键,您还必须如上所述通过字段指定,否则将引发验证错误。
原:For a model which has a many-to-many relationship to itself through an intermediary model, two foreign keys to the same model are permitted, but they will be treated as the two (different) sides of the many-to-many relationship. If there are more than two foreign keys though, you must also specify through_fields as above, or a validation error will be raised.
使用中间模型定义从模型到自身的多对多关系时,必须使用 symmetrical=False(请参见模型字段引用)。
原:When defining a many-to-many relationship from a model to itself, using an intermediary model, you must use symmetrical=False (see the model field reference).
既然您已经设置了ManytomanyField来使用中介模型(在本例中是成员资格),那么就可以开始创建一些多对多关系了。您可以通过创建中间模型的实例来实现这一点:
原:Now that you have set up your ManyToManyField to use your intermediary model (Membership, in this case), you’re ready to start creating some many-to-many relationships. You do this by creating instances of the intermediate model:
>>> ringo = Person.objects.create(name="Ringo Starr") >>> paul = Person.objects.create(name="Paul McCartney") >>> beatles = Group.objects.create(name="The Beatles") >>> m1 = Membership(person=ringo, group=beatles, ... date_joined=date(1962, 8, 16), ... invite_reason="Needed a new drummer.") >>> m1.save() >>> beatles.members.all() <QuerySet [<Person: Ringo Starr>]> >>> ringo.group_set.all() <QuerySet [<Group: The Beatles>]> >>> m2 = Membership.objects.create(person=paul, group=beatles, ... date_joined=date(1960, 8, 1), ... invite_reason="Wanted to form a band.") >>> beatles.members.all() <QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>]>
与普通的多对多字段不同,不能使用add()、create()或set()创建关系:
原:Unlike normal many-to-many fields, you can’t use add(), create(), or set() to create relationships:
>>> # The following statements will not work
>>> beatles.members.add(john)
>>> beatles.members.create(name="George Harrison")
>>> beatles.members.set([john, paul, ringo, george])
为什么?您不能只在一个人和一个组之间创建关系-您需要为成员关系模型所需的关系指定所有详细信息。简单的“添加”、“创建”和“分配”调用不提供指定此额外细节的方法。因此,对于使用中间模型的多对多关系,它们被禁用。创建此类关系的唯一方法是创建中间模型的实例。
原: Why? You can’t just create a relationship between a Person and a Group - you need to specify all the detail for the relationship required by the Membership model. The simple add, create and assignment calls don’t provide a way to specify this extra detail. As a result, they are disabled for many-to-many relationships that use an intermediate model. The only way to create this type of relationship is to create instances of the intermediate model.
由于类似的原因,已禁用remove()方法。例如,如果中间模型定义的自定义through表没有在(model1,model2)对上强制唯一性,则remove()调用将无法提供有关应删除中间模型实例的足够信息:
原:The
remove()method is disabled for similar reasons. For example, if the custom through table defined by the intermediate model does not enforce uniqueness on the(model1, model2)pair, aremove()call would not provide enough information as to which intermediate model instance should be deleted:
>>> Membership.objects.create(person=ringo, group=beatles,
... date_joined=date(1968, 9, 4),
... invite_reason="You've been gone for a month and we miss you.")
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>, <Person: Ringo Starr>]>
>>> # This will not work because it cannot tell which membership to remove
>>> beatles.members.remove(ringo)
但是,clear()方法可用于删除实例的所有多对多关系:
原: However, the
clear()method can be used to remove all many-to-many relationships for an instance:
>>> # Beatles have broken up
>>> beatles.members.clear()
>>> # Note that this deletes the intermediate model instances
>>> Membership.objects.all()
<QuerySet []>
一旦通过创建中间模型的实例建立了多对多关系,就可以发出查询。与普通的多对多关系一样,您可以使用多对多相关模型的属性进行查询:
原:Once you have established the many-to-many relationships by creating instances of your intermediate model, you can issue queries. Just as with normal many-to-many relationships, you can query using the attributes of the many-to-many-related model:
# Find all the groups with a member whose name starts with 'Paul'
>>> Group.objects.filter(members__name__startswith='Paul')
<QuerySet [<Group: The Beatles>]>
在使用中间模型时,还可以查询其属性:
原:As you are using an intermediate model, you can also query on its attributes:
# Find all the members of the Beatles that joined after 1 Jan 1961
>>> Person.objects.filter(
... group__name='The Beatles',
... membership__date_joined__gt=date(1961,1,1))
<QuerySet [<Person: Ringo Starr]>
如果需要访问成员的信息,可以直接查询成员模型:
原:If you need to access a membership’s information you may do so by directly querying the Membership model:
>>> ringos_membership = Membership.objects.get(group=beatles, person=ringo)
>>> ringos_membership.date_joined
datetime.date(1962, 8, 16)
>>> ringos_membership.invite_reason
'Needed a new drummer.'
访问相同信息的另一种方法是从一个人对象查询多对多反向关系:
原:Another way to access the same information is by querying the many-to-many reverse relationship from a Person object:
>>> ringos_membership = ringo.membership_set.get(group=beatles)
>>> ringos_membership.date_joined
datetime.date(1962, 8, 16)
>>> ringos_membership.invite_reason
'Needed a new drummer.'
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。