QuerySet的API

文字版:


django中如何查看orm操作对应的SQL语句

from django.db import connection

print(connection.queries)

在cmd中快速复制的方法:

右击cmd的边框,选择属性

在“选项”这一选项卡中,选中“快速编辑”,并确定

在cmd中,用左键选中一段文字,点击右键,内容就到了剪切板了

下边的方法都是QuerySet的方法,而且会返回新的QuerySet

filter

将满足条件的数据提取出来,返回一个新的QuerySet。

books=Book.objects.filter(id__gte=6).filter(~Q(id=7))

exclude

排除满足条件的数据,返回一个新的QuerySet

books=Book.objects.filter(id__gte=6).exclude(id=7)

annotate

给QuerySet中每个对象添加一个使用查询表达式(聚合函数、F表达式、Q表达式、Func表达式等)的新字段

order_by

books=Book.objects.order_by('-id')

根据id进行逆序排序。

如果在order_by返回结果继续使用order_by,那么前一次的排序结果会丢失。

books=Book.objects.order_by('name').order_by('id')

最终会按照id进行排序,丢掉了按照name排序的结果。

另一种排序方式:在model的类中定义Meta类:

classMeta:

ordering=['name','-id']

在查询这张表的时候,就不用order_by,只要Book.objects.all(),结果就是先按照name排序,如果name相等再次按照id倒序排列。

all

获取这个ORM模型的QuerySet对象,可以迭代,每一条就是一行查询记录。

还是和objects方法有区别的,objects方法返回的是Manage对象,不能对它做遍历。

books=Book.objects.all()

forbookinbooks:

print(book.name)

如上,all方法返回的就是QuerySet对象,是可以迭代的,它的每个元素是Book类的对象。

values和values_list

values

用来指定提取数据时,提取哪些字段,默认是提取所有的字段。

values是用来指定提取哪些字段的。

values方法返回的是QuerySet,不过QuerySet中的数据类型不再是model对象,而是values中指定的字段和其值形成的字典。

示例:

books=Book.objects.values("id")

books=Book.objects.values("name",author_name=F("author__name"))

author是Book这张表中的一个外键字段,引用的是Author这张表。

通过F表达式,修改关联查询的结果的字段名,但是这个名字不能和Book本身表中的字段名重复。

如果values方法没有参数,会返回这张表的所有字段和其值,不包括外键。

values_list

同values的区别只是,返回的QuerySet中的数据不是字典,而是元组。只有字段的值,不包括字段的名字。

每个元组是一条记录的所有字段的值组成的,包括外键值。

示例

books=Book.objects.values_list("name",flat=True)

如果values_list方法中只传入了一个字段名,还是会返回一个元组。但是如果加上flat=True,就会把元组拆开,以str类型返回。

select_related

在提取某个model的数据的同时,也提前将相关联的数据提取出来,比如提取Book数据,可以使用select_related将author信息也提取出来,以后再次使用Book.author的时候,就不需要再次访问数据库了,可以减少数据库查询的次数。

只能用在一对多的关系,ForeignKey

示例:

1、使用select_relate示例:

books=Book.objects.select_related('author')

forbookinbooks:

print(book.author.name)

print(connection.queries)

这段语句的sql结果:

[{'time': '0.001', 'sql': 'SELECT "cmdb_book"."id", "cmdb_book"."name", "cmdb_book"."author_id", "author"."id", "author"."name", "author"."age", "author"."email" FROM "cmdb_book" INNER JOIN "author" ON ("cmdb_book"."author_id" = "author"."id")'}]

可以看到,使用select_related只有一个SQL语句。

2、不使用select_related的示例

books=Book.objects.all()

forbookinbooks:

print(book.author.name)

print(connection.queries)

这段代码的SQL语句:

[{'time': '0.001', 'sql': 'SELECT "cmdb_book"."id", "cmdb_book"."name", "cmdb_book"."author_id" FROM "cmdb_book"'},{'time': '0.000', 'sql': 'SELECT "author"."id", "author"."name", "author"."age", "author"."email" FROM "author" WHERE "author"."id" = 1'}, {'time': '0.000','sql': 'SELECT "author"."id", "author"."name", "author"."age", "author"."email" FROM "author" WHERE "author"."id" = 1'}, {'time': '0.000', 'sql': 'SELECT "author"."id", "author"."name", "author"."age", "author"."email" FROM "author" WHERE "author"."id" = 1'}, {'time': '0.000', 'sql': 'SELECT "author"."id", "author"."name", "author"."age", "author"."email" FROM "author" WHERE "author"."id" = 1'}, {'time': '0.000','sql': 'SELECT "author"."id", "author"."name", "author"."age", "author"."email" FROM "author" WHERE "author"."id" =1'}, {'time': '0.000', 'sql': 'SELECT "author"."id", "author"."name", "author"."age", "author"."email" FROM "author" WHERE "author"."id" = 1'}]

