我们都知道对于ManyToMany字段,Django采用的是第三张中间表的方式。通过这第三张表,来关联ManyToMany的双方。下面我们根据一个具体的例子,详细解说中间表的使用。

一、默认中间表

首先,模型是这样的:

class Person(models.Model):

name = models.CharField(max_length=128)

def __str__(self):

return self.name

class Group(models.Model):

name = models.CharField(max_length=128)

members = models.ManyToManyField(Person)

def __str__(self):

return self.name

在Group模型中,通过members字段,以ManyToMany方式与Person模型建立了关系。

让我们到数据库内看一下实际的内容,Django为我们创建了三张数据表,其中的app1是应用名。

然后我在数据库中添加了下面的Person对象:

再添加下面的Group对象:

让我们来看看,中间表是个什么样子的:

首先有一列id,这是Django默认添加的,没什么好说的。然后是Group和Person的id列,这是默认情况下,Django关联两张表的方式。如果你要设置关联的列,可以使用to_field参数。

可见在中间表中,并不是将两张表的数据都保存在一起,而是通过id的关联进行映射。

二、自定义中间表

一般情况,普通的多对多已经够用,无需自己创建第三张关系表。但是某些情况可能更复杂一点,比如如果你想保存某个人加入某个分组的时间呢?想保存进组的原因呢?

Django提供了一个through参数,用于指定中间模型,你可以将类似进组时间,邀请原因等其他字段放在这个中间模型内。例子如下:

from django.db import models

class Person(models.Model):

name = models.CharField(max_length=128)

def __str__(self):

return self.name

class Group(models.Model):

name = models.CharField(max_length=128)

members = models.ManyToManyField(Person, through='Membership')

def __str__(self):

return self.name

class Membership(models.Model):

person = models.ForeignKey(Person, on_delete=models.CASCADE)

group = models.ForeignKey(Group, on_delete=models.CASCADE)

date_joined = models.DateField() # 进组时间

invite_reason = models.CharField(max_length=64) # 邀请原因

在中间表中,我们至少要编写两个外键字段,分别指向关联的两个模型。在本例中就是‘Person’和‘group’。

这里,我们额外增加了‘date_joined’字段,用于保存人员进组的时间,‘invite_reason’字段用于保存邀请进组的原因。

下面我们依然在数据库中实际查看一下(应用名为app2):

注意中间表的名字已经变成“app2_membership”了。

Person和Group没有变化。

但是中间表就截然不同了!它完美的保存了我们需要的内容。

三、使用中间表

针对上面的中间表,下面是一些使用例子(以欧洲著名的甲壳虫乐队成员为例):

>>> ringo = Person.objects.create(name="Ringo Starr")

>>> paul = Person.objects.create(name="Paul McCartney")

>>> beatles = Group.objects.create(name="The Beatles")

>>> m1 = Membership(person=ringo, group=beatles,

... date_joined=date(1962, 8, 16),

... invite_reason="Needed a new drummer.")

>>> m1.save()

>>> beatles.members.all()

]>

>>> ringo.group_set.all()

]>

>>> m2 = Membership.objects.create(person=paul, group=beatles,

... date_joined=date(1960, 8, 1),

... invite_reason="Wanted to form a band.")

>>> beatles.members.all()

, ]>

与普通的多对多不一样,使用自定义中间表的多对多不能使用add(), create(),remove(),和set()方法来创建、删除关系,看下面:

>>> # 无效

>>> beatles.members.add(john)

>>> # 无效

>>> beatles.members.create(name="George Harrison")

>>> # 无效

>>> beatles.members.set([john, paul, ringo, george])

为什么?因为上面的方法无法提供加入时间、邀请原因等中间模型需要的字段内容。唯一的办法只能是通过创建中间模型的实例来创建这种类型的多对多关联。但是,clear()方法是有效的,它能清空所有的多对多关系。

>>> # 甲壳虫乐队解散了

>>> beatles.members.clear()

>>> # 删除了中间模型的对象

>>> Membership.objects.all()

一旦你通过创建中间模型实例的方法建立了多对多的关联,你立刻就可以像普通的多对多那样进行查询操作:

# 查找组内有Paul这个人的所有的组(以Paul开头的名字)

>>> Group.objects.filter(members__name__startswith='Paul')

]>

可以使用中间模型的属性进行查询:

# 查找甲壳虫乐队中加入日期在1961年1月1日之后的成员

>>> Person.objects.filter(

... group__name='The Beatles',

... membership__date_joined__gt=date(1961,1,1))

可以像普通模型一样使用中间模型:

>>> ringos_membership = Membership.objects.get(group=beatles, person=ringo)

>>> ringos_membership.date_joined

datetime.date(1962, 8, 16)

>>> ringos_membership.invite_reason

'Needed a new drummer.'

>>> ringos_membership = ringo.membership_set.get(group=beatles)

>>> ringos_membership.date_joined

datetime.date(1962, 8, 16)

>>> ringos_membership.invite_reason

'Needed a new drummer.'

这一部分内容,需要结合后面的模型query,如果暂时看不懂,没有关系。

对于中间表,有一点要注意(在前面章节已经介绍过,再次重申一下),默认情况下,中间模型只能包含一个指向源模型的外键关系,上面例子中,也就是在Membership中只能有Person和Group外键关系各一个,不能多。否则,你必须显式的通过ManyToManyField.through_fields参数指定关联的对象。参考下面的例子:

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, on_delete=models.CASCADE)

