Django模型层多表查询详解:ForeignKey与ManyToManyField实战

巷口听风
巷口听风
发布时间:2026-10-13| 3人浏览过
原创

本文深入解析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程序设计有所帮助。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。