Django ORM 多表操作
Django ORM 多表操作

表模型
- 图书表
- 出版社表
- 作者表
- 作者详情表
表关系
- 一对一:一对一推荐建在查询频率高的一方
- 一对多:外键字段建在多的一方
- 多对多:外键字段建在查询频率多的一方,在Django第三张表不需要创建,自动创建
ps:外键字段不需要写表名_id后面的_id,ORM创建的时候自动添加了_id,以及外键以虚拟字段的形式存在
创建模型
'''models.py'''
from django.db import models
# 书籍表
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=6, decimal_places=2)
pub_date = models.DateField()
publish = models.ForeignKey(to='Publish',on_delete=models.CASCADE)
authors = models.ManyToManyField(to='Author')
# 出版社表
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
# 作者表
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
author_detail = models.OneToOneField(to='AuthorDetail',on_delete=models.CASCADE)
# 作者详情表
class AuthorDetail(models.Model):
phone_number = models.BigIntegerField()
email = models.EmailField()
说明:
- 1、EmailField 数据类型是邮箱格式,底层继承 CharField,进行了封装,相当于 MySQL 中的 varchar。
- 2、Django1.1 版本不需要联级删除:on_delete=models.CASCADE,Django2.2 需要。
- 3、一般不需要设置联级更新.
- 4、外键在一对多的多中设置:models.ForeignKey("关联类名", on_delete=models.CASCADE)。
- 5、OneToOneField = ForeignKey(...,unique=True)设置一对一。
- 6、若有模型类存在外键,创建数据时,要先创建外键关联的模型类的数据,不然创建包含外键的模型类的数据时,外键的关联模型类的数据会找不到
逆向到表模型

插入数据



ps:插入几条数据方便操作
ORM 添加数据(添加外键)
一对多(外键 ForeignKey)
方式一: 传对象的形式,返回值的数据类型是对象,书籍对象
步骤:
- 获取出版社对象
- 给书籍的出版社属性 pulish 传出版社对象
'''test.py'''
import os
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangoForeignKey.settings')
import django
django.setup()
from app01 import models
pub_obj = models.Publish.objects.filter(pk=1).first()
book = models.Book.objects.create(title='水浒传',price='99.9',pub_date='2021-02-07',publish=pub_obj)
print(book) # Book object (3)
if __name__ == '__main__':
main()
方式二: 传对象 id 的形式(常用)
一对多中,设置外键属性的类(多的表)中,MySQL 中显示的字段名是:外键属性名_id。
返回值的数据类型是对象,书籍对象。
步骤:
- a. 获取出版社对象的 id
- b. 给书籍的关联出版社字段 pulish_id 传出版社对象的 id
import os
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangoForeignKey.settings')
import django
django.setup()
from app01 import models
book = models.Book.objects.create(title='西游记',price='88.8',pub_date='2008-08-09',publish_id=1)
print(book)
一对一 (OneToOneFeild)
方式一:传对象 id 的形式(常用)
格式:外键属性名_id
import os
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangoForeignKey.settings')
import django
django.setup()
from app01 import models
author = models.Author.objects.create(name='杜甫',age=38,author_detail_id=2)
print(author)
方式二:传对象的形式,返回值的数据类型是对象
import os
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangoForeignKey.settings')
import django
django.setup()
from app01 import models
author_detail_obj = models.AuthorDetail.objects.filter(pk=3).first()
author = models.Author.objects.create(name='王羲之',age=44,author_detail=author_detail_obj)
print(author)
多对多(ManyToManyField):在第三张关系表中新增数据
方式一: 传对象形式,无返回值。
步骤:
- 获取作者对象
- 获取书籍对象
- 给书籍对象的 authors 属性用 add 方法传作者对象
import os
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangoForeignKey.settings')
import django
django.setup()
from app01 import models
'''多对多'''
# 获取作者对象
author_obj1 = models.Author.objects.filter(pk=4).first()
author_obj2 = models.Author.objects.filter(pk=5).first()
# 获取书籍对象
book_obj1 = models.Book.objects.filter(pk=3).first()
book_obj2 = models.Book.objects.filter(pk=3).first()
# 添加数据
book_obj1.authors.add(author_obj1,author_obj2)
book_obj2.authors.add(author_obj2)

