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()
class 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.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)
class 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
关键字参数指定.
others#
下列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提供了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')
首先获得要进行关联的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()
参考资料:
作者:finley
出处:https://www.cnblogs.com/Finley/p/5537753.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性