详解Django的model查询操作与查询性能优化


Posted in Python onOctober 16, 2018

1 如何 在做ORM查询时 查看SQl的执行情况

(1) 最底层的 django.db.connection

在 django shell 中使用  python manage.py shell

>>> from django.db import connection
>>> Books.objects.all()
>>> connection.queries  ## 可以查看查询时间
[{'sql': 'SELECT "testsql_books"."id", "testsql_books"."name", "testsql_books"."author_id" FROM "testsql_books" LIMI
T 21', 'time': '0.002'}]

(2) django-extensions 插件 

pip install django-extensions
INSTALLED_APPS = (
    ...
    'django_extensions',
    ...
    )

在 django shell 中使用  python manage.py shell_plus  --print-sql (extensions 强化)

这样每次查询都会 有sql 输出

>>> from testsql.models import Books
>>> Books.objects.all()
  SELECT "testsql_books"."id", "testsql_books"."name", "testsql_books"."author_id" FROM "testsql_books" LIMIT 21

Execution time: 0.002000s [Database: default]

<QuerySet [<Books: Books object>, <Books: Books object>, <Books: Books object>]>

2 ORM查询操作 以及优化

基本操作

增

models.Tb1.objects.create(c1='xx', c2='oo') 增加一条数据,可以接受字典类型数据 **kwargs

obj = models.Tb1(c1='xx', c2='oo')
obj.save()

 查

models.Tb1.objects.get(id=123)     # 获取单条数据,不存在则报错(不建议)
models.Tb1.objects.all()        # 获取全部
models.Tb1.objects.filter(name='seven') # 获取指定条件的数据
models.Tb1.objects.exclude(name='seven') # 获取指定条件的数据

 删

models.Tb1.objects.filter(name='seven').delete() # 删除指定条件的数据

 改
models.Tb1.objects.filter(name='seven').update(gender='0') # 将指定条件的数据更新,均支持 **kwargs
obj = models.Tb1.objects.get(id=1)
obj.c1 = '111'
obj.save()                         # 修改单条数据

查询简单操作

获取个数

  models.Tb1.objects.filter(name='seven').count()

大于,小于

  models.Tb1.objects.filter(id__gt=1)       # 获取id大于1的值
  models.Tb1.objects.filter(id__gte=1)       # 获取id大于等于1的值
  models.Tb1.objects.filter(id__lt=10)       # 获取id小于10的值
  models.Tb1.objects.filter(id__lte=10)       # 获取id小于10的值
  models.Tb1.objects.filter(id__lt=10, id__gt=1)  # 获取id大于1 且 小于10的值

in

  models.Tb1.objects.filter(id__in=[11, 22, 33])  # 获取id等于11、22、33的数据
  models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in

isnull
  Entry.objects.filter(pub_date__isnull=True)

contains

  models.Tb1.objects.filter(name__contains="ven")
  models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
  models.Tb1.objects.exclude(name__icontains="ven")

range

  models.Tb1.objects.filter(id__range=[1, 2])  # 范围bettwen and

其他类似

  startswith,istartswith, endswith, iendswith,

order by

  models.Tb1.objects.filter(name='seven').order_by('id')  # asc
  models.Tb1.objects.filter(name='seven').order_by('-id')  # desc

group by--annotate

  from django.db.models import Count, Min, Max, Sum
  models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))
  SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"

limit 、offset

  models.Tb1.objects.all()[10:20]

regex正则匹配,iregex 不区分大小写

  Entry.objects.get(title__regex=r'^(An?|The) +')
  Entry.objects.get(title__iregex=r'^(an?|the) +')

date

  Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
  Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))

year

  Entry.objects.filter(pub_date__year=2005)
  Entry.objects.filter(pub_date__year__gte=2005)

month

  Entry.objects.filter(pub_date__month=12)
  Entry.objects.filter(pub_date__month__gte=6)