方式二: 传对象id形式,无返回值。
步骤:
- a. 获取作者对象的 id
- b. 获取书籍对象
- c. 给书籍对象的 authors 属性用 add 方法传作者对象的 id
import os
# Create your tests here.
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangoForeignKey.settings')
import django
django.setup()
from app01 import models
book_obj = models.Book.objects.filter(title='水浒传').first()
book_obj.authors.add(1,4)

ORM 修改数据
'''一对多,一对一'''
models.Book.objects.filter(pk=1).update(publish_id=2)
book_obj = models.Book.objects.filter(pk=1).first()
print(book_obj.publish)
publish_obj = models.Publish.objects.filter(pk=1).first()
models.Book.objects.filter(pk=1).update(publish=publish_obj)
'''多对多'''
book_obj.authors.set([3, 2])
book_obj.authors.set([author_obj1, author_obj2])
ORM 删除和清空数据
remove():从关联对象集中移除执行的模型对象
对于 ForeignKey 对象,这个方法仅在 null=True(可以为空)时存在,无返回值
author_obj =models.Author.objects.get(id=1)
book_obj = models.Book.objects.get(id=11)
author_obj.book_set.remove(book_obj)
return HttpResponse("ok")
clear():从关联对象集中移除一切对象,删除关联,不会删除对象
对于 ForeignKey 对象,这个方法仅在 null=True(可以为空)时存在
# 清空三国关联的所有作者
book = models.Book.objects.filter(title="三国演义").first()
book.authors.clear()
跨表查询
- 正向:外键字段在哪,去从该表的角度查另外的表,就是正向
- 反向:从没有外键表去查另外相关联的表,就是反向
口诀:
- 正向查询按外键字段
- 反向查询按表名小写
注意:
正向:属性名
反向:小写类名加 _set
反向查询的时候查询的对象可能有多个的情况加__set,查询的对象只有一个的情况不需要加
基于对象的跨表查询
'''子查询思路'''
1、先查出一个对象
2、基于对象正反查
'''基于对象的跨表查询:正向'''
1.查询三国演义书籍对应的出版社名称
book_obj = models.Book.objects.filter(title='三国演义').first()
publish = book_obj.publish
print(publish.name) # 南方出版社
2.查询水浒传对应的作者
book_obj = models.Book.objects.filter(title ='水浒传').first()
author = book_obj.authors
print(author.name)
3.查询李白的手机号
author_obj = models.Author.objects.filter(name='李白').first()
author_obj_det = author_obj.author_detail
print(author_obj_det.phone_number)
'''基于对象的跨表查询:反向'''
4.查询东方出版社出版过的书籍
publish = models.Publish.objects.filter(name='东方出版社').first()
books = publish.book_set.all()
print(books.first().title) # 西游记
5.查询杜甫写过的书
author = models.Author.objects.filter(name='杜甫').first()
books = author.book_set.all()
print(books.first().title)
6.查询email是163@qq.com的作者姓名 # 一对一的情况,不需要写_set
author_det = models.AuthorDetail.objects.filter(email='163@qq.com').first()
author = author_det.author
print(author.name) # 李白
基于双下划线的跨表查询
上面的操作类似子查询,将上一个查询结果当作该次查询的条件使用,那么现在演示的跨表操作,就类似sql连表操作(inner join···),是两种不同的查询方法
'''基于双下划线的跨表操作:连表操作'''
'''正向'''
1.查询三国演义书籍对应的出版社名称
publish = models.Book.objects.filter(title='三国演义').values('publish__name')
print(publish) # <QuerySet [{'publish__name': '南方出版社'}]>
2.查询水浒传对应的作者
author = models.Book.objects.filter(title='水浒传').values('authors__name','authors__age')
print(author)
3.查询李白的手机号
auuth_det_obj = models.Author.objects.filter(name='李白').values('author_detail__phone_number')
print(auuth_det_obj)
'''反向'''
4.查询东方出版社出版过的书籍
book_obj = models.Publish.objects.filter(name='东方出版社').values('book__title')
print(book_obj)
5.查询杜甫写过的书
books = models.Author.objects.filter(name='杜甫').values('book__title')
print(books)
6.查询email是163@qq.com的作者姓名
author = models.AuthorDetail.objects.filter(email='163@qq.com').values('author__name')
print(author)
'''一对一的情况'''
7. 查询水浒传对应的作者的电话和电话
author_det = models.Book.objects.filter(title='水浒传').values('authors__author_detail__phone_number','authors__author_detail__email')
print(author_det)
聚合查询
- 聚合函数:Sum,Max,Min,Count,Avg
- 在Django中使用聚合函数需要导入:
from django.db.models import Sum,Max,Min,Min,Count,Avg
注意:
- 使用聚合函数查询的时候,建议把聚合结果字段重命名
# 格式:aggregate(别名 = 聚合函数名("属性名称"))
models.Book.objects.all().aggregate(AllPrice=Sum('price'))
- 聚合查询返回值的数据类型是字典
- 聚合函数
aggregate()是 QuerySet 的一个终止子句, 生成的一个汇总值,相当于 count(),使用 aggregate() 后,数据类型就变为字典,不能再使用 QuerySet 数据类型的一些 API 了 - 日期数据类型(DateField)可以用 Max 和 Min
示例
'''聚合查询'''
from django.db.models import Avg,Max,Min,Sum,Count
'''1、查询所有书籍的总价,平均值,最大值,最小值,个数'''
book_totalprice = models.Book.objects.all().aggregate(totalprice = Sum('price'),maxprice = Max('price'),minprice = Min('price'),avgprice = Avg('price'),num = Count('price'))
print(book_totalprice)
# {'totalprice': Decimal('377.50'), 'maxprice': Decimal('100.00'), 'minprice': Decimal('88.80'), 'avgprice': Decimal('94.375000'), 'num': 4}
F查询
F 查询:取出某个字段对应的值
导入:from django.db.models import F
比如F(‘price’)的意思就是取出该书价格的数值
from django.db.models import F
# 每本书的价格上调10元
res = models.Book.objects.update(price=F('price')+10)
print(res) # 影响的行数:4
# 查询评论数大于阅读数的书籍
res=models.Book.objects.filter(commit_num__gt=F('read_num'))
print(res)
Q查询
我们知道在filter中写的条件可以以逗号隔开是and的关系,那么或,非得关系如果构造呢?
此时就需要Q函数来帮助我们去构造这些关系:
与(&),或(|),非(~)
导入: from django.db.models import Q
from django.db.models import Q
1、查询名字叫三国演义或者价格大于100的书
res = models.Book.objects.filter(Q(title='三国演义')|Q(price__gt=100))
print(res)
2、查询名字叫三国演义并且价格小于100的书
res = models.Book.objects.filter(Q(title='三国演义')&Q(price__lt=100))
print(res)
3、查询名字不是三国演义的书名
res = models.Book.objects.filter(~Q(title='三国演义'))
print(res)
Django ORM 多表操作的更多相关文章
- Django ORM多表操作
多表操作 创建模型 实例:我们来假定下面这些概念,字段和关系 作者模型:一个作者有姓名和年龄. 作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息.作者详情模型和作者模型之间是一对 ...
- django ORM单表操作
1.ORM介绍 ORM是“对象-关系-映射”的简称 映射关系: mysql---------Python 表名----------类名 字段----------属性 表记录--------实例化对象 ...
- django框架基础-ORM单表操作-长期维护
############### 单表操作-添加数据 ################ import os if __name__ == '__main__': os.environ.set ...
- Django框架06 /orm多表操作
Django框架06 /orm多表操作 目录 Django框架06 /orm多表操作 1. admin相关操作 2. 创建模型 3. 增加 4. 删除 5. 修改 6. 基于对象的跨表查询 7. 基于 ...
- Django框架05 /orm单表操作
Django框架05 /orm单表操作 目录 Django框架05 /orm单表操作 1. orm使用流程 2. orm字段 3. orm参数 4. orm单表简单增/删/改 5. orm单表查询 5 ...
- day53:django:URL别名/反向解析&URL分发&命名空间&ORM多表操作修改/查询
目录 1.URL别名&反向解析 2.URL分发&命名空间 3.ORM多表操作-修改 4.ORM多表操作-查询 4.1 基于对象的跨表查询 4.2 基于双下划线的跨表查询 4.3 聚合查 ...
- Django ORM那些相关操作zi
Django ORM那些相关操作 一般操作 看专业的官网文档,做专业的程序员! 必知必会13条 <1> all(): 查询所有结果 <2> filter(**kwargs) ...
- Django ORM 那些相关操作
Django ORM 那些相关操作 一般操作 必知必会13条 <> all(): #查询所有的结果 <> filter(**kwargs) # 它包含了与所给筛选条件相匹配的对 ...
- day59——orm单表操作
day59 orm单表操作 对象关系映射(object relational mapping) orm语句 -- sql -- 调用pymysql客户端发送sql -- mysql服务端接收到指令并执 ...
随机推荐
- 【记录一个问题】libtask无法在android下编译通过
源码来自:https://github.com/msteinert/libtask 首先是asm.S无法编译通过. 其次,编译context.c出现这些错误: .//context.c:124:19: ...
- entity framework无法写入数据库.SaveChanges()失败
参考https://stackoverflow.com/questions/26745184/ef-cant-savechanges-to-db/28256645 https://www.codepr ...
- MySQL的innoDB存储引擎的运作方式,数据结构等
先上InnoDB架构图: 自上而下依次为内存区结构,后台线程,操作系统,磁盘存储,日志文件等. 其中内存由缓冲池,额外缓冲池,日志缓冲池组成.其中缓冲池中结构如下: 在磁盘存储文件中,MyISAM存储 ...
- 学习鸟哥linux私房菜--安装中文输入法fcitx
首先需要卸载前面安装的scim,查阅命令,参考网址如下 http://www.cnblogs.com/propheteia/archive/2012/06/26/2563383.html 链接中博主采 ...
- 嵌入式硬件之ADC/DAC
嵌入式硬件之ADC/DAC 写在前面 这几天在做一个寒假练项目,其中涉及到了音频的处理,ADC.DAC再次进入到了我的视野,并引起了我新的思考. 1.初次相识 记得去年七月份,本科毕业刚离校,就到研究 ...
- 数据库查询语句遇到:Unknown column 'XXXX' in 'where clause'解决方法
数据库查询语句遇到:Unknown colunm 'XXX' in 'where clause'解决方法 根本原因:可能是sql语句所用到的数据类型错误(int与String)弄错- 我的情况: 在网 ...
- 「SHOI2006」有色图
首先发现这题虽然是边的置换,但是是由点的置换所造成的,并且发现点置换对应的所有边置换和置换操作构成置换群. 由于颜色可以全选,那么根据 Polya 定理,答案为: \[|X / G| = \frac{ ...
- 记一次.net core 异步线程设置超时时间
前言: 刷帖子看到一篇 Go 记录一次groutine通信与context控制 看了一下需求背景,挺有意思的,琢磨了下.net core下的实现 需求背景: 项目中需要定期执行任务A来做一些辅助的工作 ...
- AESUtil_1
package com.tebon.ams.util;import org.apache.commons.codec.binary.Base64;import javax.crypto.Cipher; ...
- xshell脚本之条件语句
xshell脚本之条件语句 1.test命令: 如果test命令中列出的条件成立,test命令就会退出并返回状态码0, 如果条件不成立,test命令就会退出并返回非零的退出状态码,这使得if-then ...