Django ORM 知识点总结

Query是如何工作的

Django QuerySet是懒执行的,只有访问到对应数据的时候,才会去访问数据库。另外如果你再次读取查询到的数据,将不会触发数据库的访问,而是直接从缓存获取。
比如

# 这里不会访问数据库,origins只是一个查询query,不是数据实例
origins = queryset.filter(status__in=[0, 2])
# 这里会访问数据库,将origins中的查询query与此update语句拼在一起组成一个sql语句
origins.update(status=1)
# 这里的origins,是再次执行查询之后的结果,因此,结果为空集
# 如果此时认为origins是之前查询的结果集,就会出错
for origin in origins:
self.after_confirm(origin, project_id)

在访问两个数据库的时候,需要把对前一个数据库访问的结果转为缓存数据再执行对下一个数据库的访问,比如

# object1与object2通过关系表Relations关联
# object1和Relations表在同一个数据库中,object2在另一个数据库中
# 现在需要通过object1的一堆id来找到对应的object2# 错误写法:
object2_ids = Relations.filter(object1_id__in=(object1_ids)).values_list('object2_id', flat=True).distinct()
object2s = Object2.objects.filter(id__in=object2_ids)
# 如果这时直接这样写,则实际上是涉及两个数据库的query的拼接,会出错
# 应该将第一个query转换为内存数据list# 正确写法:
object2_ids = list(Relations.filter(object1_id__in=(object1_ids)).values_list('object2_id', flat=True).distinct())
object2s = Object2.objects.filter(id__in=object2_ids)

多使用query的count()函数代替for循环计数

对1530条数据做for循环计数的速度是0.2~0.3s

而用count只需要0.007s左右

Django目前不提供外键或多对多的关系跨越多个数据库的支持。如果你使用路由器分割模型对不同的数据库,任何FOREIGNKEY和多对多关系的模型定义必须是单个数据库的内部。

复制模型数据

  • 获取model_object值的方式

model.var

model中定义了为IntegerField的属性取出来是int

  • 将model_object转成字典

model.__dict__ 或者 model_to_dict(model)

  • 复制模型数据
# 在主数据库创建一个订单副本
# id也会相应复制,但created_time和modified_time不会
order = Order.objects.using('qtr').last()
OrderCopy.objects.create(**model_to_dict(order), project_id='qtr')

外键的反向引用

  • Tag.objects.filter(project_tag__project_id=project_id)

ProjectTag表的tag字段外键到了Tag表的id字段,并且定义了related_name='project_tag'的反向引用,因此可以通过Tag Model的project_tag字段访问到ProjectTag Model。project_tag__project_id表示ProjectTag Model的project_id字段

  • Tag.objects.filter(user_tag__user_id=user_id)

UserTag表的tag字段外键到了Tag表的id字段,并且定义了related_name='user_tag'的反向引用。同时UserTag表的user字段外键到了User表,因此user_tag__user_id表示User的id字段

总之,外键的反向引用用两横

Update

Tag.objects.filter(id__in=ids).all().update(**update_data)

filter(id__in=ids)相当于where id in ids

如果过滤的结果是空集则不会执行更新

update_data是一个字典

利用Q构建复杂的查询条件

如何取数据表最后两条数据

Record.objects.order_by('-id')[:2]

[:2]会被翻译为LIMIT 2

关于这个语句的性能消耗:http://blog.jobbole.com/52852/ 总之就是消耗不大

获取指定列的数据

  • values:返回一个dict
record = Record.objects.values('id','name').first()
print(type(record))
# <class 'dict'>
  • values_list: 返回一个tuple,设置flat=True可以在只选择一列的情况下返回不用tuple包裹的数据
# 取最后两条数据记录的svn版本
ClientVersion.objects.values_list('svn_version', flat=True).order_by('-id')[:2]
  • 若是过滤出了多行数据,返回的是queryset类型,可以用list()将其转为列表

获取上一条数据和下一条数据

