多表查询是模型层的重要功能之一, 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()

参考资料:

django文档-模型字段-关联字段

django文档 - 执行查询 - 关联的对象

django文档 - 执行查询 - 跨关联关系查询

Django 多表查询的更多相关文章

  1. Django多表查询

    一.前言 1.什么是ORM? ORM,即Object-Relational Mapping(对象关系映射),它的作用是在关系型数据库和业务实体对象之间作一个映射,这样,我们在具体的操作业务对象的时候, ...

  2. Django --- ORM表查询

    目录 使用数据库之前的配置工作 单表操作常用的方法 一对多字段的增删改查 多对多字段数据的增删改查 跨表查询 聚合函数 分组查询 F与Q查询 使用数据库之前的配置工作 settings.py中的配置 ...

  3. Django单表查询及其方法

    单表查询 前期准备 首先新建一个test的python文件,然后再manage.py中导入main语句及其下面的复制到新文件中 并导入django 写上django.setup() 就可以导入对应的m ...

  4. Django 多表查询练习题 Q查询 F查询 聚合 分组

    -------------------------------------------------自己偷的懒,或许用加倍时间也补不回来,珍惜现在的拥有的时光,把我现在! 上节回顾 基于对象的跨表查询( ...

  5. django 多表查询并返回结果

    (不喜勿喷,个人记录) 问题,有两张关联的表,表B的api_id关联表A的id 我想在页面上返回两张表查询之后的共同结果? 因为两张表的id是一样的,就先获取到表A的对象,然后拿表A的对象id当做表B ...

  6. Django多表查询练习题

    #一 model表:from django.db import models # Create your models here. class Teacher(models.Model): tid=m ...

  7. Django 单表查询

    前言 如何只单独测试django中的某一个py文件呢?或者说如何书写测试脚本? 我们可以在任意一个py文件(应用下的tests或者自己新建一个)中书写以下代码: 前期准备 创建一个电影表 class ...

  8. Django 多表查询 聚合查询 分组查询 F查询 Q查询

    # -------------------------------------------------------------------------------------------------- ...

  9. Django 多表、跨表、聚合、分组查询

    前期准备: 创建表 class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalFi ...

随机推荐

  1. 在centos docker中安装nvidia驱动

    因为计算需要用到GPU加速, 今天尝试在centos 机器的Docker里安装了GTX980驱动, 记录一下详细安装过程. 首先安装Docker和镜像: sudo yum install docker ...

  2. C#委托总结-入门篇

    1,概念:委托类型表示对具有特定参数列表和返回类型的方法的引用. 通过委托,可以将方法视为可分配给变量并可作为参数传递的实体. 委托是引用类型,可以把它看作是用来存方法的一种类型.比如说类型strin ...

  3. 敏捷开发-代码提交流程& 安装gerrit

  4. XCode10.0遇到的问题

    1:编译时报info.plist冲突. 解决方法,XCode上 File -> Workspace Settings ... 将Build System改为 Legacy Build Syste ...

  5. jzoj100031

    這題是結論題 好玄學,不懂 代碼: #include<bits/stdc++.h> using namespace std; struct no{ int v,p; bool operat ...

  6. js处理想要得到数据结构

    例1 var arr = [ { date: "2018-01-10", time: "11:00" }, { date: "2018-01-10&q ...

  7. tomcat JNDI Resource 配置

    最近公司的项目慢慢开始向Maven项目迁移, 部分配置文件公共组也帮我们做了些改动,其中在spring的applicationContext.xml中看到了数据连接bean存在两个,一个是jndi 一 ...

  8. Java并发编程之happens-before

    happens-before是JMM最核心的概念,理解happens-before是理解JMM的关键. 一.JMM的设计 首先,让我们先分析一下JMM的设计意图.从JMM的设计者的角度,在设计JMM的 ...

  9. JS: 数组扁平化

    数组扁平化 什么是数组扁平化? 数组扁平化就是将一个多层嵌套的数组 (Arrary) 转化为只有一层. // 多层嵌套 [1, 2, [3, 4]] // 一层 [1, 2, 3, 4] 递归实现 思 ...

  10. uiautomatorviewer 双击闪退问题解决

    最近在学习app自动测试,结果在打开uiautomatorviewer查看app界面元素时,就出现了闪退的问题,找了很多很多方法,最后终于可以解决了,详情请继续往下看 首次安装adt的步骤 将下载的压 ...