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
的升级版,没错,他们俩一个是在查无此数据后新建一个是更新不存在数据时新建,具体用法同create
,get_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'))
这是一个或查询,满足其中一个条件的数据会被返回。
参考