没有使用select_related时,每次有外键查询的时候,都会重新查询一次,因为我这张表里边有5条数据,每条数据的外键字段都是一条新的SQL语句。

defer

在一些表中,可能存在很多字段,但是一些字段的数据量可能非常大,而此时又不需要,比如我们在获取文章列表的时候,文章内容我们是不需要的,这时我们就可以使用defer来过滤掉一些字段。

它和value有些类似,不过value返回的QuerySet中是字典;而defer返回的QuerySet中是model对象。

示例:

books=Book.objects.defer('author')

forbookinbooks:

print(book.id,book.author)

print(connection.queries)

我们defer方法中,添加了author,那么返回的查询结果books是QuerySet,一条记录是一个model对象,但是每条记录中都没有author这个字段。

即使我们使用了defer来排除掉author,但是我们下边还是可以用book.author来获取这个字段,每一条记录都会触发一条SQL语句。

所以,如果我们确保后边的操作不会用到某个字段,才可以把这个字段defer掉。

only

跟defer相反:defer是排除掉某个字段;only是只提取这个字段。

返回的和defer一样类型。

id字段是一定会返回的,即使没有在把这个字段当做参数传进only方法中。

get

返回的不是QuerySet对象,返回的是符合条件的model对象。

给get指定的条件匹配有且仅有一条结果,如果有多个、或者没有满足,会出错。

books=Book.objects.get(id__gte=9)

这个查询,就会返回多条结果,导致程序出错。

create

创建一条数据,并且保存在数据库中。

这个方法相当于先用指定的model创建一个对象,然后调用这个对象的save方法。

get_or_create

count

在SQL层面,调用count,获取提取到的数据的条数。效率非常高。

不要使用len,len会把所有的数据从磁盘上加载到内存中,然后一个一个计算这个QuerySet中有多少条数据。效率非常低效

first和last

分别返回QuerySet中第一条和最后一条数据

books=Book.objects.all().first()

返回的是Book对象。

exists

判断符合某个条件的数据是否存在。

res=Book.objects.filter(name="宋宴").exists()

返回的是True或者False

是QuerySet可以调用的,数据记录对象没有这个方法

update

执行更新操作,在SQL底层走的也是update命令。update可能会更改多条记录,但是只需要一条SQL语句。

Book.objects.filter(name="宋宴").update(name='大宋')

上边代码更新了一条数据,成功返回1,失败返回0。

delete

Book.objects.filter(name="红楼梦").delete()

删除匹配到的QuerySet中所有记录,删除的时候要注意on_delete指定的处理方式。

成功返回1,失败返回0

distinct

去除掉重复的数据,如果底层使用的是MySQL,那么不能传递任何参数。

Author.objects.filter(name='曹雪芹').distinct()

上边的代码会筛选出所有name=曹雪芹的记录,但是每条记录的id不一样,所以不是重复的数据不会被删除。

这和SQL中有些不一样,在SQL中,我可以只筛选出某个字段,对该字段进行去重。

切片

在SQL层面实现

有时查找数据,只需要一部分,就可以用切片。

切片操作并不会把所有的数据都取出来,而是在数据库层面使用LIMIT和OFFSET来帮我们完成的。

不能在Manager类上使用,Manager的所有方法都是从QuerySet类中拷贝过来的,除了切片。因此不能用Author.objects.[1:3]之类操作。

但是可以这样使用:

objects.get_queryset()[1:2]

objects.all()[1:2]

也就是说,只要是QuerySet都可以使用切片操作,但是切片之后就不能使用filter方法了。

Django什么时候会将QuerySet转换为SQL去执行

生成一个QuerySet对象并不会马上转换为SQL语句执行。例如 :res=Book.objects.all()print(connection.queries)

把QuerySet转换为SQL的情况:

遍历

使用步长做切片。

一般的切片,并不会转化为SQL。

但是如果在切片的时候指定了步长,就会立即转化为SQL了。

Book.objects.all()[0:3:2] 指定了步长为2。

但是为什么指定了步长就会执行SQL语句呢???

使用len函数

调用len函数来查看QuerySet中总共有多少个对象,所以也需要执行SQL语句查看有多少条数据。

res=Book.objects.all()

length=len(res)

使用list函数

list函数把一个QuerySet对象转换为list对象。

判断:

如果把某个QuerySet对象放在if条件中,也会立马执行SQL语句。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,911评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,014评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,129评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,283评论 1 264
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,159评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,161评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,565评论 3 382
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,251评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,531评论 1 292
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,619评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,383评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,255评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,624评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,916评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,199评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,553评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,756评论 2 335

推荐阅读更多精彩内容