Django-ORM-多表操作
一、创建模型
表与表之间的关系:一对一、多对一、多对多
一对一
xx = models.OneToOneField(to='表名',to_filed='字段名',on_delete=models.CASCADE)
to_field可以不写,默认是关联到另一张表的主键,
on_delete在1.x版本的Django中不用写,默认是级联删除的,2.x版本的django要写。
一对多
xx = models.ForengnKey(to='表名',to_field='字段名',on_delete=models.CASCAD)
多对多
xx = models.ManyTOManyField(to='另外一个表名') # 这是自动创建第三表
# ManyToManyField就是多对多
实例:
作者模型:一个作者有姓名和年龄。
作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息。作者详情模型和作者模型之间是一对一的关系(one-to-one)
出版商模型:出版商有名称,所在城市以及email。
书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many);一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many)。
# models.py 文件
from django.db import models
# 作者表
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
# 和Authordetail建立一对一的关系,一对一的这个关系字段写在两个表的任意一个表里。
# 并且ORM会自动给你这个字段名字拼上一个_id,如:authordetail_id
authordetail = models.OneToOneField(to='AuthorDetail', to_field='id', on_delete=models.CASCADE)
# “OneToOneField()” 表示一对一
# “to” 指向表
# “to_field” 指向你关联字段,不写默认会自动关联主键字段
# “on_delete=models.CASCADE” 在2.x之后的需要写上,表示:是否级联删除
# 作者详细信息表
class AuthorDetail(models.Model):
birthday = models.DateField()
telephone = models.CharField(max_length=32)
addr = models.CharField(max_length=64)
# 出版社信息表 和书籍表示一对多的关系
class Publish(models.Model):
name = models.CharField(max_length=32)
city = models.CharField(max_length=32)
email = models.EmailField()
# 书籍信息表
class Book(models.Model):
name = models.CharField(max_length=32)
publishDate = models.DateField()
price = models.DecimalField(max_digits=5, decimal_places=2) # 小数点前五位,小数点后两位
# 建立一对多的关系,外键字段建立在多的一方,字段publishs如果是外键字段,那么它自动是int类型
publishs = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
# 建立多对多的关系,ManyToManyField 可以建立在两个模型中的任意一个
# 并且 author 并不是字段,只能说这个book类里面有author这个字段属性
# 它会自动建立第三张表,就用 author 去操作第三张表
author = models.ManyToManyField(to='Author')
二、增删改
增加记录
一对一
# 方式一:
new_author_detail = models.AuthorDetail.objects.create( # 也是个记录对象
birthday='1943-08-04',
telephone='8743845',
addr='成都'
)
models.Author.objects.create(
name='鲍勃',
age='32',
authordetail=new_author_detail
)
# 方式二:先查询出来,在对外键字段赋值,(常用)
obj = models.AuthorDetail.objects.filter(addr='四川').first() # 转换成记录对象
models.Author.objects.create(
name='艾伦',
age='23',
authordetail_id=obj.id
)
一对多
# 方式一:
obj = models.Publish.objects.get(id=2)
models.Book.objects.create(
name='魔道祖师',
publishDate='2011-09-03',
price=33,
publishs=obj
)
# 方式二:常用
models.Book.objects.create(
name='魔道祖师2',
publishDate='2011-09-03',
price=34,
publishs_id=models.Publish.objects.get(name='中国华侨出版社').id
)
多对多
# 方式一:常用
book_obj = models.Book.objects.get(id=1) # 获取这本书的记录对象
book_obj.author.add(*[1, 2]) # 在使用记录对象中的author属性add添加作者id
# 方式二:
author1 = models.Author.objects.get(name='艾伦3') # 先查出作者记录对象
author2 = models.Author.objects.get(name='田姊')
book_obj = models.Book.objects.get(name='格局') # 在查出书籍记录对象
book_obj.author.add(*[author2, author1]) # 书籍记录对象add添加作者记录对象
删除记录
一对一
一对一和一对多的删除和单表删除是一样的
一对一 表一外键关联到表二,表一删除,不影响表二,表二删除会影响表一。
一对多
# 删除中国华侨出版社,并且还会级联删除所有的所有中国华侨出版社的书籍
models.Publish.objects.get(name='中国华侨出版社').delete()
models.Book.objects.get(name='格局').delete() # 只删除书籍不影响出版社
多对多
book_obj = models.Book.objects.get(name='格局')
book_obj.author.remove(1) # 删除对应的格局书籍的作者id
book_obj.author.remove(*[1, 3]) # 删除对应的格局书籍的多个作者id
book_obj.author.clear() # 清空这本书籍的所有作者
book_obj.author.add(1) # 新增
book_obj.author.set([1, 2]) # 删除后添加,——>更新
修改记录
一对一
models.Author.objects.filter(name='鲍勃').update(
name='小杨',
age=18,
authordetail=models.AuthorDetail.objects.get(id=6), # 方式一:
authordetail_id=4 # 方式二:
)
一对多
models.Book.objects.filter(pk=3).update(
name='回首往事',
publishs=models.Publish.objects.get(id=2), # 方式一:
publishs_id=1 # 方式二:
)
多对多
更新的是第三张表的字段
book_obj = models.Book.objects.get(id=2)
book_obj.author.set([1, 2, 3])
# clear 清空
# add 增加
三、基于对象的跨表查询(子查询)
正向查询和反向查询:
关系属性(字段)写在那个类(表)里面,从当前类(表)的数据去查询它关联类(表)的数据叫做正向查询,反之叫做反向查询。
基表(基于那个表)决定了正向还是反向
一对一
# 正向查询
# 查询作者为小杨的电话
author_obj = models.Author.objects.get(name='小杨')
tel = author_obj.authordetail.telephone
print(tel)
# 反向查询
# 查询电话为4323211的作者姓名
author_obj = models.AuthorDetail.objects.get(telephone='4323211')
name = author_obj.author.name
print(name)
"""
正向查询:Authorobj.authordetail 对象.关联属性名称
--------------------->
Author AuthorDetail
<---------------------
反向查询:AuthorDetailobj.author 对象.小写类名
"""
一对多
# 正向查询
# 查询时间简史这本书的出版社
book_obj = models.Book.objects.get(name='时间简史')
name = book_obj.publishs.name
print(name)
# 反向查询
# 查询中国华侨出版社出版了那些书
pub_obj = models.Publish.objects.get(name='中国华侨出版社')
name = pub_obj.book_set.all()
print(name)
"""
正向查询:Bookobj.publishs 对象.关联属性名称
--------------------->
Book Publish
<---------------------
反向查询:Publishobj.book_set.all() 对象.小写类名_set
"""
多对多
# 正向查询
# 时间简史这本书是那些作者写的
book_obj = models.Book.objects.get(name='时间简史')
obj = book_obj.author.all()
print(obj)
# 反向查询
# 作者田姊写了那些书
author_obj = models.Author.objects.get(name='田姊')
obj = author_obj.book_set.all()
print(obj)
"""
正向查询:Bookobj.author.all() 对象.关联属性名称
--------------------->
Book Author
<---------------------
反向查询:Authorobj.book_set.all() 对象.小写类名_set
"""
四、基于双下划线的跨表查询(连表join)
普通版
一对一
# 查询小杨的电话
# 正向查询
obj = models.Author.objects.filter(name='小杨').values('authordetail__telephone')
print(obj)
# 反向查询
obj = models.AuthorDetail.objects.filter(author__name='小杨').values('telephone')
print(obj)
# 查询电话为4323211的作者名字
# 正向查询
obj = models.Author.objects.filter(authordetail__telephone='4323211').values('name')
print(obj)
# 反向查询
obj = models.AuthorDetail.objects.filter(telephone='4323211').values('author__name')
print(obj)
一对多
# 查询时间简史是哪个出版社出版的
# 正向查询
obj = models.Book.objects.filter(name='时间简史').values('publishs__name')
print(obj)
# 反向查询
obj = models.Publish.objects.filter(book__name='时间简史').values('name')
print(obj)
# 中国华侨出版社出版了那些书
# 正向查询
obj = models.Book.objects.filter(publishs__name='中国华侨出版社').values('name')
print(obj)
# 反向查询
obj = models.Publish.objects.filter(name='中国华侨出版社').values('book__name')
print(obj)
多对多
# 时间简史是由那些作者写的
# 正向查询
obj = models.Book.objects.filter(name='时间简史').values('author__name')
print(obj)
# 反向查询
obj = models.Author.objects.filter(book__name='时间简史').values('name')
print(obj)
# 田姊写了那些书
# 正向查询
obj = models.Book.objects.filter(author__name='田姊').values('name')
print(obj)
# 反向查询
obj = models.Author.objects.filter(name='田姊').values('book__name')
print(obj)
进阶版
1、查询中国华侨出版社出版的书的名称以及作者的名字
# 方式一:基于表为Book
obj = models.Book.objects.filter(publishs__name='中国华侨出版社').values('name', 'author__name')
print(obj)
# 方式二:基于表为Publish
obj = models.Publish.objects.filter(name='中国华侨出版社').values('book__name', 'book__author__name')
print(obj)
# 方式三:基于表为Author
obj = models.Author.objects.filter(book__publishs__name='中国华侨出版社').values('book__name', 'name')
print(obj)
2、手机号以432开头的作者出版过的所有书籍以及出版社名称
# 方式一:基于表为Author
obj = models.Author.objects.filter(authordetail__telephone__startswith=432).values('book__name', 'book__publishs__name')
print(obj)
# 方式二:基于表为Publish
obj = models.Publish.objects.filter(book__author__authordetail__telephone__startswith='432').values('book__name', 'name')
print(obj)
# 方式三:基于表为AuthorDetail
obj = models.AuthorDetail.objects.filter(telephone__startswith='432').values('author__book__name', 'author__book__publishs__name')
print(obj)
五、聚合查询、分组查询、F和Q查询
聚合查询
聚合查询使用 aggregate() :他是一个终止句子,它返回一个包含一些键值对的字典。
聚合函数:Avg、Max、Min、Sun、Count。使用的时候需要导入
例如:计算所有图书的平均价格
from django.db.models import Avg
price_avg = models.Book.objects.all().aggregate(average_price=Avg('price'))
print(price_avg)
# 输出
{'average_price': Decimal('40.000000')}
分组查询
annotate( ):——为调用的QuerySet中每一个对象都生成一个独立的统计值(统计方法用聚合函数)
例如:查询每个出版社出版的书籍的平均价格
方式一:
from django.db.models import Avg
obj = models.Publish.objects.annotate(price_avg=Avg('book__price')).values('name', 'price_avg')
print(obj)
# 输出
<QuerySet [{'name': '光明日报出版社', 'price_avg': Decimal('48.500000')}, {'name': '中国华侨出版社', 'price_avg': Decimal('47.500000')}]>
方式二:
from django.db.models import Avg
obj = models.Book.objects.values('publishs__name').annotate(price_avg=Avg('price'))
print(obj)
# 输出
<QuerySet [{'publishs__name': '光明日报出版社', 'price_avg': Decimal('48.500000')}, {'publishs__name': '中国华侨出版社', 'price_avg': Decimal('47.500000')}]>
F和Q查询
F查询:
1、F( ) 可以用来比较同一个model 实例中两个不同字段的值。
实例:查询Book表中点赞数大于评论数的书籍
from django.db.models import F
obj = models.Book.objects.filter(good__gt=F('comment'))
print(obj)
2、也支持F( ) 对象之间以及F( ) 对象和常数之间的加减乘除和取模的操作
实例:查询点赞数大于评论数两倍的书籍
from django.db.models import F
obj = models.Book.objects.filter(good__gt=F('comment')*2)
print(obj)
3、修改操作也可以批量修改
实例:将每本书的价格提升30
from django.db.models import F
models.Book.objects.all().update(price=F('price')+30)
Q查询:
1、Q查询可以使用&(与)、|(或)、~
(非)操作符组合。
实例:查询Book书籍中作者名字为“小杨”或者“小明”的书籍
from django.db.models import Q
obj = models.Book.objects.filter(Q(author__name='小杨')|Q(author__name='小明'))
print(obj)
# 输出
<QuerySet [<Book: 魔道祖师1>, <Book: 山海经>]>
2、可以组合&
和|
操作符以及使用括号进行分组来编写任意复杂的Q
对象进行Q嵌套,多层Q嵌套等。
实例:查询作者为 “小杨” 和非 ”光明日报出版社“ 出版的,并且价格小于100的书籍
from django.db.models import Q
obj = models.Book.objects.filter(Q(Q(author__name='小杨') & ~Q(publishs__name='光明日报出版社')) & Q(price__lt=100)).values('name')
print(obj)
ORM执行原生SQL
obj = models.Book.objects.raw('select * from app01_book;')
for i in obj:
print(i.name)
# 输出
山海经
时间简史
回首往事
魔道祖师1
魔道祖师2
魔道祖师3
本文来自博客园,作者:Mr-Yang`,转载请注明原文链接:https://www.cnblogs.com/XiaoYang-sir/articles/14902983.html