详解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实现简单拆分PDF文件的方法
Jul 30 Python
Python实现脚本锁功能(同时只能执行一个脚本)
May 10 Python
利用Python查看目录中的文件示例详解
Aug 28 Python
python使用正则表达式的search()函数实现指定位置搜索功能
Nov 10 Python
使用Python的Dataframe取两列时间值相差一年的所有行方法
Jul 10 Python
Python对CSV、Excel、txt、dat文件的处理
Sep 18 Python
python基于socket进行端口转发实现后门隐藏的示例
Jul 25 Python
python实现猜数游戏
Mar 27 Python
使用python批量转换文件编码为UTF-8的实现
Apr 03 Python
Python HTMLTestRunner可视化报告实现过程解析
Apr 10 Python
Kmeans均值聚类算法原理以及Python如何实现
Sep 26 Python
python使用dlib进行人脸检测和关键点的示例
Dec 05 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
【动漫杂谈】关于《请在T台上微笑》
2020/03/03 日漫
php面向对象全攻略 (四)构造方法与析构方法
2009/09/30 PHP
php简单的留言板与回复功能具体实现
2014/02/19 PHP
php对数组排序代码分享
2014/02/24 PHP
thinkPHP框架整合tcpdf插件操作示例
2018/08/07 PHP
PHP7 新增功能
2021/03/09 PHP
javascript实现 在光标处插入指定内容
2007/05/25 Javascript
js展开闭合效果演示代码
2013/07/24 Javascript
jquery实现无限分级横向导航菜单的方法
2015/03/12 Javascript
JavaScript实现控制打开文件另存为对话框的方法
2015/04/17 Javascript
简单的JS控制button颜色随点击更改的实现方法
2017/04/17 Javascript
微信小程序 es6-promise.js封装请求与处理异步进程
2017/06/12 Javascript
用Vue.extend构建消息提示组件的方法实例
2017/08/08 Javascript
微信小程序实现列表下拉刷新上拉加载
2020/07/29 Javascript
ng-repeat指令在迭代对象时的去重方法
2018/10/02 Javascript
layer页面跳转,获取html子节点元素的值方法
2019/09/27 Javascript
TypeScript 引用资源文件后提示找不到的异常处理技巧
2020/07/15 Javascript
vue2和vue3的v-if与v-for优先级对比学习
2020/10/10 Javascript
[01:57]2016完美“圣”典风云人物:国士无双专访
2016/12/04 DOTA
python让图片按照exif信息里的创建时间进行排序的方法
2015/03/16 Python
python使用自定义user-agent抓取网页的方法
2015/04/15 Python
Python爬虫代理IP池实现方法
2017/01/05 Python
Python tkinter模块弹出窗口及传值回到主窗口操作详解
2017/07/28 Python
python实现雨滴下落到地面效果
2018/06/21 Python
python函数参数(必须参数、可变参数、关键字参数)
2019/08/16 Python
科尔士百货公司官网:Kohl’s
2016/07/11 全球购物
linux面试相关问题
2012/08/11 面试题
大专毕业生自我鉴定
2013/11/21 职场文书
安全教育感言
2014/03/04 职场文书
小学向国旗敬礼活动方案
2014/09/27 职场文书
个人整改措施落实情况汇报
2014/10/29 职场文书
超市收银员岗位职责
2015/04/07 职场文书
小学教代会开幕词
2016/03/04 职场文书
工作转正自我鉴定范文
2019/06/21 职场文书
nginx 反向代理之 proxy_pass的实现
2021/03/31 Servers
swagger如何返回map字段注释
2021/07/03 Java/Android