# 本条
obj = Record.objects.get(name='test')
# 上一条
pre_obj = Record.objects.filter(id__lt=obj.id).last()
# 下一条
next_obj = Record.objects.filter(id__gt=obj.id).first()

不等于

User.objects.exclude(age=10) // 查询年龄不为10的用户
User.objects.exclude(age__in=[10, 20]) // 查询年龄不为在 [10, 20] 的用户

exact

def test_exact():
query1 = Origin.objects.filter(origin_str='test')
print(query1.query)
query2 = Origin.objects.filter(origin_str__exact='test')
print(query2.query)
# 二者翻译成sql语句是一样的
# WHERE `translate_app_origin`.`origin_str` = test

筛选空

django model从数据库中取字符串的时候会自动去掉字符实际内容两旁的空格
比如 queryset.filter(result='') 可以过滤出result=" "和result=""的条目

# 排除result=null、result=""、result=" "
# 注意不要写成queryset.exclude(result__isnull=True, result=''),这表示同时满足两个条件才会被过滤
items = queryset.exclude(result__isnull=True).exclude(result='')

queryset的拼接

a1 = User.objects.filter(id__gt=8)
a2 = User.objects.filter(id__lt=4)a3 = a1 | a2
# 这种方式合并的结构还是一个queryset,相当于a3把a1和a2的条件合并了
# 只能合并同一个数据库同种model对象的数据,并不能拼接两个不同数据库相同model的queryset
from itertools import chaina1 = User.objects.filter(id__gt=8)
a2 = User.objects.filter(id__lt=4)a3 = chain(a1, a2)
# 这时候a3是个可迭代对象,把a1和a2分别求出来之后合并成了一个可迭代对象,
# 可以把不同model的对象合并,类似于与list相加。
# 但是这样合并之后a3并不是一个queryset,不能用任何筛选,没什么意义,还不如全部转成data_dict再拼接

总之就是,没有把多个不同数据库中相同model过滤出来的queryset合并的办法

distinct

如果出现错误:DISTINCT ON fields is not supported by this database backend

如果你用的Mysql数据库,那么distinct() 里面不要任何参数,参数应该写在 value 中去,如

language_list = items.values_list('language', flat=True).distinct()

order by

一个query只能有一个order_by,如果有多个,后面的order_by会覆盖前面的,如

Order.objects.order_by('project_id').order_by('name')
# sql:
# select * from order order by order.name ASC

对bool值按默认顺序排序的时候,False会排在True前面,因为False相当于0,True相当于1

# 需要将True排在前面
def test_order_by():
result = OrderLanguagePair.objects.order_by('-activate').first()
print(result.activate)

group by

比如现在想知道每个项目有多少个订单,在sql语句中应对订单按项目id分组,然后求出每组订单的数量

SELECT project_id, count(*) FROM order group by project_id;

django ORM中没有显式的group by函数,通过annotate来实现分组

# annotate的作用是为一个query增加一个自定义的新字段
# annotate接收表达式作为参数
def annotate(self, *args, **kwargs):
"""
Return a query set in which the returned objects have been annotated
with extra data or aggregations.
"""

如果没有指定任何字段,annotate会根据前面queryset的第一个字段(一般是id)分组计算,如

Order.objects.annotate(Count('name'))
# sql:
# select *, count(order.name) from order group by order.id

在annotate前用values或values_list指定根据什么字段分组,如

# 注意values要放在annotate之前
Order.objects.values('project_id').annotate(count=Count('*'))
# sql:
# select order.project_id, count(*) as count from order group by order.project_id

annotate定义的字段会加到前面的values或values_list中

values中有多个值时,会按照顺序group by

Order.objects.values('project_id', 'name').annotate(count=Count('*'))
# sql:
# select order.project_id, order.name, count(*) as count from order group by order.project_id, order.name

如果annotate所属的query含有order_by的话,除了按values的字段分组外,还会额外按照order_by的字段分组(如果order_by中的字段不在values中)

