Django中间模型管理多对多模型
中间模型管理多对多模型
through:通过中间模型管理多对多模型,允许对目标模型添加一些额外信息
模型定义
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)
上述代码表示了个体与组别存在多对多关系,同时还需要对个人进行更加详细的数据描述,因此可以ManyToManyField中使用through属性来定义一个中间模型进行管理,注意:
- 中间模型必须有且仅有一个外键指向目标模型(也就是本例中的Person)。使用多于一个的外键将会引发验证错误。
- 中间模型必须有且仅有一个外键指向源模型(也就是本例中的Group)。使用多于一个的外键将会引发验证错误。
- 唯一例外的情况是一个模型通过中间模型与自身产生多对多关系。这种情况下,两个外键指向同一个模型是允许的,但是它们会被看作同一个多对多关系的两个(不同的)方面。
创建
>>> 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(), or 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)})
也可以通过中间模型来创建源模型和目标模型
>>> 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>]>
查询
>>> Group.objects.filter(members__name__startswith='Paul')
<QuerySet [<Group: The Beatles>]>
>>> Person.objects.filter(
... group__name='The Beatles',
... membership__date_joined__gt=date(1961,1,1))
<QuerySet [<Person: Ringo Starr]>
或通过中间模型直接查询
>>> 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.'
或者通过中间模型的反向查询
>>> ringo = Person.object.fitter(name=ringo)
>>> 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.'
删除
-
remove():如果目标模型没有对数据的独一性进行要求,那么remove()将会删除所有相同的值>>> beatles.members.all() <QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>, <Person: Ringo Starr>]> >>> beatles.members.remove(ringo) >>> beatles.members.all() <QuerySet [<Person: Paul McCartney>]>可以看到本来
Queryset对象中有两个相同的<Person: Ringo Starr>,删除后都不存在了 -
clear():删除一个实例的所有中间关系>>> beatles.members.clear() >>> Membership.objects.all() <QuerySet []>

浙公网安备 33010602011771号