day

  Entry.objects.filter(pub_date__day=3)
  Entry.objects.filter(pub_date__day__gte=3)

week_day

  Entry.objects.filter(pub_date__week_day=2)
  Entry.objects.filter(pub_date__week_day__gte=2)

hour

  Event.objects.filter(timestamp__hour=23)
  Event.objects.filter(time__hour=5)
  Event.objects.filter(timestamp__hour__gte=12)

minute

  Event.objects.filter(timestamp__minute=29)
  Event.objects.filter(time__minute=46)
  Event.objects.filter(timestamp__minute__gte=29)

second

  Event.objects.filter(timestamp__second=31)
  Event.objects.filter(time__second=2)
  Event.objects.filter(timestamp__second__gte=31)

查询复杂操作

FK foreign key 使用的原因:

  • 约束
  • 节省硬盘

但是多表查询会降低速度,大型程序反而不使用外键,而是用单表(约束的时候,通过代码判断)

extra

extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
    Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
    Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
    Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
    Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])

F

from django.db.models import F
  models.Tb1.objects.update(num=F('num')+1)

Q

方式一:
  Q(nid__gt=10)
  Q(nid=8) | Q(nid__gt=10)
  Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')

  方式二:
  con = Q()
  q1 = Q()
  q1.connector = 'OR'
  q1.children.append(('id', 1))
  q1.children.append(('id', 10))
  q1.children.append(('id', 9))
  q2 = Q()
  q2.connector = 'OR'
  q2.children.append(('c1', 1))
  q2.children.append(('c1', 10))
  q2.children.append(('c1', 9))
  con.add(q1, 'AND')
  con.add(q2, 'AND')

  models.Tb1.objects.filter(con)

exclude(self, *args, **kwargs)

# 条件查询
  # 条件可以是:参数,字典,Q

select_related(self, *fields)

性能相关:表之间进行join连表操作,一次性获取关联的数据。
   model.tb.objects.all().select_related()
   model.tb.objects.all().select_related('外键字段')
   model.tb.objects.all().select_related('外键字段__外键字段')

prefetch_related(self, *lookups)

性能相关:多表连表操作时速度会慢,使用其执行多次SQL查询 在内存中做关联,而不会再做连表查询
      # 第一次 获取所有用户表
      # 第二次 获取用户类型表where id in (用户表中的查到的所有用户ID)
      models.UserInfo.objects.prefetch_related('外键字段')

annotate(self, *args, **kwargs)

# 用于实现聚合group by查询

  from django.db.models import Count, Avg, Max, Min, Sum

  v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id'))
  # SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id

  v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1)
  # SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1

  v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1)
  # SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1

extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)

# 构造额外的查询条件或者映射,如:子查询

    Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
    Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
    Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
    Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])

reverse(self):

# 倒序
models.UserInfo.objects.all().order_by('-nid').reverse()
# 注:如果存在order_by,reverse则是倒序,如果多个排序则一一倒序

下面两个 取到的是对象,并且注意 取到的对象可以 获取其他字段(这样会再去查找该字段降低性能
defer(self, *fields):

models.UserInfo.objects.defer('username','id')
或
models.UserInfo.objects.filter(...).defer('username','id')
# 映射中排除某列数据

only(self, *fields):

# 仅取某个表中的数据
models.UserInfo.objects.only('username','id')
或
models.UserInfo.objects.filter(...).only('username','id')

执行原生SQL

1.connection
from django.db import connection, connections
cursor = connection.cursor() 
# cursor = connections['default'].cursor()
django的settings中的db配置 ' default',指定数据库
cursor.execute("""SELECT * from auth_user where id = %s""", [1])
row = cursor.fetchone()

2 .extra
Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])

