Django ForeignKey和ManyToManyField多表查询

多表查询在Django模型层是一项重要功能,Django提供了一套基于关联字段的独特解决方案。

图片[1]-Django ForeignKey和ManyToManyField多表查询-山海云端论坛

ForeignKey

来自Django官方文档的模型示例:

from django.db import models class Blog(models.Model): name = models.CharField(max_length=100) tagline = models.TextField() class Author(models.Model): name = models.CharField(max_length=50) email = models.EmailField() class Entry(models.Model): blog = models.ForeignKey(Blog) authors = models.ManyToManyField(Author) headline = models.CharField(max_length=255) body_text = models.TextField() pub_date = models.DateField() mod_date = models.DateField() n_comments = models.IntegerField() n_pingbacks = models.IntegerField() rating = models.IntegerField()

ForeignKey

ForeignKey字段接受一个Model类作为参数,类型与被参照的字段完全相同:

blog = models.ForeignKey(Blog)

ForeignKey.to_field

关联到的关联对象的字段名称。默认情况下,Django使用关联对象的主键:

blog = models.ForeignKey(Blog, to_field=Blog.name)

ForeignKey.db_constraint

Django Model的ForeignKey字段的主要功能是维护一个一对多的关系,以进行关联查询。

只有在db_constraint=True时Django model才会在数据库上建立外键约束,在该值为False时不建立约束,默认db_constraint=True

ForeignKey.related_name

这个名称用于让关联的对象反查到源对象。

如果你不想让Django创建一个反向关联,请设置related_name为’+’或者以’+’结尾。

ForeignKey.related_query_name

ForeignKey.related_name作为默认值。

使用ForeignKey查询

前向查询

若关系模型A包含与模型B关联的关联字段,模型A的实例可以通过关联字段访问与其关联的模型B的实例:

e = Entry.objects.get(id=2) e.blog # Returns the related Blog object.

修改e.blog并调用save方法存入数据库:

e.blog = some_blog e.save()

如果ForeignKey字段有null=True设置(即它允许NULL值),可以分配None来删除对应的关联性:

e = Entry.objects.get(id=2) e.blog = None e.save() # "UPDATE blog_entry SET blog_id = NULL ...;"

Django提供了一种使用双下划线__的查询语法:

Entry.objects.filter(blog__name='Beatles Blog')

反向查询

被索引的关系模型可以访问所有参照它的模型的实例,如Entry.blog作为Blog的外键,默认情况下Blog.entry_set是包含所有参照Blog的Entry示例的查询集,可以使用查询集API取出相应的实例。

b = Blog.objects.get(id=1) b.entry_set.all()

Entry.blogrelated_namerelated_query_name可以设置该查询集的名字。

ManyToManyField

来自Django官网的示例:

from django.db import models class Person(models.Model): name = models.CharField(max_length=50) class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField(Person, through='Membership', through_fields=('group', 'person')) class Membership(models.Model): group = models.ForeignKey(Group) person = models.ForeignKey(Person) inviter = models.ForeignKey(Person, related_name="membership_invites") invite_reason = models.CharField(max_length=64)

ManyToManyField

ManyToManyField.through

Django会自动创建一个表来管理多对多关系,若要手动指定关联表则需要使用through关键字参数。

ManyToManyField.through_fields

上文示例中Membership有两个外键指向Personpersoninviter),这使得关联关系含混不清并让Django不知道使用哪一个。

在这种情况下,必须使用through_fields明确指定Django应该使用哪些外键。

through_fields接收一个二元组(‘field1’, ‘field2’),其中field1为指向定义ManyToManyField字段的模型的外键名称(本例中为group),field2为指向目标模型的外键的名称(本例中为person)。

ManyToManyField.db_table

默认情况下,关联表的名称使用多对多字段的名称和包含这张表的模型的名称以及Hash值生成,如:memberShip_person_3c1f5

若要想要手动指定表的名称,可以使用db_table关键字参数指定。

其他API和ForeignKey中的同名API相同。

使用ManyToManyField查询

多对多关系和ForeignKey具有相似的API。

e = Group.objects.get(id=3) e.members.all() # Returns all members objects for this Group.

反向查询

a = Person.objects.get(id=1) a.group_set.all()

同样related_name可以设置反向查询集的名称。

添加删除关联

因为ManyToManyField自动维护关联表,程序员不便于直接访问。ManyToManyField提供了API用于添加和删除关联(即through表中的记录)。

使用一个自动维护through表的模型作为示例:

class User(models.Model): user_id = models.IntegerField(primary_key=True) class Flight(models.Model): flight_id = models.IntegerField(primary_key=True) reserve = models.ManyToManyField(User, related_name='flight_reserve')

首先获得要进行关联的FlightUser实例:

flights = Flight.objects.filter(flight_id=flight_id) if flights.count() != 0: flight = flights[0] users = User.objects.filter(id=user_id) if users.count() != 0: user = users[0]

通过拥有关联字段的Flight实例进行添加关联操作:

flight.reserve.add(user) flight.save()

删除操作与这类似:

flight.reserve.remove(user) flight.save()

© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容