多表外键字段增删改查、正反向查询技巧、基于对象的跨表查询、基于双下划线的跨表查询、F与Q查询
昨日内容回顾
- 模板标签
{{ 使用变量的时候 }}
{% 跟逻辑相关的时候 %}
# 模板标签也会自动补全
- 模板继承
# 使用场景:在混合开发的项目中
{% extends 'home.html' %} # 导入指定文件内全部代码内容
{% block content %}
{% endblock %}
{% block css %}
{% endblock %}
{% block js %}
{% endblock %}
# 模板导入
'''被导入的页面一般是一个局部页面''''
{% include 'menu.html' %}
- 测试环境的准备
直接cv manage.py中的前4行,放到tests.py中,在加两句话:
import django
django.setup()
# 测试环境的代码不一定非要放在tests.py中, 放在任意目录下即可
- ORM的常用查询方法
1. all
2. first()
3. last()
4. filter => where
5. get
6. values # 返回的结果是列表套字典
7. values_list # 列表套元组
8. order_by() # 默认是升序,字段前面加负号-就是降序,也支持多个字段排序
9. distinct # 不能加主键,有unique的也没有意义
10. exclude
11. exists
12. reverse
# 补充索引的分类:
1. 索引加快查询速度
2. 分类:
2.1 主键索引
2.2 唯一索引
2.3 普通索引 create index()
2.4 联合索引,组合索引
a b c # index(a, b, c)
走索引的情况(最左匹配原则):a, ab, abc
不走的情况:b, c bc, ac
eg:
where b=1 and c=2
# explain select *from t1
- 基于双下划线的查询
1. gt gte
2. lt lte
3. range => between and
4. in
5. containers
6. startwith
7. endswith
8. __year
9. __month
今日内容概要
- 外键字段的增删改查
- 正反向查询的概念
- 基于对象的跨表查询(子查询)
- 基于双下划綫的跨表查询(连表操作)
- F与Q查询
- 聚合查询和分组查询
内容详细
1. 数据表准备
# 前期数据表准备
# 以图书 出版社 作者 作者详情表为例
# 1.在models.py文件中创建表:
# 书籍表
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8,decimal_places=2)
'''
auto_now=False,
如果设置为True, 在更新当前记录的数据时候,会自动更新时间
auto_now_add=False,
如果设置为True,当插入数据的时候,会把当前时间自动添加进去
'''
# publish_time = models.DateField
publish_time = models.DateTimeField(auto_now=True)
publish = models.ForeignKey(to='Publish')
authors = models.ManyToManyField(to='Author')
# 查询时返回表头
def __str__(self):
return self.title
# 出版社表
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=64)
# 作者表
class Author(models.Model):
name = models.CharField(max_length=32)
author_detail = models.OneToOneField(to='AuthorDetail')
# 查询时返回名称
def __str__(self):
return self.name
# 作者详情表
class AuthorDetail(models.Model):
phone = models.CharField(max_length=32)
# 2.在任一init.py文件中写入:
import pymysql
pymysql.install_as_MySQLdb()
# 3.在settings.py文件中 更改配置连接数据库:
DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
# },
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'day07', # 数据库名 自己先用 navicat创建
'HOST': '127.0.0.1',
'PORT': 3306,
'USER': 'root',
'PASSWORD': '123',
'CHARSET': 'utf8'
}
}
# 4.在test.py文件中创建测试环境:
import os
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite6.settings")
import django
django.setup()
from app01 import models
# 代码写在此处下面
2. 外键字段的增删改查
# 先自定义出版社 再添加图书
# 在 test.py文件中测试:
import os
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite6.settings")
import django
django.setup()
from app01 import models
# 代码写在此处下面
# 针对一对多 一对一
# 1.增加数据 增加一本书
# 方式一
# models.Book.objects.create(title='西游记', price=100, publish_time='2022.3.3', publish_id=1)
# 方式二
# 先查询出你要添加的出版社对象
# publish_obj = models.Publish.objects.filter(pk=2).first()
# models.Book.objects.create(title='西游记1', price=111, publish_time='2022-02-01', publish=publish_obj)
# 2.改
# 将主键id为1的出版社id改为2
# models.Book.objects.filter(pk=1).update(publish_id=2)
# 改回去
# publish_obj = models.Publish.objects.filter(pk=1).first()
# models.Book.objects.filter(pk=1).update(publish=publish_obj)
# 针对多对多字段操作
# 1.增
# 给一本书添加多个作者
# book_obj = models.Book.objects.filter(pk=1).first()
# 增加
# book_obj.authors # 代表已经到第三张表了
# book_obj.authors.add(1)
# book_obj.authors.add(1, 2)
# 支持对象
# author_obj1 = models.Author.objects.filter(pk=1).first()
# author_obj2 = models.Author.objects.filter(pk=2).first()
# book_obj.authors.add(author_obj1, author_obj2)
# 2.改
# book_obj.authors.set([3, 2])
# author_obj1 = models.Author.objects.filter(pk=1).first()
# author_obj2 = models.Author.objects.filter(pk=2).first()
# book_obj.authors.set([author_obj1, author_obj2])
# 3.删除
# book_obj = models.Book.objects.filter(pk=2).first()
# book_obj.authors.remove(1)
# book_obj.authors.remove(1,2)
# author_obj = models.Author.objects.filter(pk=1).first()
# author_obj1 = models.Author.objects.filter(pk=2).first()
# book_obj.authors.remove(author_obj)
# book_obj.authors.remove(author_obj, author_obj1)
"""
remove
在第三张关系表中删除数据
括号内既可以传主键字段也可以传数据对象 并且都支持传多个
"""
# 清空
# book_obj = models.Book.objects.filter(pk=2).first()
# book_obj.authors.clear() # 清空当前书籍与作者的所有绑定关系
"""
clear
在第三张关系表中清空数据
括号内无需传值
"""
3. 正反向查询
# 正向查询
书籍对象查出版社对象 外键字段在书表中 # 正向查询
书籍对象查作者对象 外键字段在书表中 # 正向查询
作者对象查作者详情 外键字段在作者中 # 正向查询
# 反向查询
出版社查书籍对象 外键字段不在出版社表中 # 反向查询
作者查书籍对象 外键字段不在作者表中 # 反向查询
作者详情查作者 外键字段不在作者详情表中 # 反向查询
'''
外键字段在我手上,我查你就是正向
外键字段不再我手上,我查你就是反向
'''
# 口诀:
正向查询按外键字段 ...
反向查询按表名小写 或 +_set ...
4. 基于对象的跨表查询(子查询)
"""将一条SQL语句的查询结果当做另外一条SQL语句的查询条件"""
'''基于对象的跨表查询'''
# 在 test.py文件中测试:
# 1.查询书籍主键为1的出版社
# 书 >>> 出版社 >>> 正向
# book_obj = models.Book.objects.filter(pk=1).first()
# print(book_obj) # 西游记
# print(book_obj.publish) # Publish object 代表的是出版社对象
# print(book_obj.publish.name) # 北京大学出版社
# print(book_obj.publish.addr) # 北京
# 2.查询书籍主键位1的作者
# book >>> author >>> 正向
# book_obj = models.Book.objects.filter(pk=1).first()
# print(book_obj.authors) # app01.Author.None
# print(book_obj.authors.all()) # <QuerySet [<Author: beijing>, <Author: qinghua>]>
# for author_obj in book_obj.authors.all():
# print(author_obj.name) # beijing qinghua
# 3.查询 qinghua 的手机号
# 作者 >>> 作者详情 >>> 正向
# author_obj = models.Author.objects.filter(name='qinghua').first()
# print(author_obj.author_detail) # AuthorDetail object 结果时对象
# print(author_obj.author_detail.phone) # 120
# 4.查询武汉出版社出版的书籍
# 出版社查书 >>> 反向
# publish_obj = models.Publish.objects.filter(name='武汉大学出版社').first()
# print(publish_obj.book_set) # app01.Book.None
# print(publish_obj.book_set.all()) # <QuerySet [<Book: 红楼梦>]>
# for book_obj in publish_obj.book_set.all():
# print(book_obj.title) # 红楼梦
# 5.查询 qinghua 写过的书
# 作者查书 >>> 反向
# author_obj = models.Author.objects.filter(name='qinghua').first()
# print(author_obj.book_set.all()) # <QuerySet [<Book: 西游记1>]>
# 6.查询手机号是120的作者姓名
# 作者详情查作者信息 >>> 反向
# author_detail_obj = models.AuthorDetail.objects.filter(phone=120).first()
# print(author_detail_obj.author) # qinghua
'''
总结:
反向查询只要查询出的结果可能有多个的时候,都要加上 表名_set.all()
如果查询出来的结果是一个,就不用加_set,直接使用表名小写
'''
5. 基于双下划线的跨表查询
"""正反向查询的概念同样适用"""
# 在 test.py文件中测试:
# 1.查询书籍主键为1的出版社名称与书籍名称
# 正向
# res = models.Book.objects.filter(pk=1).values('title', 'publish__name')
# print(res) # <QuerySet [{'title': '西游记', 'publish__name': '北京大学出版社'}]>
# 2.查询书籍主键位1的作者
# 正向
# res = models.Book.objects.filter(pk=1).values('authors__name')
# print(res) # <QuerySet [{'authors__name': 'beijing'}]>
# 3.查询作者 qinghua 的手机号
# 正向
# res = models.Author.objects.filter(name='qinghua').values('author_detail__phone')
# print(res) # <QuerySet [{'author_detail__phone': '120'}]>
# 4.查询 武汉大学出版社 出版的书籍名称
# 反向
# res = models.Publish.objects.filter(name='武汉大学出版社').values('book__title')
# print(res) # <QuerySet [{'book__title': '红楼梦'}]>
# 5.查询 qinghua 写过的书
# 反向
# res = models.Author.objects.filter(name='qinghua').values('book__title')
# print(res) # <QuerySet [{'book__title': '西游记1'}]>
# 6.查询手机号是120的作者姓名
# 反向
# res = models.AuthorDetail.objects.filter(phone=120).values('author__name')
# print(res) # <QuerySet [{'author__name': 'qinghua'}]>
# 7.查询书籍主键位1的作者的手机号
# 正向
# book author author_detail
# res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone')
# print(res) # <QuerySet [{'authors__author_detail__phone': '110'}]>
6. F查询和Q查询
# F查询
可以拿到数据库中原有的数据
from django.db.models import F
''' F查询默认是对数字类型的'''
# 1.把书籍的价格在原来的基础之上加100元
# SQL语句:
# update book set price = price + 100 where id=1;
'''
一般来说,跟数据相关的模块要么在django.db,要么在django.db.models
'''
# models.Book.objects.update(price=F('price')+100)
# 2.F查询对 字符类型的
from django.db.models.functions import Concat
from django.db.models import Value
# models.Book.objects.update(title=Concat(F('title'), Value('南京出版社')))
# Q查询
# 查询书籍价格大于等于300的或者id=1的数据
# sql: select * from t where price >= 300 or id=1
# orm:
from django.db.models import Q
# res = models.Book.objects.filter(Q(price__gte=300), Q(id=1)) # 逗号分隔,是and关系
# res = models.Book.objects.filter(Q(price__gte=300) | Q(id=1)) # |分隔,是or关系
# res = models.Book.objects.filter(~Q(price__gte=300) | ~Q(id=1)) # ~分隔,取反
# print(res)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用