Django模型层多表查询详解:ForeignKey与ManyToManyField实战
本文深入解析Django框架中的多表查询机制,重点阐述ForeignKey与ManyToManyField的使用。通过官方示例代码,详细说明外键约束、反向查询、自定义关联表及多对多关系的添加删除操作,帮助开发者掌握Django模型层的核心关联查询技巧。
本文通过具体实例解析Django框架中的多表查询功能,供读者参考学习。
多表查询是Django模型层的关键功能,框架提供了一套基于关联字段的独特解决方案来处理此类需求。
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模型才会在数据库层面建立外键约束;若该值为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.blog的related_name和related_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包含两个指向Person的外键(person和inviter),这导致关联关系模糊,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.db_constraint
- ManyToManyField.related_name
- ManyToManyField.related_query_name
使用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提供了用于添加和删除关联(即through表中的记录)的API。
以下使用一个自动维护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')
首先获取需要进行关联的Flight和User实例:
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()
希望本文所述内容能对基于Django框架的Python程序设计有所帮助。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









