Django Queryset用法
文章目录
- filter/get
- get/update_or_create
- update
- django查询之Q对象、F对象、聚合查询、分组查询
- QuerySet
- 并不是执行Objects.all(),或者filter之后就会与数据库交互
- 优化: **减少查询次数**:
- MTM: `add() / remove() / update() / delete() / clear()` 方法
- 性能分析
- 参考文献:
|- apps
|-----Blog
|---------models.py: author, blog, category
filter/get
get()
不到会抛异常,但get到多条也会报错!!!
author = Author.objects.filter(name="GG", status=0).first()
if not author:continue# get()不到会抛异常,但get到多条也会报错;可用filter().first()代替
try:author = Author.objects.get(name="GG", status=0)
except Exception:return
get/update_or_create
get_or_create()
在查询时使用defaults以外的参数进行查询;当实例不存在时,将包含default参数一起创建一个新实例。update_or_create()
数据存在则更新,当实例不存在时,将包含default参数一起创建一个新实例。
au, created = Author.objects.get_or_create(id=6, defaults={'name': "GG"}) # 返回(obj, created),obj是查询或创建的对象实例,created是个布尔值,表示是否是新创建的实例。 BlogAuthoItem.objects.get_or_create(author=au, blog=blog, defaults=info) # django中的字段名
au, created = Author.objects.update_or_create(id=6, defaults=defaults) # 数据存在则更新,不存在则保存
get_or_create() 如果查找到的对象超过一个以上,将引发MultipleObjectsReturned。
update
- update()会立即执行,不用再执行save()。但用=赋值操作要.save()。
- 不会产生
pre_save或post_save信号
(调用save()方法产生)或服从auto_now字段选项, 因此update_time要手动更新!!!
- 不会产生
- update更加适用于批量数据更新,而save则只适合做单条数据更新操作,效率比update低。
Blog.objects.all()[:10] # 切片操作,获取10个人,不支持负索引,切片可节约内存
v1 = Business.objects.all() # object <QuerySet [<Business: Business object>,...]
v2 = Business.objects.all().values('id','caption') # list <QuerySet [{'caption': '运维部', 'id': 1}, {'caption': '开发', 'id': 2}, {'caption': '市场', 'id': 3}, {'caption': '测试', 'id': 4}]>
v3 = Business.objects.all().values_list('id','caption') # tuple <QuerySet [(1, '运维部'), (2, '开发'), (3, '市场'), (4, '测试')]># 批量更新update:适用于 .all() .filter() .exclude()等后面. 危险??
Blog.objects.filter(name__contains="abc").update(name='xxx', publish_time=datetime.now())
Author.objects.filter(id=1).update(**defaults) # defaults是个dict
Blog.objects.all().delete() # 单条更新save():适合于.get() .get_or_create() .update_or_create() 等得到的obj. 修改字段后不要忘记 .save()!!!!!!
au.save()
django查询之Q对象、F对象、聚合查询、分组查询
from django.db.models import Q, F, Avg
from datetime import timedelta, datetime
from django.db.models import Avg, Max, Min, Count
from django.db.models.functions import TruncDate, TruncDay, TruncHour, TruncMinute, TruncSecond# F() 比较同一个model实例中两个不同字段的值。
Blog.objects.filter(like_num__lt=F('hate_num')
q = Q(update_time__gt=F("publish_time") - timedelta(days=1)) # 时间增量
q &= Q(create_time__gt=datetime.now() - timedelta(days=3))# Q对象:支持 & | ~ 组合。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。
blogs = Blog.objects.filter(Q(authors__name="yuan")| Q(authors__name="egon"))# 聚合查询: aggregate()是QuerySet的一个终止子句,它返回一个包含一些键值对的字典
Blog.objects.all().aggregate(Avg("price"),Max("price")) # 计算价格的均值、最大值,返回 {'price__avg': 192.593333, 'price__max': Decimal('233.33')} # 分组查询:annotate为调用的QuerySet中每一个对象都生成一个独立的统计值authorNum,适合多对多关系查询
blogs = Blog.objects.all().annotate(authorNum=Count("authors")).order_by('authorNum')Blog.objects.annotate( hour=TruncHour('start_datetime', output_field=TimeField())).values('hour').annotate(experiments=Count('id'))# Q对象 和 filter比较:
Blog.objects.filter(Q(category__id=category.id))
Blog.objects.filter(category=category)
Blog.objects.filter(lcategory__id=category.id)
QuerySet
- 支持链式查询:
Blog.objects.filter(category=2).exclude(private=True)
- 查询结果排序:
Author.objects.all().order_by('name')
- 不支持负索引:
Blog.objects.all().reverse()[:2] # 最后两条
Blog.objects.order_by('-id')[:20] # id最大的20条
- 去重:
qs = qs.distinct() # distinct('author')
blogs = Blog.objects.values('number') # [{'number': u'1'}, {'number': u'2'}, {'number': u'3'}]
blogs = Blog.objects.values_list('number') # [(u'1',), (u'2',), (u'3',)]
blogs = Blog.objects.values_list('number', flat=True) .distinct() # [u'1', u'2', u'3'] queryset.extra(select={'length': 'Length(title)'}).order_by('length')
并不是执行Objects.all(),或者filter之后就会与数据库交互
- queryset总是惰性的
一个创建QuerySets的动作不会立刻导致任何的数据库行为。你可以不断进行filter动作一整天,Django不会运行任何实际的数据库查询动作,直到QuerySets被提交(evaluated)。# 返回QuerySet对象,程序并没有真的在数据库中执行SQL语句查询数据,但支持迭代,可用for循环可获取数据 blogs = Blog.objects.all() blogs = Blog.objects.filter(name__icontains="Django")# 返回Model对象,说明用get方法会直接执行sql语句获取数据 blog = Blogs.objects.get(id='1')
- queryset具有cache的,可减少数据库查询
- for语句遍历queryset时,所有匹配的记录会从数据库获取,然后转换成Django的model,这被称为执行(evaluation)。
- 这些model会保存在queryset内置的
cache
中,若再次遍历这个queryset,不需要重复运行通用的查询。即代码只会执行一次数据库查询。 if queryset
触发执行: 用if语句判断会完全执行整个queryset并把数据放入cache,虽然你并不需要这些数据!!
- 避免cache问题
- 为避免if,可用
queryset.exists()
来检查是否有数据,从而节省带宽和内存. - 避免遍历数据时产生cache,可用
.iterator()
来获取数据防止生成cache,处理完数据就将其丢弃。 但多次遍历时会重复执行查询!!! exists() + iterator()
: 用两次数据库查询来避免使用查询集缓存。
- 为避免if,可用
len()方法相当于会把整个queryset遍历一次,把所有的数据都取出来对象化,消耗大量资源
- 数据是否存在:.exists() > count() > len()
- 数据数量:count() > len()
- 批量操作QuerySet.update()/delete()`: 不会执行自定义行为。
- 无需获取不使用字段
- 通过 values() 和values_list()
可以提高查询速度
-defer()
排除字段和only()
指定字段
- 请注意,如果确实使用它们,ORM将不得不在一个单独的查询中获取它们,如果您不恰当地使用它们,那么这将是一个悲观化。
优化: 减少查询次数:
Book.objects.raw('select * from Book') # 用RawSQL
book = Book.objects.get(id=27) # 主键索引更快
book = Book.objects.get(name__startswith='将') # 字段模糊查询会更慢
select_related
用inner join
、主要针查询外键(ForeignKey)或一对一(OneToOneField)关系进行优化。通过减少SQL查询的次数来进行优化、提高性能。prefetch_related
执行一个单独的查找,它允许预先读取多对多和多对一的对象数据,这是 select_related 做不到的。另外 perfetch_related 也可以与通用外键和关系一起使用。
blog = Blog.objects.get(id=124) # 访问一次数据库
author = blog.author # 再次访问数据库blog = Blog.objects.select_related('author').get(id=124) # 访问数据库
author = blog.author # 不会再次访问数据库,在之前的查询中已经取到了对应的数据
单纯只要外键值:
blog = Blog.objects.get(id=2)
author_id = blog.author.id # Bad query, additional db lookup in author tableblog = Blog.objects.select_related('author').get(id=2)
author_id = blog.author.id # A better version of above query but still a bad queryblog = Blog.objects.get(id=2)
author_id = blog.author_id # Good Query 最佳实践
MTM: add() / remove() / update() / delete() / clear()
方法
1、为对象添加多对多关系前,需要保持对象,即写入数据库产生id列,然后才能利用id列建立多对多关系表。
2、可以用create()函数,连建立to_*_id代表的目标对象,带add()新建对象到多对多关系表一起,一步完成两个操作。
3、.distinct().count()
组合使用
au.blogs.all().delete() # 需指出类似all()的查询集。
au.blogs.clear().add(obj1[, obj2, ...]) # 不需要再调用save(), 多次添加同一个关系不会重复。但参数类型不能错,否则引发TypeError.remove(obj1[, obj2, ...]) # 解绑指定关系。 只删除关系,保留源侧和目标侧对象。
.set(queryset) # 批量设多个关系.clear() # 不会删除对象,只会清除他们之间的关系
.delete() # 删除单个或批量删除对象。 级联删除,相关联的一对多,多对多关系都会删除。 【任何有外键指向要删除对象的对象将一起被删除】# 该方法将返回被删除对象的总数量和一个字典,字典包含每种被删除对象的类型和该类型的数量。
Article.objects.filter(publications__title__startswith="Science")
Article.objects.filter(publications__id=1)
Article.objects.filter(publications__pk=1)
Article.objects.filter(publications=1) # (publications__in=[1,2])
Article.objects.filter(publications=p1) # (publications__in=[p1,p2])
性能分析
方法一: code
from django.db import connection
dbsql = connection.queries # 具体sql执行情况和耗时情况
方法二: pip install django-extensions
- INSTALLED_APPS = (...'django_extensions',...)
- python manage.py shell_plus --print-sql # 查看执行sql和结果
参考文献:
Django ORM数据查询操作优化
Django Queryset用法相关推荐
- Django QuerySet 就学那么一点点,一点点就够了
橡皮擦,一个逗趣的互联网高级网虫.新的系列,让我们一起进入 Django 世界. 已经完成的文章 滚雪球学 Python 第三轮,Python Web 之 Django 的世界 小手哆嗦一下,就能用 ...
- Django QuerySet API 文档阅读(3):QuerySet定义(一)
原文地址:QuerySet API reference | Django documentation | Django QuerySet有两个属性,ordered和db: ordered: ...
- Django学习笔记之Django QuerySet的方法
一般情况下,我们在写Django项目需要操作QuerySet时一些常用的方法已经满足我们日常大多数需求,比如get.filter.exclude.delete神马的感觉就已经无所不能了,但随着项目但业 ...
- Django QuerySet API文档
在查询时发生了什么(When QuerySets are evaluated) QuerySet 可以被构造,过滤,切片,做为参数传递,这些行为都不会对数据库进行操作.只要你查询的时候才真正的操作数据 ...
- 合并多个python list以及合并多个 django QuerySet 的方法
尊重原文作者,该文转载于: http://www.yihaomen.com/article/python/533.htm 在用python或者django写一些小工具应用的时候,有可能会遇到合并多个l ...
- Django模板用法
django模板原理 # 创建template对象,由context对象传递template所需要的值, 有render方法进行模板的呈现 # 写模板,创建 Template 对象,创建 Contex ...
- Django update用法
model update常规用法 假如我们的表结构是这样的 class User(models.Model):username = models.CharField(max_length=255, u ...
- django QuerySet
Django对数据库的封装1--QuerySet 发布时间:2018-02-28 来源:网络 上传者:用户 关键字: manager 数据库 记录 影响 发表文章 摘要: Django对数据库的操 ...
- Django QuerySet优化
参考: https://docs.djangoproject.com/zh-hans/3.2/topics/db/optimization https://www.jianshu.com/p/aded ...
最新文章
- SQLSERVER存储过程基本语法使用
- Linux下创建root权限的账号osadmin
- 请不要做浮躁的人——转给即将上路或者正在路上的程序员朋友
- VirtualBox安装完Linux却进不了系统
- JAVA-date(计算时间差)
- c++101rule
- Java回调函数实现案例
- syn_sent mysql_服务器上出现大量的SYN_RECV或者SYN_SENT状态的TCP连接的问题分析
- 三个工具测试网络速度
- C#面试经历分享(好好看,好好学)
- python3 tkinter 刷新标签图片
- Flutter 核心编程二:Dart基础语法之基本数据类型,数组,方法,Runs,函数闭包,typedef,操作符
- 保护信息安全,实名认证该怎么选?
- 创业服务资源获取的途径有哪些?
- 流批一体?实时数据处理场景化应用实例~
- BOF和EOF的详细解释
- htonl函数的功能_htonl()函数详解
- 代替塞规的高精度孔径测量方法——泊肃叶压差法
- aix还原Oracle数据库,【案例】Oracle数据恢复思路 Oracle FOR AIX
- 【MM小贴士】SCAT-批量删除预制发票的学习