Django学习笔记之Django QuerySet的方法

一般情况下,我们在写Django项目需要操作QuerySet时一些常用的方法已经满足我们日常大多数需求,比如get、filter、exclude、delete神马的感觉就已经无所不能了,但随着项目但业务逻辑越来越复杂,这几个方法可能就不能很好但满足我们了,所以这时候,最好的办法是神马??对,读文档!这里的读文档不是有业务需求时去查文档,而是要为了阅读文档而阅读文档。以下也是作为我的文档阅读笔记,我记下了一些我以后可能会用到或者一些技巧性提升的东西,好,不废话,正文开始:

首先,我们假设有以下两个model:

class Entry(Model.models):
    ip = models.CharField(max_length=20)
    time = models.DateTimeField()
    black = models.BooleanField(default=False)
class Blog(Model.models):
    title = models.CharField(max_length=100)
    content = models.CharField(max_length=500)
    publish = models.BooleanField(default=False)
    entry = models.ForeignField(Entry, relate_name='entrys')

1、annotate(args, **kwargs)

为queryset增加注解,神马是注解?就是你读出queryset可能会需要一些额外数据要添加进去的时候,你就可以用这个东东咯,使用方法看代码:

>>> q = Blog.objects.annotate(Count('entry'))
# The name of the first blog
>>> q[0].name
'Blogasaurus'
# The number of entries on the first blog
>>> q[0].entry__count
42

Blog model 类本身并没有定义 entry__count 属性,但可以使用注解函式的关系字参数,从而改变注解的命名:

>>> q = Blog.objects.annotate(number_of_entries=Count('entry'))
# The number of entries on the first blog, using the name provided
>>> q[0].number_of_entries
42

2、aggregate(args, *kwargs)

这个参数有点像annotate的反义,annotate返回的是一个包含注解值的queryset,而aggregate则单独返回注解值,返回类型是一个dict,当然,这种方式在文档中叫做聚合查询,具体使用如下:

>>> q = Blog.objects.aggregate(Count('entry'))
{'entry__count': 16}

通过在 aggregate 指定关键字参数,你可以控制返回的聚合名称:

>>> q = Blog.objects.aggregate(number_of_entries=Count('entry'))
{'number_of_entries': 16}

3、defer(*fields)

延后读取字段。啥意思?我读文档时就这感觉。。后来发现是酱紫滴,一个复杂滴model可能你从数据库中读出后根本不需要某些字段,读了又浪费时间浪费空间,怎么办?对!用defer,延后读取,你可以在defer中指定一个或多个字段,也可用链式方法使用defer,它返回对依然是个完整对queryset但其中defer指定但字段并没有真但从数据库读出来,只有当你访问这些延后字段时django才会从数据库读取这些数据,感觉在数据量变大后用这个方法很nice,具体用法如下:

Blog.objects.defer("content").filter(publish=True).defer("title")

不过要注意的是,不能用defer过的字段进行order_by操作,这样做木有作用滴,如果需要清楚defer,只要加个defer(None)就ok啦。

你还阔以defer model中的外键,但是你需要提使用 select_related() 载入关联 model,具体用法:

Blog.objects.select_related().defer("entry__ip", "entry__time")

4、only(*fields)

我想你已经猜到了,一定是defer相反的咯,是啊是啊,没错。only会立即查询指定的字段,但是要注意了,这有坑,only只返回指定的字段,其他木有指定的默认就给defer了哟,所以以下写法是等价滴:

Entry.objects.only('ip')
Entry.objects.defer('time', 'black')

当你使用链式方法调用only时只有最后一个only内的参数会立即返回,其他参数都会被defer,注意这里only的覆盖性~

5、create(**kwargs)

创建并保存对象。一般我们要新建一个model对象时直接使用他的构造函数或者使用.语法赋值,最后调用.save()方法保存。那么在我们已经知道新建这个对象所有必须数据的情况下,其实用create会更快捷,代码看着更干净,起使用方法与构造方法类似,只是不需要调用.save()啦, 例子如下:

p = Entry.objects.create(ip='127.0.0.1', time=<a datetime type object>, black=False)

6、get_or_create(kwargs) 和 update_or_create(kwargs)

嗯,看看就知道这个是create的升级版,没错,他们俩一个是在查无此数据后新建一个是更新不存在数据时新建,具体用法同createget_or_create等效如下过程

try:
    obj = Blog.objects.get(title='test', content='test')
except Blog.DoesNotExist:
    obj = Blog(title='test', content='test')
    obj.save()

注意这两个方法的返回值,他们返回两个东东:

created, obj = get_or_create(**kwargs)

其中created是个bool值,当此方法生成了一个新的model object,此值为True,反之为False,obj则是生成的object或者查到的object实例。

7、latest(field_name=None) 和 earliest(field_name=None)

分别返回指定字段的最新数据与最早数据。

8、first() 和 last()

分别返回queryset的第一项与最后一项,具体用法如下:

p = Blog.objects.order_by('title').first()

等同于:

try:
    p = Blog.objects.order_by('title')[0]
except IndexError:
    p = None

9、update(**kwargs)

用于更新一组数据,但要注意,它不能更新外键, 不能更新切片过的queryset以及不能再被切片的set,用法如下:

Entry.objects.filter(black=False).update(ip='0.0.0.0')

10、delete()

有人肯定要说了,博主你再逗我,这个方法抬头不见低头见,还用你说?!是啊是啊,删除普通数据的时候当然木有什么,但是如果删除外健关系很复杂的object时有木有想过细节?是不是细思极恐 啊#_# 比如,以我们开头的model为例,我删了一个entry实例,那么与它有外健关联的blog实例会怎样?一同被删了?还是保留?保留的话那他对应的entry外健是神马?WTF! 嗯,实话告诉你,默认情况下调用delete()是会删除所有有关的外键对象的(是不是突然感觉自己之前代码里有坑了)所以我们需要详细说说这个方法,如何做才能让他不删除对应的外键或者说按照我们想象的方式进行删除呢?

答案在这里:

django.models 的 on_delete参数,此参数有以下几个可选值:

  • CASCADE:这就是delete()的默认选项,也就是关联删除
  • PROTECT:如果删除的model obj含有外键则引起 ProtectedError
  • SET_NULL:就是把外键置空咯,当然前提是你得设置外键的null=True
  • SET_DEFAULT:就是把外键设为默认咯,当然前提是你得设置外键的default=xxx
  • SET():SET内应是一个函数,用来返回一个外键实例,用法如下:

 def get_sentinel_user():
     return get_user_model().objects.get_or_create(username='deleted')[0]
 class MyModel(models.Model):
     user = models.ForeignKey(settings.AUTH_USER_MODEL,
                              on_delete=models.SET(get_sentinel_user))

11、fields lookups

强大滴django fields lookups,具体可选参数有:

iexact icontains in istartwith gt gte lt lte endwith iendwith range year month day week_day hour minute second insole (ex: search) iregex

其中,首字母带“i”的意思就是不分大小写,如果需要大小写敏感就把“i”去掉啦~其他参数大体从字面意思就知道啦,改天补上详细的例子。

12、Avg、Count、Sum、Max、Min、StdDev、Variance

这些方法就是求数据的相应结果咯,比如avg就是平均值啦,嗯,基本都看得懂,除了后两个,一个是方差,一个是标准差,具体用法其实前文里有,我还是放一下:

q = Blog.objects.annotate(Count('entry'))

13、强大的Q查询与F查询:

嗯,这一部分先留着,总之告诉你很腻害就是了,可以做很复杂的查询,先放个例子:

q = Blog.objects.filter(Q(title='test')|Q(content='hahaha'))

这是一个或查询,满足其中一个条件的数据会被返回。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏应兆康的专栏

Python Web - Flask笔记5

MySQL Workbench是一款专为MySQL设计的ER/数据库建模工具。它是著名的数据库设计工具DBDesigner4的继任者。你可以用MySQL Wor...

19510
来自专栏程序员的SOD蜜

使用操作符重载,生成ORM实体类的SQL条件语句

ORM框架的一个不可或缺的功能就是根据实体类,生成操作数据库的SQL语句,这其中,最难处理的就是那些复杂的SQL条件比较语句。比如,有下面这样一个SQL语句: ...

237100
来自专栏JAVA后端开发

给mybatis添加自动建表,自动加字段的功能

以前项目用惯了hibernate,jpa,它有个自动建表功能,只要在PO里加上配置就可以了,感觉很爽. 但现在用mybatis,发现没有该功能,每次都加个字段...

54130
来自专栏顶级程序员

MySQL 全文索引应用简明教程

本文从以下几个方面介绍下MySQL全文索引的基础知识: MySQL全文索引的几个注意事项 全文索引的语法 几种搜索类型的简介 几种搜索类型的实例 全文索引的几个...

392100
来自专栏简书专栏

Python程序结构2

上面一段代码的运行结果如下,从下面的结果可以看出速度差距为2、3倍左右,当数据量更大时,可能差距更大。:

11530
来自专栏GreenLeaves

SQL学习之高级数据过滤

一、高级数据过滤之IN操作符 IN 操作符用来指定条件范围,范围中的每个条件都可以进行匹配。IN取一组由逗号分隔、括在圆括号中的合法值。代码如下: select...

22350
来自专栏青玉伏案

Oracle常用函数

前一段时间学习Oracle 时做的学习笔记,整理了一下,下面是分享的Oracle常用函数的部分笔记,以后还会分享其他部分的笔记,请大家批评指正。 1.Oracl...

21890
来自专栏JackieZheng

Hadoop阅读笔记(六)——洞悉Hadoop序列化机制Writable

  酒,是个好东西,前提要适量。今天参加了公司的年会,主题就是吃、喝、吹,除了那些天生话唠外,大部分人需要加点酒来作催化剂,让一个平时沉默寡言的码农也能成为一个...

24150
来自专栏JMCui

Hybris IMPEX

1、Impex是基于java Model的一种面向对象的数据操作手段,因此写impex代码前需要理清java Model之间的依赖关系。 2、基本语法:mode...

39260
来自专栏恰童鞋骚年

Hadoop学习笔记—5.自定义类型处理手机上网日志

  假设我们如下一个日志文件,这个文件的内容是来自某个电信运营商的手机上网日志,文件的内容已经经过了优化,格式比较规整,便于学习研究。

8010

扫码关注云+社区

领取腾讯云代金券