ORM关于表那些事
一、ORM表和表之间的关系
- 1、 一对多 --> 外键(ForeignKey)
- 2、 多对多 --> 另外一张关系表(ManyToManyField)
- 1. 三种方式
- 1. 自己建立第三张关系表,外键分别关联两个表
- 1. 优点
- 1. 可以扩充第三张关系标的字段
- 2. 缺点
- 1. 自己做连表查询
- 3. 建表例子
- class Book(models.Model):
- title = models.CharField(max_length=12)
- class Author(models.Model):
- name = models.CharField(max_length=12)
- # 1. 多对多第一种创建方式:自己创建第三张关系表
- class Author2Book(models.Model):
- id = models.AutoField(primary_key=True)
- author_id = models.ForeignKey(to='Author')
- book_id = models.ForeignKey(to='Book')
- price = models.IntegerField() # 可以自己扩充需要的字段
- 2. 通过ORM内置的ManyToManyField,自动创建第三张关系表
- 1. 优点
- 1. 提供了很多连表操作的快捷方法--> all(), add(), set(), clear(), remove()
- 2. 缺点
- 1. 无法扩展第三张关系表
- 3. 建表例子
- class Book(models.Model):
- title = models.CharField(max_length=12)
- class Author(models.Model):
- name = models.CharField(max_length=12)
- books = models.ManyToManyField(to='Book') # 字段就这些,无法扩充其他字段
- 3. 自己创建第三张关系表,通过ManyToManyField关联
- 1. 优点:
- 1. 既能够使用多对多查询的快捷方法all()(只能用all,不能使用add,set等),还能够自己扩展第三张关系表的字段
- 2. 建表例子
- class Book(models.Model):
- title = models.CharField(max_length=12)
- class Author(models.Model):
- name = models.CharField(max_length=12)
- # 告诉ManyToManyField通过(through)Author2Book这张表进行关联,不使用ORM自动创建的第三张表,而是使用我自己创建的表
- # through_fields告诉ORM通过哪几个字段进行多对多关联
- books = models.ManyToManyField(to='Book', through='Author2Book', through_fields=('author', 'book'))
- # 1. 多对多第三种创建方式:自己创建第三张关系表,此时外键不需要添加_id了,因为ORM会默认帮你在外键后面加_id
- class Author2Book(models.Model):
- id = models.AutoField(primary_key=True)
- author = models.ForeignKey(to='Author')
- book = models.ForeignKey(to='Book')
- price = models.IntegerField(null=True)
- # author_id和book_id要联合唯一
- class Meta:
- unique_together = (('author', 'book'),)
- 3. 操作例子
- # 多对多的第三张方式也支持all查询
- author_obj = Author.objects.first()
- # 第一个作者的所有书籍
- ret = author_obj.books.all()
- # 给第一个作者添加一本书
- # author_obj.books.add(4) # 报错
- Author2Book.objects.create(author_id=1, book_id=4)
- 2. 以后该用哪种?
- 1. 当第三张关系表中不需要其他额外字段的时候,我们就用默认ManyToManyField就可以了
- 2. 当第三张关系表中需要额外的字段时,我们就要用第三种方式,自己建立第三张关系表并且用ManyToManyField关联
- 3、 一对一 --> OneToOneField(跟ForeignKey一样,生成的字段默认加_id)
- 0. 用法和外键一样
- 1. 当一张表里的字段非常多,并且某几个字段的查询频率远远大于其他字段的时候
- 2. 把常用字段单独拆成一张表,查询的时候更快捷!
- 3. 当两张表建立了一对一关系后,就不能再关联其他表了
- 4. 建表例子
- class Author(models.Model):
- name = models.CharField(max_length=12) # 姓名
- gender = models.SmallIntegerField(choices=((1, '男'), (2, '女'), (3, '保密')), default=3) # 性别
- phone = models.CharField(max_length=11, unique=True) # 手机
- email = models.EmailField() # 邮箱
- info = models.OneToOneField(to='AuthorInfo') # 详细信息,一对一,实际数据库的字段是:info_id
- # 作者详细信息表
- class AuthorInfo(models.Model):
- birthday = models.DateTimeField() # 生日
- city = models.CharField(max_length=12) # 住址
- is_marry = models.BooleanField() # 婚否
- income = models.BigIntegerField() # 收入
- 5. 查询例子
- # 一对一查询,查询第一个作者的住址
- author_obj = Author.objects.first()
- ret = author_obj.info.city
二、 ORM关联查询
- class Publisher(models.Model):
- id = models.AutoField(primary_key=True)
- name = models.CharField(max_length=20)
- addr = models.TextField()
- date = models.DateField() # 成立日期
- def __str__(self):
- return self.name
- class Book(models.Model):
- id = models.AutoField(primary_key=True)
- title = models.CharField(max_length=20)
- price = models.DecimalField(max_digits=6, decimal_places=2)
- isbn = models.CharField(max_length=20, unique=True) # 书籍的唯一编号
- publisher = models.ForeignKey(to='Publisher', on_delete=models.CASCADE)
- def __str__(self):
- return self.title
- class Author(models.Model):
- name = models.CharField(max_length=12) # 姓名
- gender = models.SmallIntegerField(choices=((1, '男'), (2, '女'), (3, '保密')), default=3) # 性别
- phone = models.CharField(max_length=11, unique=True) # 手机
- email = models.EmailField() # 邮箱
- books = models.ManyToManyField(to='Book') # 作品
- info = models.OneToOneField(to='AuthorInfo') # 详细信息
- # 作者详细信息表
- class AuthorInfo(models.Model):
- birthday = models.DateTimeField() # 生日
- city = models.CharField(max_length=12) # 住址
- is_marry = models.BooleanField() # 婚否
- income = models.BigIntegerField() # 收入
表
- 1、 基于对象的查询
- 1. 正向查
- 对象.关联字段.属性
- # 查询第一本书关联的出版社名称
- book_obj = Book.objects.first()
- ret = book_obj.publisher.name
- print(ret)
- 2. 反向查
- 1. 默认不设置related_name属性
- 1. 查找的对象是多个的时候(一对多或多对多时)
- publisher_obj.book_set.all() # 一对多(ForeignKey)和多对多(ManyToManyField)的反向查询:类名_set
- publisher_obj.book_set.filter(price__lt=34)
- 2. 查找的对象时一个的时候(一对一)
- author_info_obj.author.name # 一对一(OneToOneField)的反向查询:类名
- 3. 例如
- # 一对多查询(需要给反向查询的表加_set)
- # 查询第一本书关联的出版社名称(正向查)
- book_obj = Book.objects.first()
- ret = book_obj.publisher.name
- print(ret)
- # 查询明哥出版社出版的所有书(反向查)
- publisher_obj = Publisher.objects.get(name='明哥出版社')
- # 反向查找(多个) .表名_set
- ret = publisher_obj.book_set.all()
- print(ret)
- # 一对一查询(不需要给反向查询的表加_set)
- # 查询id=1的作者婚否(正向查)
- author_obj = Author.objects.first()
- ret = author_obj.info.is_marry
- print(ret)
- # 查找住在深圳的那个作者姓名(反向查)
- authorinfo_obj = AuthorInfo.objects.get(city='深圳')
- ret = authorinfo_obj.author.name
- print(ret)
- 2. 设置related_name='books'属性(publisher = models.ForeignKey(to='Publisher', related_name='books'))
- # 查询明哥出版社出版的所有书
- publisher_obj = Publisher.objects.get(name='明哥出版社')
- publisher_obj.books.all()
- 2、 使用value基于QuerySet的查询(__表示跨表查询)
- 1. 正向查
- Book.objects.filter(id=1).values_list('publisher__name')
- 2. 反向查
- 1. 默认不设置related_name属性,无论一对一、一对多还是多对多默认都用类名的小写
- Publisher.objects.filter(id=1).values_list('book__price')
- 2. 设置related_name='books'属性
- Publisher.objects.filter(id=1).values_list('books__price')
- 3. related_query_name = 'hello'
- 在关联的字段参数设置了related_query_name = 'hello'后,反向查找就不需要使用表名,而是直接使用"hello"
- 3. 例子
- # 热身:普通的values的使用
- # 查询第一本书的名称
- ret = Book.objects.filter(id=1).values('title')
- print(ret)
- # 使用:外键基于QuerySet跨表查询
- # 查询第一本书关联的出版社名称(__表示跨表查询)(正向查找)
- # valuse('publisher')表示通过外键找到了publisher表,__表示跨表取到publisher表的字段的值
- ret = Book.objects.filter(id=1).values('publisher__name')
- print(ret)
- # 反向查找
- # 查询id=1的出版社的所有书的名称和价格
- ret = Publisher.objects.filter(id=1).values_list('book__title', 'book__price')
- print(ret)
- # 一对一基于QuerySet跨表查询
- # 查询id=1的作者婚否(正向查找)
- ret = Author.objects.filter(id=1).values('info__is_marry')
- print(ret)
- # 查找住在深圳的作者的姓名(反向查找)
- ret = AuthorInfo.objects.filter(city='深圳').values('author__name')
- print(ret)
- # 多对多基于QuerySet跨表查询
- # 查询id=1的作者关联的所有数据的名称和价格(正向查找)
- ret = Author.objects.filter(id=1).values('books__title', 'books__price')
- print(ret)
- # 查找id=1的作者的名字(反向查找)
- ret = Book.objects.filter(id=1).values('author__name')
- print(ret)
- # 链式查询
- # 查找id=1的书的作者的城市
- ret = Book.objects.filter(id=1).values('author__info__city')
- print(ret)
ORM关于表那些事的更多相关文章
- ORM以及Django使用ORM创建表
day61 2018-04-28 1. 内容回顾 1. HTTP协议消息的格式: 1. 请求(request) 请求方法 路径 HTTP/1.1\r\n k1:v1\r\n ...\r\n \r\n ...
- Django 通过 ORM 实现表的CRUD
Django 通过 ORM 实现表的CRUD 单表的创建 修改 setting.py 文件 DATABASES = { 'default': { 'ENGINE': 'django.db.backen ...
- day59——orm单表操作
day59 orm单表操作 对象关系映射(object relational mapping) orm语句 -- sql -- 调用pymysql客户端发送sql -- mysql服务端接收到指令并执 ...
- python 之 Django框架(orm单表查询、orm多表查询、聚合查询、分组查询、F查询、 Q查询、事务、Django ORM执行原生SQL)
12.329 orm单表查询 import os if __name__ == '__main__': # 指定当前py脚本需要加载的Django项目配置信息 os.environ.setdefaul ...
- 17-2 orm单表操作和多表操作
参考:https://www.cnblogs.com/liwenzhou/p/8660826.html 一 ORM单表操作 1 增删改查 1. 查询 1. 查所有 models.Publisher. ...
- 第十七篇 ORM跨表查询和分组查询---二次剖析
ORM跨表查询和分组查询---二次剖析 阅读目录(Content) 创建表(建立模型) 基于对象的跨表查询 一对多查询(Publish与Book) 多对多查询 (Author 与 Book) 一对一查 ...
- Django ORM多表查询练习
ORM多表查询 创建表结构: from django.db import models # 创建表结构 # Create your models here. class Class_grade(mod ...
- django框架基础-ORM单表操作-长期维护
############### 单表操作-添加数据 ################ import os if __name__ == '__main__': os.environ.set ...
- ORM单表查询,跨表查询,分组查询
ORM单表查询,跨表查询,分组查询 单表查询之下划线 models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值models ...
随机推荐
- 后端开发者的Vue学习之路(四)
目录 上节内容回顾: npm 介绍 安装 常用命令: 补充: 基于npm的Hello World 项目结构分析 用法迁移 小提醒 ES6语法 知识补充 单文件组件 使用注意: 路由 开启路由 定义路由 ...
- 一种递推组合数前缀和的Trick
记录一下一种推组合数前缀和的方法 Trick 设\(\sum_{i = 0}^m C_n^i = S(n, m)\) \(S\)是可以递推的 \(S(n, m + 1) = S(n, m) + C_{ ...
- Arcgis瓦片--js客户端加载
接上篇博客,下载好arcgis格式的瓦片数据以后,需要用js客户端在前端加载出来.这里介绍两种方案: 1.使用超图iServer将瓦片发布成rest地图服务,或者arcgis地图服务,客户端直接加载 ...
- (最详细)小米MIX的Usb调试模式在哪里打开的教程
当我们使用安卓手机链接pc的时候,或者使用的有些应用比如我们团队营销团队当使用的应用引号精灵,以前老版本就需要开启Usb调试模式下使用,现当新版本不需要了,如果手机没有开启Usb调试模式,pc则没法成 ...
- Android 使用Picasso加载网络图片等比例缩放
在做android图片加载的时候,由于手机屏幕受限,很多大图加载过来的时候,我们要求等比例缩放,比如按照固定的宽度,等比例缩放高度,使得图片的尺寸比例得到相应的缩放,但图片没有变形.显然按照andro ...
- python之生成随机密码
https://www.cnblogs.com/evablogs/p/7096583.html 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #!/usr/bin/py ...
- 数据库H2学习
本文转载自:https://www.cnblogs.com/xdp-gacl/p/4171024.html 一.H2数据库介绍 常用的开源数据库有:H2,Derby,HSQLDB,MySQL,Post ...
- SQL SERVER 索引碎片
一次发现同样的SQL在线上库和复制库执行时间差好多,重新创建相关表索引,性能提升明显,怀疑索引有碎片
- 写入Log错误日志
第一步创建ApplicationLog类 代码: using System;using System.Collections.Generic;using System.Linq;using Syste ...
- Asp.net Core应用程序部署为服务
安装前使用dotnet命令运行下看网站能不能正常运行 1.下载nssm,下载后解压文件 下载地址:https://nssm.cc/usage 2.使用命令行工具进入到nssm的目录: 3.执行服务安装 ...