manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
多对多关系的额外字段:throuth
例如:这样一个应用,它记录音乐家所属的音乐小组。 我们可以用一个ManyToManyField 表示小组和成员之间的多对多关系。 但是,有时你可能想知道更多成员关系的细节,比如成员是何时加入小组的。
对于这些情况,Django 允许你指定一个中介模型来定义多对多关系。 你可以将其他字段放在中介模型里面。 源模型的ManyToManyField 字段将使用through 参数指向中介模型。 对于上面的音乐小组的例子,代码如下:
from django.db import models class Person(models.Model): name = models.CharField(max_length=128) def __str__(self): # __unicode__ on Python 2 return self.name class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField(Person, through='Membership') def __str__(self): # __unicode__ on Python 2 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)
您需要在设置中间模型的时候,显式地为多对多关系中涉及的中间模型指定外键。这种显式声明定义了这两个模型之间是如何关联的。
在中间模型当中有一些限制条件:
- 你的模型中间要么有且仅有一个指向源模型(我们例子当中的Group)的外键,你要么必须通过ManyToManyField.through_fields参数在多个外键当中手动选择一个外键,有如果外个多键盘没有用through_fields 参数选择一个的话,会出现验证错误。对于某个目标模型(我们示例当中的Person)的外键也有同样的限制。
- 在一个有用的描述模型当中自己指向自己的多对多关系的中间模型当中,可以有两个指向同一个模型的外健,但这两个外健分表代表多对多关系(不同)的两端。如果外健的个数超过两个,你必须和上面一样的指定through_fields参数,要不然会出现验证错误。
现在你已经通过中间模型完成你的ManyToManyField(示例中的Membership),可以开始创建一些多对多关系了。你通过实例化中间模型来创建关系:
>>> 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()
创建关系,只要你为任何必需的细分指定 through_defaults
:
>>> beatles.members.add(john, through_defaults={'date_joined': date(1960, 8, 1)}) >>> beatles.members.create(name="George Harrison", through_defaults={'date_joined': date(1960, 8, 1)}) >>> beatles.members.set([john, paul, ringo, george], through_defaults={'date_joined': date(1960, 8, 1)})
你可能更潜在直接创造中间模型。
如果自定义中间模型没有强制对的唯一性,调用方法会删除所有中间模型的实例:(model1, model2)remove()
>>> 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 deletes both of the intermediate model instances for Ringo Starr >>> beatles.members.remove(ringo) >>> beatles.members.all() <QuerySet [<Person: Paul McCartney>]>
方法clear()
用于实例的所有多对多关系:
>>> # Beatles have broken up >>> beatles.members.clear() >>> # Note that this deletes the intermediate model instances >>> Membership.objects.all() <QuerySet []>
一旦你建立了自定义多对多关联关系,就可以执行查询操作。和一般的多对多关联关系一样,你可以使用多对多关联模型的属性来查询:
# Find all the groups with a member whose name starts with 'Paul' >>> Group.objects.filter(members__name__startswith='Paul') <QuerySet [<Group: The Beatles>]>
当你使用中间模型的时候,你也可以查询他的属性:
# 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]>
如果你想访问一个关系的信息时你可以直接查询Membership模型:
>>> 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.'
另一种访问同样信息的方法是通过Person对象来查询多对多递归关系:
>>> 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.'
一对一关联
使用OneToOneField来定义一对一关系。就像使用其他类型的Field一样:在模型属性中包含它。
当一个对象以某种方式“继承”另一个对象时,这那个对象的主键非常有用。
OneToOneField需要一个位置参数:与模型相关的类。
例如,当你要建立一个有关“位置”信息的数据库时,你可能会包含通常的地址,电话等分支。然后,如果你想接着建立一个关于关于餐厅的数据库,除了将位置数据库当中的一部分复制到Restaurant模型,你也可以将一个指向Place OneToOneField放到Restaurant当中(因为餐厅“是一个”地点);事实上,在处理这样的情况时最好使用模型继承,它隐含的包括了一个一对一关系。
和 ForeignKey一样,可以创建自关联关系也可以创建与尚未定义的模型的关系。
OneToOneField初步还接受一个可选的parent_link参数。
OneToOneField类通常自动的成为模型的主键,这条规则现在不再使用了(而你可以手动指定primary_key参数)。因此,现在可以在其中的模型当中指定多个OneToOneField分段。
详情参考官网: https://www.khan.pub/django3.0/index.html
标签:Django
相关阅读 >>
更多相关阅读请进入《Django》频道 >>

Python编程 从入门到实践 第2版
python入门书籍,非常畅销,超高好评,python官方公认好书。
相关推荐
评论
管理员已关闭评论功能...
- 欢迎访问木庄网络博客
- 可复制:代码框内的文字。
- 方法:Ctrl+C。