person = models.ForeignKey(Person, on_delete=models.CASCADE)

inviter = models.ForeignKey(

Person,

on_delete=models.CASCADE,

related_name="membership_invites",

)

invite_reason = models.CharField(max_length=64)

php 中间表统计,多对多中间表详解相关推荐

  1. 03 mysql数据查询_MySql学习day03:数据表之间的连接、查询详解

    主键: 关键字:primary key 特点:不能为null,并且唯一. 主键分类: 逻辑主键:例如ID,不代表实际的业务意义,只是用来唯一标识一条记录(推荐) 业务主键:例如username,参与实 ...

  2. Python的Django框架中forms表单类的使用方法详解2

    用户表单是Web端的一项基本功能,大而全的Django框架中自然带有现成的基础form对象,本文就Python的Django框架中forms表单类的使用方法详解. Form表单的功能 自动生成HTML ...

  3. php 表单提交文件大小,PHP如何通过表单直接提交大文件详解

    PHP如何通过表单直接提交大文件详解 前言 我想通过表单直接提交大文件,django 那边我就是这么干的.而对于 php 来说,我认为尽管可以设置最大上传的大小,但最大也无法超过内存大小,因为它无法把 ...

  4. mysql某个表被行锁了_MySQL 行锁和表锁的含义及区别详解

    一.前言 对于行锁和表锁的含义区别,在面试中应该是高频出现的,我们应该对MySQL中的锁有一个系统的认识,更详细的需要自行查阅资料,本篇为概括性的总结回答. MySQL常用引擎有MyISAM和Inno ...

  5. java MySQL表的约束与数据库设计 详解

    1.DQL 数据查询语言 在上一篇博文中,我们已经讲述了部分数据查询语句,在此我们再次对其进行补充. 1.1 排序 通过ORDAR BY 语句,可以将查询出来的结果进行排序.(排除只是一种现实的方式, ...

  6. jpa 定义中间表实体_Spring Data JPA实体详解

    1. Spring Data JPA实体概述 JPA提供了一种简单高效的方式来管理Java对象(POJO)到关系数据库的映射,此类Java对象称为JPA实体或简称实体.实体通常与底层数据库中的单个关系 ...

  7. MySql表的基本增删改查详解

    目录 创建表create 表中--插入数据--"增" 单行,全列插入 多行插入 插入重复则-更新 插入重复则-替换 插入查询结果 表中--检索数据--"查" 全 ...

  8. mysql单表查询实例_MySQL简单查询详解-单表查询

    MySQL简单查询详解-单表查询 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.查询的执行路径 一条SQL查询语句的执行过程大致如下图所示: 1>.客户端和服务端通过my ...

  9. HTML 表单(form) 使用详解

    一.表单 1.表单的作用 HTML 表单用于接收不同类型的用户输入,用户提交表单时向服务器传输数据,从而实现用户与Web服务器的交互. 2.表单的工作机制 3.表单定义(<form>< ...

最新文章

  1. 报名 | 工业大数据分析:机会与挑战讲座
  2. opengl地球贴纹理_一文看懂材质/纹理 Material, Texture, Shading, Shader 的区别
  3. nuxt解决首屏加载慢问题_一个 Node 脚本让你的前端项目加载速度飞起来
  4. mysql新增阵列df_DF学Mysql(三)——索引操作
  5. C#算法设计排序篇之08-计数排序(附带动画演示程序)
  6. java运用ascii实现动画效果_安卓开发20:动画之Animation 详细使用-主要通过java代码实现动画效果...
  7. 分析单点登录(流程图与数据安全)
  8. Tinder活号技术在YouTube上面居然有用模拟器和浏览器玩明白了使用谷歌下载的
  9. ios 请在设置中打开相机权限_iOS 检测相机权限是否打开
  10. Mathematica实现0.618法(黄金分割法)求最大最小值
  11. 05使用TypeScript实现Doom3词法解析器(读书笔记:TypeScript图形渲染实战算法分析与架构设计)
  12. 计算机提示没有有效的ip配置,教大家电脑提示以太网没有有效的ip配置怎么办...
  13. 学习金字塔——谈谈对学习的一点理解
  14. BLE4.2链路层(LL)安全机制-LL Privacy
  15. 程序员如何轻松又愉快的学好英语
  16. 快速提升SEO关键词搜索排名的5大伎俩
  17. 电车识别 电瓶车识别
  18. swiper 轮播图,最后一张图与第一张图无缝衔接
  19. MC基础教程#2 加载器、模组、光影、材质包、数据包下载及安装(国际Java版)
  20. 防火防盗防诈骗!老实程序员如何保护好自己?

热门文章

  1. 【英语学习】【English L06】U06 Banking L2 A savings account sounds better for me
  2. 对象json字符串数组 java对象,java把json的字符串转换为json对象和数组
  3. 流程在团队管理中的作用
  4. Windows下openssl的下载安装和使用
  5. java枚举来实现单例_枚举实现单例模式
  6. 软件测试实践报告文档,软件测试实践报告.doc
  7. TypeScript,初次见面,请多指教 ?
  8. 如果没有Visual Studio 2015,我们如何创建.NET Core项目 ?
  9. 轻量级OLAP(一):Cube计算
  10. VirtualBox 安装 Ubuntu 14.10 花屏 解决方案