由于官方文档一般讲究『平均发力,面面俱到』,虽然内容是详细,但是对于初学者往往是『不知轻重,找不着北』。本文试图总结一些 Django ORM 中比较常用的东西,力求覆盖全面,实现『花20%的时间,搞定80%的内容』的目的。
【ORM class 的定义】
这个非常简单,基本无脑使用。注意,这里我假设:使用者基本不使用『物理层外键』,外键逻辑再应用层控制(这个话题见仁见智,各有各的选择)。
【创建】
有两者风格,一种是:
# 一开始就直接把属性全部列举出来, 并创建对象
blog_orm = Blog(title="xxx", name="xxx", ...)
blog_orm.save()
复制代码
另一种是:
# 先将对象创建出来,虽然再根据要求(条件),填充对应的属性。
blog_orm = Blog()
blog_orm.title = "xxx"
if some_condition:
blog_orm.name = "yyy"
blog_orm.save()
复制代码
两种方式没有优劣,但是第二种更加常见,因为一般数据库表有许多字段,创建ORM对象时,那个时间点的上下文,是并不能获取到某些属性,这些属性可能是后续根据某些条件生成的,或者依赖一些特定的参数。
【查询】
Django ORM的查询,基本上算是一门小的 DSL 了,而且只适用于 Django ORM,并不能迁移到其他领域,对于个人而言,这种东西,属于价值比较有限的东西,花太多力气学习是不值得的。相比之下,多发点时间了解 SQL ,可能更加有价值,因为它的适用范围更加广泛。
- 记住几个个API。Django ORM的 API非常统一,这是比较好的消息。
.filter(**kw) 正面条件,比如 等于/大于
.exclude(**kw) 方面条件,比如 不能于/不是
Q(**kw) OR 逻辑,比如条件1 或者 条件2,使用形式为: Q(name="xxx") | Q(sex="yyy")
复制代码
- 风格分为两种。
第一种:求出QuerySet。
这是最常用,也最实用的, 因为QuerySet 有非常完备系统的API,后文详述之。如果没有特殊情况,一般使用这种方式
比如:user_qs = User.objects.filter(name="xxx").filter(sex="yyy").exclude(age=22)
第二种:直接求值出来,即 .first() .all()这些方法
这种一般只在特定而且确定的情况下,才去使用,范围比较受限
比如:
user_qs =
one_user_obj = user_qs.first()
all_user_objs = user_qs.all()
复制代码
- 并不需要特别记忆的『Lookup Expression』
无非是映射到SQL的WHERE中的条件而已,用几次就熟悉了。
Django文档,有个专门的链接讲这个东西,即便如此,常用的也就那么几个。
复制代码
- LIMIT OFFSET
这个需要特别发点时间去记忆。
一直不明白,Django 为什么不提供 .offset() .limit() 这样的 API,而是搞成『很照顾Python习惯』的切片方式,
这样,虽然照顾了『Python的习惯』,但是使用中难免有点心智上的负担,因为他的大脑需要自动映射到SQL的 OFFSET/LIMIT,
一直觉得,ORM不应该搞太厚的逻辑,也不要夹带太多私货,一切应该以『照顾SQL的习惯』为基准。
复制代码
【修改】
- 单个修改
这个非常简单易用
user_obj.name = "new_name"
user_obj.save()
复制代码
- 批量修改
对符合某一组查询条件的ORM对象列表,进行批量更新
user_qs =
user_qs.udpate(name="new_name")
复制代码
【删除】
- 单个删除:user_obj.delete()
- 批量删除
user_qs =
user_qs.delete()
复制代码
【事务】
这个绝对是非常重要的,不是因为再Django中这个东西重要,而是因为这个东西本身就重要,跟Django不Django没有半点关系。
再Django中使用,非常简单:
from django.db import transaction
with transaction.atomic():
do_more_stuff()
复制代码