Django(六)
神奇的双下划线查询
# 1.查询年龄大于20岁的人的信息
from app01 import models
res = models.User.objects.filter(age__gte=20)
print(res)
# 2.查询年龄是18,20的用户
res1 = models.User.objects.filter(age__in=(18,20))
print(res1)
# 查询年龄在18-20之间的用户
res2 = models.User.objects.filter(age__range=[18,20])
print(res2)
# 4.查询名字中含有a的用户
res3 = models.User.objects.filter(name__contains='a')
print(res3)
# 5.查询日期的月份是5的数据
res4 = models.User.objects.filter(date__month=5)
print(res4)
'''
日常开发中,根据不同的数据类型,通过变量名点的方法就可以知道对于这个类型的数据有哪些双下划线方法
'''
外键字段的创建
"""
MySQL复习
关系的种类
一对多关系
多对多关系
一对一关系
关系的判断
换位思考
字段的位置
一对多关系 外键字段建在多的一方
多对多关系 外键字段建在第三张关系表中
一对一关系 外键字段建在任意一方都可以 但是推荐建在查询频率较高的表中
"""
django orm创建表关系
图书表
出版社表
作者表
作者详情表
# 图书与出版社
一本书只能有一个出版社
一个出版社可以出版多本书
所以是一对多的关系,外键应该建立在图书表
在图书类里面加上
publisher = models.ForeignKey(to='Publisher') # 创建一对多的外键
# 图书与作者
一本书可以由多个作者编写
一个作者可以写多本书
所以是多对多的关系,外键应用第三张表记录
在图书类加上
authors = models.ManyToManyField(to='Author') # 创建多对多的外键
也可以在作者类里建外键
# 作者与作者详情
一个作者只能与一个详情相对应
所以是一对一的关系
因为作者类查询较频繁,所以作者类加上
author_details = models.OneToOneField(to='AuthorDetails') # 建立一对一的外键
# orm外键的创建会自动去找各表的主键,建立外键关联
ManyToManyField不会在表中创建实际的字段 而是告诉django orm自动创建第三张关系表
ForeignKey、OneToOneField会在字段的后面自动添加_id后缀 如果你在定义模型类的时候自己添加了该后缀那么迁移的时候还会再次添加_id_id 所以不要自己加_id后缀
ps:三个关键字里面的参数
to用于指定跟哪张表有关系 自动关联主键
to_field\to_fields 也可以自己指定关联字段
外键字段操作
# 一对一,一对多外键操作
# 新增数据
# models.Book.objects.create(title='生物',price=29.9,publisher_id=1) # 直接写外键数据
# publisher_obj = models.Publisher.objects.filter(pk=1).first()
# models.Book.objects.create(title='物理',price=29.9,publisher=publisher_obj) # 通过外键对象添加
# 修改数据
# models.Book.objects.filter(pk=1).update(publisher_id=3) # 直接写外键数据
# publisher_obj = models.Publisher.objects.filter(pk=1).first()
# models.Book.objects.filter(pk=1).update(publisher=publisher_obj) # 通过外键对象添加
# 多对多操作
# # 第三张表添加关系
# book_obj = models.Book.objects.filter(pk=1).first()
# book_obj.authors.add(2)
# # 对象.外键名.add(),括号内可以放多个值,同时添加多个关系,用逗号隔开
# # 第三张表修改关系
# book_obj = models.Book.objects.filter(pk=1).first()
# book_obj.authors.set([3,2,1])
# # 对象.外键名.set(),括号内必须是一个可迭代对象,值可以是对象,也可以是主键值
# # 第三张表删除关系
# book_obj = models.Book.objects.filter(pk=1).first()
# book_obj.authors.remove(1)
# # 对象.外键名.remove(),括号内的值可以是对象,也可以是主键值
# # 4.清空第三张表的数据
# book_obj = models.Book.objects.filter(pk=1).first()
# book_obj.authors.clear()
# # 对象.外键名.clear(),括号内无需参数,清除当前对象的有关记录
多表查询
"""
MySQL多表查询思路
子查询
将SQL语句用括号括起来当做条件使用
连表操作
inner join\left join\right join\union
django orm本质还是使用的上述两种方法
子查询>>>:基于对象的跨表查询
连表操作>>>:基于双下划线的跨表查询
"""
# 正反向的概念
当前数据对象如果有外键字段,就是正向,没有外键字段就是反向
"""
查询口诀
正向查询按外键字段名
反向查询按表名小写
"""
基于对象的跨表查询
"""基于对象的跨表查询本质就是子查询即分步操作即可"""
eg:
给定表A字段值,查表B
1.先根据条件获取表A对象
2.正向查询通过表A对象.外键就可以查询表B对象
3.如是反向查询,通过A对象.B表名小写,如果是一对一关系,直接会返回对象,如果是一对多,多对多关系,要在表名后加_set
4.如果返回结果存在多个对象,需要再最后加all(),否则会返回None
# # 1.查询语文书籍对应的出版社
# # 获取书籍对象
# book_obj = models.Book.objects.filter(title='语文').first()
# # 跨表查询
# res = book_obj.publisher
# print(res) # 出版社对象:a社
# # 2.查询数学书籍对应的作者
# book_obj = models.Book.objects.filter(title='数学').first()
# res = book_obj.authors # app01.Author.None,出现这种情况在后面加上.all()
# res = book_obj.authors.all() # <QuerySet [<Author: 作者对象:oscar>]>
# print(res)
# # 3.查询作者oscar的详情信息
# author_obj = models.Author.objects.filter(name='oscar').first()
# res = author_obj.author_details
# print(res) # 作者详情对象:120
# # 4.查询b社出版的书籍
# publisher_obj = models.Publisher.objects.filter(name='b社').first()
# # res = publisher_obj.book_set # app01.Book.None
# res = publisher_obj.book_set.all() # <QuerySet [<Book: 书籍对象:英语>, <Book: 书籍对象:政治>]>
# print(res)
# # 5.查询oscar编写的书籍
# author_obj = models.Author.objects.filter(name='oscar').first()
# res = author_obj.book_set.all() # <QuerySet [<Book: 书籍对象:数学>, <Book: 书籍对象:地理>]>
# print(res)
# # 6.查询电话是110的作者
# author_details_obj = models.AuthorDetails.objects.filter(phone=110).first()
# res = author_details_obj.author # 作者对象:petter
# print(res)
基于双下划线的跨表查询
"""基于双下划线的跨表查询本质就是连表操作"""
eg:
给定表A字段值,查表B
models.A.objects.filter(A的字段名=字段值).values(B__B的字段名)
# # 1.查询语文书籍对应的出版社名称
# res = models.Book.objects.filter(title='语文').values('publisher__name')
# print(res) # <QuerySet [{'publisher__name': 'a社'}]>
# # 2.查询数学对应的作者姓名和年龄
# res = models.Book.objects.filter(title='数学').values('authors__name','authors__age')
# print(res) # <QuerySet [{'authors__name': 'oscar', 'authors__age': 20}]>
# # 3.查询作者oscar的手机号和地址
# res = models.Author.objects.filter(name='oscar').values('author_details__phone','author_details__addr')
# print(res) # <QuerySet [{'author_details__phone': 120, 'author_details__addr': '上海'}]>
# # 4.查询a社出版的书籍名称和价格
# res = models.Publisher.objects.filter(name='a社').values('book__title','book__price')
# print(res) # <QuerySet [{'book__title': '语文', 'book__price': Decimal('29.90')}, {'book__title': '数学', 'book__price': Decimal('29.90')}, {'book__title': '生物', 'book__price': Decimal('29.90')}, {'book__title': '物理', 'book__price': Decimal('29.90')}]>
# # 5.查询oscar编写的书籍名称和日期
# res = models.Author.objects.filter(name='oscar').values('book__title','book__date')
# print(res) # <QuerySet [{'book__title': '数学', 'book__date': datetime.date(2022, 5, 4)}, {'book__title': '地理', 'book__date': datetime.date(2021, 12, 27)}]>
# # 6.查询电话是110的作者的姓名和年龄
# res = models.AuthorDetails.objects.filter(phone=110).values('author__name','author__age')
# print(res) # <QuerySet [{'author__name': 'petter', 'author__age': 18}]>
双下划线查询扩展
"""基于双下划线的跨表查询的结果也可以是完整的数据对象"""
'''手上有条件所在的表可以不被models点 直接点最终的目标数据对应的表'''
eg:
给定表A字段值,查表B
models.B.objects.fliter(A__字段名=字段值)
# # 1.查询语文书籍对应的出版社名称
# res = models.Publisher.objects.filter(book__title='语文')
# print(res) # <QuerySet [<Publisher: 出版社对象:a社>]>
# # 2.查询数学对应的作者姓名和年龄
# res = models.Author.objects.filter(book__title='数学').values('name','age')
# print(res) # <QuerySet [{'name': 'oscar', 'age': 20}]>
# # 3.查询作者oscar的手机号和地址
# res = models.AuthorDetails.objects.filter(author__name='oscar').values('phone','addr')
# print(res) #<QuerySet [{'phone': 120, 'addr': '上海'}]>
# # 4.查询a社出版的书籍名称和价格
# res = models.Book.objects.filter(publisher__name='a社').values('title','price')
# print(res) # <QuerySet [{'title': '语文', 'price': Decimal('29.90')}, {'title': '数学', 'price': Decimal('29.90')}, {'title': '生物', 'price': Decimal('29.90')}, {'title': '物理', 'price': Decimal('29.90')}]>
# # 5.查询oscar编写的书籍名称和日期
# res = models.Book.objects.filter(authors__name='oscar').values('title','date')
# print(res) # <QuerySet [{'title': '数学', 'date': datetime.date(2022, 5, 4)}, {'title': '地理', 'date': datetime.date(2021, 12, 27)}]>
# # 6.查询电话是110的作者的姓名和年龄
# res = models.Author.objects.filter(author_details__phone=110).values('name','age')
# print(res) # <QuerySet [{'name': 'petter', 'age': 18}]>
# 连续跨表操作
写条件的时候,根据表间练习,每多一张表就多一个__
# # 查询数学对应的作者的手机号
# res = models.AuthorDetails.objects.filter(author__book__title='数学').values('phone')
# print(res) # <QuerySet [{'phone': 120}]>
"""
可能出现的不是疑问的疑问:如何获取多张表里面的字段数据
res = models.Book.objects.filter(title='python全栈开发').values('authors__author_detail__phone','authors__name','title')
print(res)
"""
如何查看SQL语句
方式1:如果结果集对象是queryset 那么可以直接点query查看
方式2:配置文件固定配置
适用面更广 只要执行了orm操作 都会打印内部SQL语句
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}