# 下面两个query对应的sql是一样的
Order.objects.values('project_id').annotate(count=Count('*')).order_by('name')
Order.objects.order_by('name').values('project_id').annotate(count=Count('*'))
# sql:
# select order.project_id, count(*) as count from order
# group by order.project_id, order.name 
# order by order.name

解决的方法是用对分组字段的排序覆盖query之前的排序,比如

query = Order.objects.order_by('name')
query.order_by('project_id').values('project_id').annotate(count=Count('*'))

别名

希望使用ORM实现给字段加别名,如

select name as user_name, id as user_id
from users

Django有两种实现方式

  1. extra
User.objects.extra(select={'user_id':user, 'user_name':id}). \
values('user_id', 'user_name')

但是这种方法只能适用于没有外键引用的情况,即只能选择给此Model的字段取别名,如果要给外键引用的字段取别名,需要用到下面这种方式

  1. annotate
ProjectLanguagePair.objects.\
annotate(supplier_name=F('supplier__supplier_name')). \
values('supplier_name')

ProjectLanguagePair用supplier字段外键到了Supplier表,相当于

SELECT `supplier_app_supplier`.`supplier_name` AS `supplier_name` 

转载于:https://www.cnblogs.com/luozx207/p/11545057.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/447692.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/447692.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

22天养成好习惯,一年后脱胎换骨!

第一个习惯&#xff1a; 每天对镜子的自己微笑。 亲爱的&#xff0c;如果你都不喜欢自己的话&#xff0c;怎么可能指望别人喜欢你&#xff1f; 第二个习惯&#xff1a; 每天用凉水洗脸。 凉水洗脸&#xff0c;皮肤健康&#xff1b;热水洗脚&#xff0c;强似吃药。 第三个习…

springCloud - 第1篇 - 服务的注册 Eureka

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 PS&#xff1a;这个系列不定时更新&#xff0c;只是个人的学习分享&#xff0c; 内容全程参考书目&#xff1a; 《Spring Cloud 与 Do…

js中的Map对象

var map new Map();//map对象中添加键值对map.set("name","tom");map.set("age",35);map.set("sex",0);//获取map对象中的值map.get("name")//tom//遍历map 函数中第一个参数是value&#xff0c;第二个参数是keymap.forEa…

十六个字 一辈子学不完

1、道歉&#xff1a;并不总意味着你是错的&#xff0c;它只是意味着你更珍惜你们之间的关系。 2、相爱&#xff1a;不是寻找一个完美的人&#xff0c;而是学会用完美的眼光&#xff0c;去欣赏一个不完美的人。 3、专一&#xff1a;不是一辈子只喜欢一个人&#xff0c;…

解决:com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column ‘ip‘ at row 1

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 报错&#xff1a; SQL []; Data truncation: Data too long for column ip at row 1; nested exception is com.mysql.jdbc.MysqlDa…

Xampp配置本地域名及常见错误解决

Xampp配置本地域名及常见错误解决 本地域名配置1、计算机-->C盘-->Windows-->System32-->drivers-->etc-->hosts127.0.0.1 localhost//设置你要配置的本地域名2、计算机-->XAMPP-->apache-->conf-->extra-->httpd-vhosts.conf<Virtu…

单元测试写法

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 好像很早前写过的&#xff1a; package com.xxx.dubbo;import com.xxx.app.xx.xx.dao.MarketingRuleMapper; import com.xxx.app.xx.xx…

刷新网页跳转锚点

html中&#xff1a; <a name"miao" > <b>{{ $v->department_name }}</b></a> js跳转锚点&#xff1a; window.οnlοadfunction(){location.hashmiao;} 转载于:https://www.cnblogs.com/best-coder/p/11550177.html

java - 通用 CRUD(增、删、改、查)工具类,代码高效复用

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 基本 CRUD 方法实现&#xff1a; package com.xxx.xxx.ls.xxx.utils;import com.alibaba.fastjson.JSON; import com.google.common…

