文章目录

  • 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之后就会与数据库交互

  1. 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')
    
  2. queryset具有cache的,可减少数据库查询
    • for语句遍历queryset时,所有匹配的记录会从数据库获取,然后转换成Django的model,这被称为执行(evaluation)。
    • 这些model会保存在queryset内置的cache中,若再次遍历这个queryset,不需要重复运行通用的查询。即代码只会执行一次数据库查询。
    • if queryset 触发执行: 用if语句判断会完全执行整个queryset并把数据放入cache,虽然你并不需要这些数据!!
  3. 避免cache问题
    1. 为避免if,可用queryset.exists()来检查是否有数据,从而节省带宽和内存.
    2. 避免遍历数据时产生cache,可用 .iterator() 来获取数据防止生成cache,处理完数据就将其丢弃。 但多次遍历时会重复执行查询!!!
    3. exists() + iterator() : 用两次数据库查询来避免使用查询集缓存。

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_relatedinner 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用法相关推荐

  1. Django QuerySet 就学那么一点点,一点点就够了

    橡皮擦,一个逗趣的互联网高级网虫.新的系列,让我们一起进入 Django 世界. 已经完成的文章 滚雪球学 Python 第三轮,Python Web 之 Django 的世界 小手哆嗦一下,就能用 ...

  2. Django QuerySet API 文档阅读(3):QuerySet定义(一)

    原文地址:​​​​​​QuerySet API reference | Django documentation | Django QuerySet有两个属性,ordered和db: ordered: ...

  3. Django学习笔记之Django QuerySet的方法

    一般情况下,我们在写Django项目需要操作QuerySet时一些常用的方法已经满足我们日常大多数需求,比如get.filter.exclude.delete神马的感觉就已经无所不能了,但随着项目但业 ...

  4. Django QuerySet API文档

    在查询时发生了什么(When QuerySets are evaluated) QuerySet 可以被构造,过滤,切片,做为参数传递,这些行为都不会对数据库进行操作.只要你查询的时候才真正的操作数据 ...

  5. 合并多个python list以及合并多个 django QuerySet 的方法

    尊重原文作者,该文转载于: http://www.yihaomen.com/article/python/533.htm 在用python或者django写一些小工具应用的时候,有可能会遇到合并多个l ...

  6. Django模板用法

    django模板原理 # 创建template对象,由context对象传递template所需要的值, 有render方法进行模板的呈现 # 写模板,创建 Template 对象,创建 Contex ...

  7. Django update用法

    model update常规用法 假如我们的表结构是这样的 class User(models.Model):username = models.CharField(max_length=255, u ...

  8. django QuerySet

    Django对数据库的封装1--QuerySet 发布时间:2018-02-28 来源:网络 上传者:用户 关键字: manager 数据库 记录 影响 发表文章 摘要:   Django对数据库的操 ...

  9. Django QuerySet优化

    参考: https://docs.djangoproject.com/zh-hans/3.2/topics/db/optimization https://www.jianshu.com/p/aded ...

最新文章

  1. SQLSERVER存储过程基本语法使用
  2. Linux下创建root权限的账号osadmin
  3. 请不要做浮躁的人——转给即将上路或者正在路上的程序员朋友
  4. VirtualBox安装完Linux却进不了系统
  5. JAVA-date(计算时间差)
  6. c++101rule
  7. Java回调函数实现案例
  8. syn_sent mysql_服务器上出现大量的SYN_RECV或者SYN_SENT状态的TCP连接的问题分析
  9. 三个工具测试网络速度
  10. C#面试经历分享(好好看,好好学)
  11. python3 tkinter 刷新标签图片
  12. Flutter 核心编程二:Dart基础语法之基本数据类型,数组,方法,Runs,函数闭包,typedef,操作符
  13. 保护信息安全,实名认证该怎么选?
  14. 创业服务资源获取的途径有哪些?
  15. 流批一体?实时数据处理场景化应用实例~
  16. BOF和EOF的详细解释
  17. htonl函数的功能_htonl()函数详解
  18. 代替塞规的高精度孔径测量方法——泊肃叶压差法
  19. aix还原Oracle数据库,【案例】Oracle数据恢复思路 Oracle FOR AIX
  20. 【MM小贴士】SCAT-批量删除预制发票的学习

热门文章

  1. windows10打开指向的链接提示Windows找不到文件
  2. 从Spring头那一堆东西说起
  3. 牛客Wannafly挑战赛29 A 御坂美琴 思维题
  4. linux 文件描述 等。
  5. 发改委:加大下一代互联网试商用投入
  6. Docker部署redis单机版本 - 修改redis密码和持久化方式
  7. 【QT】--调用百度地图API显示
  8. 智慧校园小程序-微信小程序毕业设计(附下载链接)
  9. 用过的最好的自动机画图工具  JFLAP
  10. R语言做文本挖掘:基于网购评论提炼电热水器的差异化卖点