详解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中获取网页状态码的两个方法
Nov 03 Python
在Python中操作列表之list.extend()方法的使用
May 20 Python
Python实现的矩阵类实例
Aug 22 Python
Python三级菜单的实例
Sep 13 Python
python利用Opencv实现人脸识别功能
Apr 25 Python
python实现趣味图片字符化
Apr 30 Python
python 视频逐帧保存为图片的完整实例
Dec 10 Python
python标准库OS模块函数列表与实例全解
Mar 10 Python
解决Django中checkbox复选框的传值问题
Mar 31 Python
python 常见的排序算法实现汇总
Aug 21 Python
Numpy中np.random.rand()和np.random.randn() 用法和区别详解
Oct 23 Python
在pycharm创建scrapy项目的实现步骤
Dec 01 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目录导航文件代码
2006/10/09 PHP
由php的call_user_func传reference引发的思考
2010/07/23 PHP
CodeIgniter框架过滤HTML危险代码
2014/06/12 PHP
php中使用gd库实现远程图片下载实例
2015/05/12 PHP
PHP实现的QQ空间g_tk加密算法
2015/07/09 PHP
PHP微信公众号开发之微信红包实现方法分析
2017/07/14 PHP
PHP单例模式应用示例【多次连接数据库只实例化一次】
2018/12/18 PHP
如何用javascript去掉字符串里的所有空格
2007/02/08 Javascript
jquery遍历数组与筛选数组的方法
2013/11/05 Javascript
深入理解javascript构造函数和原型对象
2014/09/23 Javascript
js中flexible.js实现淘宝弹性布局方案
2020/06/23 Javascript
jQuery Form 表单提交插件之formSerialize,fieldSerialize,fieldValue,resetForm,clearForm,clearFields的应用
2016/01/23 Javascript
jQuery+css实现的tab切换标签(兼容各浏览器)
2016/01/28 Javascript
如何解决手机浏览器页面点击不跳转浏览器双击放大网页
2016/07/01 Javascript
jQuery操作iframe中js函数的方法小结
2016/07/06 Javascript
vue.js表格分页示例
2016/10/18 Javascript
nodejs中模块定义实例详解
2017/03/18 NodeJs
Vue通过provide inject实现组件通信
2020/09/03 Javascript
JavaScript 生成唯一ID的几种方式
2021/02/19 Javascript
好用的Python编辑器WingIDE的使用经验总结
2016/08/31 Python
Python列表list解析操作示例【整数操作、字符操作、矩阵操作】
2017/07/25 Python
python3操作微信itchat实现发送图片
2018/02/24 Python
django组合搜索实现过程详解(附代码)
2019/08/06 Python
Python函数装饰器原理与用法详解
2019/08/16 Python
瑞士香水购物网站:Parfumcity.ch
2017/01/14 全球购物
英国羊皮鞋类领先品牌:Just Sheepskin
2019/12/12 全球购物
Woods官网:加拿大最古老、最受尊敬的户外品牌之一
2020/09/12 全球购物
共产党员公开承诺书范文
2014/03/28 职场文书
班级旅游计划书
2014/05/03 职场文书
辞职信范文大全
2015/03/02 职场文书
2015年护士工作总结范文
2015/03/31 职场文书
警告通知
2015/04/25 职场文书
职工宿舍管理制度
2015/08/05 职场文书
90条交通安全宣传标语
2019/10/12 职场文书
Python 实现定积分与二重定积分的操作
2021/05/26 Python
vue elementUI批量上传文件
2022/04/26 Vue.js