CSS文本溢出显示省略号

项目中常常有这种需要我们对溢出文本进行"..."显示的操作&#xff0c;单行多行的情况都有&#xff08;具体几行得看设计师心情了&#xff09;&#xff0c;这篇随笔是我个人对这种情况解决办法的归纳&#xff0c;欢迎各路英雄指教。 单行 语法 overflow:hidden;text-o…

@JsonFormat Date类型时间 格式化 注解 使用

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 JsonFormat注解是一个时间格式化注解&#xff0c;比如我们存储在mysql中的数据是date类型的&#xff0c;当我们读取出来封装在实体类中的…

好用的在线工具

1.在线工具 http://tool.oschina.net/ 网站里面包含很多强大的工具&#xff0c;代码对比&#xff0c;正则表达式在线验证&#xff0c;各种语言的语法对照表等。 2.so JSON在线工具 https://www.sojson.com/ 这个网站可能更加偏向前端一些吧&#xff0c;里面有一些加密解密&…

解决 Idea 卡在 Resolving Maven dependencies ...

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 Idea卡在Resolving Maven dependencies的解决方案 在Reimpot All Maven Porjects时, 如果项目过大, maven依赖过多, 会直接卡在Resolvin…

VS Code (visual studio code) VSC 编辑器(微软出品,js开发的编辑器)

一.选择合适的编辑器&#xff0c;提高编程效率 代码编辑器的选择&#xff0c;可以说是开发者社区中一个经久不衰的话题&#xff0c;现今编辑器的数量数不胜数&#xff0c;vim&#xff0c;sublime Text,Emacs,Atom等等&#xff0c;那么对于一个开发者而言&#xff0c;挑选一个合…

Docker 安装 redis 、Redis docker 方式部署

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 找镜像&#xff1a; docker search redis2. 拉取镜像&#xff1a; 在这一步可以选择版本&#xff0c;不选择版本&#xff0c;默认为…

xcode windows版安装使用教程

随着iPhone、iPad、Mac等苹果产品越来越火爆&#xff0c;越来越多的初学者想要了解和尝试苹果平台&#xff0c;包括苹果操作系统Mac OS X、苹果演示软件Keynote、苹果开发工具Xcode等。然而&#xff0c;苹果电脑价格昂贵&#xff0c;并不是每个人都可以承受。 因此&#xff0c;…

解决:Unable to open debugger port (127.0.0.1:55017): java.net.SocketException “Socket closed“

项目以前启动正常&#xff0c;突然报错&#xff0c;启动不起来了&#xff0c;报了个Unable to open debugger port (127.0.0.1:55017): java.net.SocketException "Socket closed"这个错。 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;…

html5 如何打包成apk,将H5封装成android应用APK文件的几种方法

直接使用编程软件提供的方法&#xff1a; 1、需要下载安装MyEclipse2014&#xff0c;Android SDK&#xff0c;eclipse(需配置Android开发环境) Java和Android环境安装与配置。 2、打开MyEclipse2014&#xff0c;新建一个HTML5 Mobile Application Project&#xff0c;命名&…

解决 Unmapped Spring configuration files found.Please configure Spring facet.

最近在学习使用IDEA工具&#xff0c;觉得与Eclipse相比&#xff0c;还是有很多的方便之处。 但是&#xff0c;当把自己的一个项目导入IDEA之后&#xff0c;Event Log提示“Unmapped Spring configuration files found.Please configure Spring facet.” 这个提示不影响工程正…

uni-app—从安装到卸载

uni-app实现了一套代码&#xff0c;同时运行到多个平台。支持iOS模拟器、Android模拟器、H5、微信开发者工具、支付宝小程序Studio、百度开发者工具、字节跳动开发者工具 工具安装 开发uni-app需要安装HBuilder X.下载地址。 下载成功后直接解压即可 简单的配置一下开发偏好&am…