查询
查询
E:\pythonDemo\django项目\query
单表操作
# django 自带的sqlite3对日期格式不敏感,容易出错
测试脚本
"""
当你只是想测试django中的某一个py文件内容那么你可以不用书写前后端交互的形式,我们可以写一个测试脚本
"""
脚本代码无论是写在应用下的test.py还是单独开设py文件都可以
# 测试环境的准备
from django.test import TestCase
# Create your tests here.
import os
import sys
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'query.settings')
import django
django.setup()
from app01 import models
"""
测试代码
"""
"""
去manage.py文件中拿前四行代码,在test文件中写上面代码
"""
查看内部sql语句的方式
queryset对象之间点query
所有的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',
},
}
}
十三个方法
# 必知必会13条
"""
1.all()
查询所有数据
2.filter()
带有过滤条件的查询
3.get()
直接拿数据对象,但是不存在报错
4.first()
拿queryset里面第一个元素
5.last()
拿queryset里面最后一个元素
6.values()
res = models.User.objects.values('name', 'age')
<QuerySet [{'name': 'egon', 'age': 14}, {'name': 'egonDBJ', 'age': 14}]>
可以指定获取的数据字段 select name, age from ...
返回结果是一个列表套字典
7.values_list()
rea = models.User.objects.values_list('name', 'age')
<QuerySet [('egon', 14), ('egonDBJ', 14)]>
拿到的是列表套元组, 元组里面是指定的字段数据
8.distinct()
去重
res = models.User.objects.values('name', 'age').distinct()
去重一定要是一模一样的数据
如果带有主键那么肯定不一样
9.order_by()
res = models.User.objects.order_by('age')
默认是升序,,条件取反就是降序
10.reverse()
反转的前提是数据已经排过序了
res = models.User.objects.order_by('age').reverse()
11.count()
统计当前数据的个数
res = models.User.objects.count()
12.exclude()
排除条件在外
res = models.User.objects.exclude(name='tank')
13.exists()
判断是否存在
res = models.User.objects.filter(pk=2).exists()
"""
双下划线查询
# 需求: 查询年龄是15或者14或24
# res = models.User.objects.filter(age__in=[15,14,24])
# print(res)
# 需求: 年龄在18到40岁之间的 顾头也顾尾
# res = models.User.objects.filter(age__range=[18, 40])
# print(res)
# 需求: 查询名字里面有e的,, 默认区分大小写
# res = models.User.objects.filter(name__contains='e')
# print(res)
# 忽略大小写
# res = models.User.objects.filter(name__icontains='e')
# print(res)
# 判断以什么开头
# res = models.User.objects.filter(name__startswith='eg')
# print(res)
# 需求: 查询出注册时间是2020-1月分
# res = models.User.objects.filter(register_time__month='1')
# res = models.User.objects.filter(register_time__year='2021')
多表操作
针对一对多的外键的增删改查
# 增
# 第一种方式,,直接写实际字段 id
# models.book.objects.create(title='三国演义', price=123.23, publish_id=1)
# 第二种 虚拟字段 放对象
# publish_obj = models.Publish.objects.filter(pk=2).first()
# models.book.objects.create(title='红楼梦', price=223.23, publish=publish_obj)
# 删
# models.Publish.objects.filter(pk=1).delete() # 级联删除
# 修改
# 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)
针对多对多的外键的增删改查
# 给书籍绑定作者
book_obj = models.book.objects.filter(pk=1).first()
# print(book_obj.authors) # 就类似于你已经到了第三张关系表了
# book_obj.authors.add(1) # 给书籍id为1的书籍绑定一个主键为1的作者
# book_obj.authors.add(2,3) # 给书籍id为1的书籍绑定一个主键为2,3的作者
# author_obj1 = models.Author.objects.filter(pk=1).first()
# author_obj2 = models.Author.objects.filter(pk=2).first()
# author_obj3 = models.Author.objects.filter(pk=3).first()
# book_obj.authors.add(author_obj1)
# book_obj.authors.add(author_obj3, author_obj2)
"""
add
给第三张关系表添加数据,括号内既可以传数字也可以传对象,并且都支持多个
"""
# 删
# book_obj.authors.remove(2,3)
# author_obj1 = models.Author.objects.filter(pk=1).first()
# book_obj.authors.remove(author_obj1)
"""
remove
给第三张关系表删除数据,括号内既可以传数字也可以传对象,并且都支持多个
"""
# 改 set
# book_obj.authors.set([1,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])
"""
括号内既可以传数字也可以传对象,但是括号内必须是一个可迭代对象
先删除,在新增
"""
# 清空
# 第三张关系表中清空某个书籍与作者的绑定关系
book_obj.authors.clear()
正反向的概念
# 正向:
看外键字段在我手上,我查你就是正向
外键字段不在我手上,我查你就是反向
eg:
由书去查出版社,因为书和出版社是一对多的关系
外键字段在书这里,所以让书去查出版社就是正向,反之出版社查书就是反向
一对一和一对多正反向的判断也是如此
"""
正向查询按字段
反向查询按表名小写
"""
多表查询
子查询(基于对象的跨表的查询)
# 基于对象的跨表查询
# 1. 查询书籍主键为1的出版社
# book_obj = models.book.objects.filter(pk=1).first()
# # 书籍查询出版社 正向
# res = book_obj.publish
# print(res)
# print(res.name)
# print(res.addr)
# 2. 查询书籍主键为1的作者
# book_obj = models.book.objects.filter(pk=2).first()
# # 书查作者 正向
# # res = book_obj.authors
# app01.Author.None
# res = book_obj.authors.all()
#<QuerySet [<Author: Author object (1)>, <Author: Author object (2)>]>
# print(res)
# print(res[0].name)
# 3. 查询作者jason的电话号码
# author_obj = models.Author.objects.filter(name='jason').first() # res = author_obj.author_detail
# print(res)
# print(res.phone)
""" 在书写orm语句的时候,跟写sql语句是一样的 什么时候需要.all() 当你的结果可能有多个的时候就需要加.all() 如果是一个直接拿对象 """
# 反向
# 4 查询出版社是东方出版社出版的书
# publish_obj = models.Publish.objects.filter(name='东方出版社').first()
# # 出版社查书,,反向
# res = publish_obj.book_set.all() # print(res)
# 4. 查询作者是jason写过的书
# author_obj = models.Author.objects.filter(name='jason').first() # # 作者查书, 反向
# res = author_obj.book_set.all()
# print(res)
# 6 查询手机号是110的作者姓名
# author_detail_obj = models.AuthorDetail.objects.filter(phone=110).first()
# res = author_detail_obj.author
# print(res)
# print(res.name)
""" 当你的查询结果可以有多个的时候,就必须加_set.all() 当你的结果只有一个的时候不需要加_set.all() """
联表查询(基于双下划线的跨表查询)
# 基于双下划线的跨表查询
# 1. 查询Jason的手机号 正向
# res = models.Author.objects.filter(name='jason').values('author_detail__phone') # print(res[0].get('author_detail__phone'))
# 反向
# res = models.AuthorDetail.objects.filter(author__name='jason')
# 那作者姓名是jason的作者详情
# res = models.AuthorDetail.objects.filter(author__name='jason').values('phone', 'author__name')
# print(res)
# 2. 查询书籍主键为1的出版社名称和书的名字
# res = models.book.objects.filter(pk=1).values('publish__name', 'title')
# print(res)
# 反向
# res = models.Publish.objects.filter(book__id=1).values('name', 'book__title')
# print(res)
# 3. 查询书籍主键为1的作者姓名
# res = models.book.objects.filter(pk=1).values('authors__name') # print(res)
# 反向
# res = models.Author.objects.filter(book__id=1).values('name')
# print(res)
# 查询书籍主键是1的作者的手机号 res = models.book.objects.filter(pk=1).values('authors__author_detail__phone') print(res) """ """
聚合查询
# 聚合查询
""" aggregate 想使用聚合函数,但是不想用分组group by 只要是跟数据库相关的模块基本上都在django.db.models 如果这个里面没有,那么应该在django.db里面 """
from django.db.models import Max, Min, Sum, Count, Avg
# 1. 统计书的平均价格
# res = models.book.objects.aggregate(Avg('price'))
# print(res)
# 上述方法一次性使用
# res = models.book.objects.aggregate(Max('price'), Min('price'), Sum('price'), Count('pk'))
# print(res)
分组查询
# 分组查询 annotate
""" 分组之后只能默认获取到分组的依据 组内其他字段无法获取 """
# 1. 统计每一本书的作者个数
# res = models.book.objects.annotate()
# models后面点什么就是按照什么分组
# res = models.book.objects.annotate(author_num=Count('authors')).values('title','author_num')
# print(res)
# 2. 统计每个出版社卖的最便宜的书的价格
# res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name', 'min_price')
# print(res)
# 3. 统计不止一个作者的图书
# res = models.book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('title', 'author_num')
# print(res)
# 4. 查询每个作者出的书的总价格
# res=models.Author.objects.annotate(sum_price=Sum('book__price')).values('name', 'sum_price')
# print(res)
""" 如果想按照指定的字段分组 models.book.objects.values('price').annotate()
"""
F查询
"""
# F 与 Q 查询
# 1. 查询卖出数大于库存数的书籍
# F 查询
from django.db.models import F
# res = models.Book.objects.filter(maichu__gt=F('kucun')) # print(res) """
F
能够帮助你直接获取到表中某个字段对应的数据 """
# 2 将所有书籍的价格提升50
# models.Book.objects.update(price=F('price') + 500)
# 3. 将所有书的名称后面加上爆款两个字
from django.db.models.functions import Concat
from django.db.models import Value
# models.Book.objects.update(title=Concat(F('title'), Value('爆款')))
Q 查询
# Q 查询
# 1. 查询卖出数大于100或者价格小于600的书籍
from django.db.models import Q
# res=models.Book.objects.filter(Q(maichu__gt=100)|Q(price__lt=600)) # Q包裹起来之后还是and关系,不过可以连接连接符
# res = models.Book.objects.filter(~Q(maichu__gt=100), ~Q(price__lt=600))
# Q包裹起来之后还是and关系,不过可以连接连接符
"""filter 括号内的多个参数是and关系"""
# print(res)
""" ~取反 |或者 """
# Q 的高阶用法 能够将查询条件的左边也变成字符串的形式
q = Q()
q.connector = 'or'q.children.append(('maichu__gt', 100)) q.children.append(('price__lt', 100))
res = models.Book.objects.filter(q)
# 默认还是and关系 print(res)
开启事务
"""事务: ACID A: 原子性 不可分割的最小单位 C: 一致性 跟原子性是相辅相成的 I: 隔离性 事务之间互相不干扰 D: 持久性 事务一旦提交,永久生效事物的回滚: rollback事务的确认: commit"""
# 事务
from django.db import transaction
try:
with transaction.atomic():
# sql 语句
# 在with代码块内书写的所有orm操作都是属于同义事务
pass
except Exception as e:
print(e)
orm中常用字段及参数
AutoField 主键字段 primary key = TrueCharField <===> varchar vervose_name 字段的注释 max_length 长度IntegerField <===> intDecimalField max_digits=8, decimal_places=2EmailField <===>varchar(254)DateField <===> dateDateTimeField < ===> datetime auto_now: 每次修改数据的时候都会自动更新当前时间 auto_now_add: 只在创建数据的时候记录创建时间 , 后续不会自动修改 BooleanField(Field) 布尔值 该字段传布尔值, 数据库里面存0或1 TextField 文本类型 该字段可以用来存大段内容文本,比如你的文章, 博客FileField 文件 upload_to ='/data' 直接给该字段传一个文件对象,会自动将文件保存到/data目录下,然后将文件保存到数据库中 # 自定义字段class MyCharField(models.Field): def __init__(self, max_length, *args, **kwargs): self.max_length = max_length # 调用父类的init方法 super().__init__(max_length=max_length, *args, **kwargs) # 这里的max_length一定要是关键字的传入 def db_type(self, connection): """ 返回真正的数据类型,及各种约束条件 :param connection: :return: """ return 'char(%s)' % self.max_length # 外键字段
数据库查询优化
only与defer
"""orm语句的特点: 惰性查询 如果你仅仅只是书写了orm语句,后面没有用到orm查询到的参数,orm语句不执行
# 想要获取书籍表中所有书的名字
# res = models.Book.objects.values('title')
# for d in res: #
print(d.get('title'))
# 实现获取到一个数据对象,然后直接点title可以拿到,并且没有其他字段
# res = models.Book.objects.only('title')
# print(res)
# for i in res:
# print(i.title)
# 点击only括号内的字段不走数据库
# print(i.price)
# 点其他的字段重新数据库 而all不需要,all是拿到所有属性
res = models.Book.objects.defer('title')
# 对象处理title没有之外,其他都有 for i in res:
print(i.price) """
defer和only刚好相反
defer括号内放的字段不在查询出来的对象里面,查询该字段需要重新走数据库 """"""select_related与prefetch_related"""
# select_related与prefetch_related 跟跨表操作有关
# res = models.Book.objects.all()
# for i in res:
# print(i.publish.name)
# 没循环一次就要走一次数据库查询 #
res = models.Book.objects.select_related('publish')
# 连表操作 # for i in res:
# print(i.publish.name) """ select_related:
内部直接先将book表和publish表连接起来一次性将大表里面的所有数据全部分装给查询出来的对象 这个时候对象无论是点book表的数据还是点publish表的数据,都无需再走数据库 select_related() 括号内只能放外键字段 一对一 一对多 多对多不能放 """ res = models.Book.objects.prefetch_related('publish') # 子查询
""" prefetch_related: 该方法内部就是子查询 将子查询查询出来的所有结果也给你封装到对象中 """ for i in res: print(i.publish.name)"""
浙公网安备 33010602011771号