html 遍历元组queryset,QuerySet的API

d230ae014485

文字版:

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语句。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值