3 . raw     
name_map = {'a':'A','b':'B'}
models.UserInfo.objects.raw('select * from xxxx',translations=name_map)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python贪心算法实例小结
Apr 22 Python
django 发送邮件和缓存的实现代码
Jul 18 Python
python实现时间o(1)的最小栈的实例代码
Jul 23 Python
pygame游戏之旅 按钮上添加文字的方法
Nov 21 Python
python3 property装饰器实现原理与用法示例
May 15 Python
Pytorch卷积层手动初始化权值的实例
Aug 17 Python
Python matplotlib绘制饼状图功能示例
Sep 10 Python
python支持多线程的爬虫实例
Dec 21 Python
tensorflow实现二维平面模拟三维数据教程
Feb 11 Python
解决在keras中使用model.save()函数保存模型失败的问题
May 21 Python
PyCharm Community安装与配置的详细教程
Nov 24 Python
Python3接口性能测试实例代码
Jun 20 Python
python查看模块,对象的函数方法
Oct 16 #Python
Python中asyncio与aiohttp入门教程
Oct 16 #Python
python查看模块安装位置的方法
Oct 16 #Python
Django model序列化为json的方法示例
Oct 16 #Python
Python重新加载模块的实现方法
Oct 16 #Python
django Serializer序列化使用方法详解
Oct 16 #Python
为什么str(float)在Python 3中比Python 2返回更多的数字
Oct 16 #Python
You might like
浅析php面向对象public private protected 访问修饰符
2013/06/30 PHP
PHP中mysqli_affected_rows作用行数返回值分析
2014/12/26 PHP
PHP连接操作access数据库实例
2015/03/30 PHP
php.ini中的request_order推荐设置
2015/05/10 PHP
php.ini中date.timezone设置详解
2016/11/20 PHP
Laravel程序架构设计思路之使用动作类
2018/06/07 PHP
使用UglifyJS合并/压缩JavaScript的方法
2012/03/07 Javascript
JavaScript学习笔记之JS对象
2015/01/22 Javascript
JavaScript插件化开发教程 (一)
2015/01/27 Javascript
一张Web前端的思维导图分享
2015/07/03 Javascript
全面解析JavaScript里的循环方法之forEach,for-in,for-of
2020/04/20 Javascript
JavaScript正则表达式实例详解
2016/10/16 Javascript
angular源码学习第一篇 setupModuleLoader方法
2016/10/20 Javascript
react-native 封装选择弹出框示例(试用ios&amp;android)
2017/07/11 Javascript
JavaScript检查数据中是否存在相同的元素(两种方法)
2018/10/07 Javascript
基于vue实现web端超大数据量表格的卡顿解决
2019/04/02 Javascript
Vue 实例事件简单示例
2019/09/19 Javascript
微信小程序canvas开发水果老虎机的思路详解
2020/02/07 Javascript
解决vue自定义指令导致的内存泄漏问题
2020/08/04 Javascript
Nuxt 项目性能优化调研分析
2020/11/07 Javascript
[00:31]DOTA2上海特级锦标赛 Fnatic战队宣传片
2016/03/04 DOTA
Python 实现子类获取父类的类成员方法
2019/01/11 Python
ipython jupyter notebook中显示图像和数学公式实例
2020/04/15 Python
HTML5标签小集
2011/08/02 HTML / CSS
字符串str除首尾字符外的其他字符按升序排列
2013/03/08 面试题
远东集团网络工程师面试题
2014/10/20 面试题
国际贸易个人求职信范文
2014/01/04 职场文书
开学季活动策划方案
2014/02/28 职场文书
小学校园文化建设汇报材料
2014/08/19 职场文书
群众路线班子对照检查材料
2014/09/25 职场文书
大学生个人年度总结范文
2015/02/15 职场文书
公司开业主持词
2015/07/02 职场文书
英语投诉信范文
2015/07/03 职场文书
python数字类型和占位符详情
2022/03/13 Python
SQL Server的存储过程与触发器以及系统函数和自定义函数
2022/04/10 SQL Server
WinServer2012搭建DNS服务器的方法步骤
2022/06/10 Servers