Django ORM filter的执行时机分享给你

Oct. 10, 2018, 1:01 a.m.

Django 的 ORM 确实是好用,最终还是通过 SQL 去和数据库打交道的,这里需要关注的是 ORM 的语法里的一些细节问题

  • 何时发起查询
  • 经常听到的 lazy loading 懒加载是什么意思

举个例子:

# 假设有这样一个Model用于生物特征登录的控制, 做了简化处理
class Login(models.Model)
        ...
    uid = models.BigAutoField() # 用户的 id
        biosignature = models.CharField() # 这是生物特征数据, 如: 指纹或人脸
    enable = models.BooleanField()  # 是否启用生物特征登录
    expired_time = models.IntegerField()  # 失效时间, 规定时间内未有过登录行为则需要重新绑定
    ...

# 业务上的逻辑一般是这样的
# 1. 先判断 enable
# 2. 再判断 expired_time
# 3. 最后判断 biosignature
# 以上每一步,如果不满足,服务器端都需要提供不同的提示信息给客户端

# === 第1种写法 - sql会执行 3次:
enable_ret = Login.objects.filter(uid=12345, enable=False) # sql 还未执行, 只是定义
if not enable_ret:  # sql 开始执行了, 因为需要用来判断是否有结果
  return '你未启用生物登录功能'

expired_time_ret = Login.objects.filter(uid=12345, expired_time__lt=int(time.time()))
if not expired_time_ret:  # sql 开始执行了
  return '你需要重新绑定'

biosignature_ret = Login.objects.filter(uid=12345, biosignature='FR2455...123VT13')
if not biosignature_ret:  # sql 开始执行了
  return '你的生物特征数据有误'

# === 第2种写法 - sql只执行 1次:
obj = Login.objects.filter(uid=12345) # sql 还未执行, 只是定义

if not obj:  # sql 开始执行了, 因为需要用来判断是否有结果
  return '用户不存在'

if not obj[0].enable:  # 不再查询数据库, 在返回的结果集中操作, 操作的是python对象的数据
  return '你未启用生物登录功能'
if obj[0].expired_time <= int(time.time()): # 同上
  return '你需要重新绑定'
if obj[0].biosignature != 'FR2455...123VT13': # 同上
  return '你的生物特征数据有误'

验证

最好的验证方式是在MySQL中查看,SQL语句的实时情况,方法如下:

# 临时打开
mysql> SET GLOBAL general_log = 'ON'; 
# 设置log文件的路径到桌面
mysql> SET GLOBAL general_log_file = '/Users/lizhaochao/Desktop/mysql/general_log.log'; 

# 使用tail命令来滚动查看log文件的内容
tail -f /Users/lizhaochao/Desktop/mysql/general_log.log

总结

  • 区分 <定义> 和 <使用> 这两个概念
    • 定义指的是把 SQL 语句的内容写好,在 ORM 里就是 Login.objects.filter(uid=12345) 这样的形式
    • 使用指的是你要用结果集来做什么的语句,比如 if queryset 语句,或者取第1个结果 queryset[0] 这样的语句
  • 有了上面的概念,理解懒加载就容易了,懒可以泛指慢慢做,后面才做的行为,所以也就是在使用时才会提交 SQL 查询给数据库
  • 记住:先定义后使用

运行环境

  • Python:3.6
  • Django:2.1.1
  • 个人计算机:iMac
  • 处理器:2.9GHz 四核
  • 内存:8GB
  • software:Jupyter

返回首页