环境
Package | Version |
---|---|
Django | 2.2.6 |
python | 3.6.0 |
django-debug-toolbar | 3.2 |
理解QuerySet
1.QuerySet
懒加载
- 对queryset执行filter, slice, 给函数传参,均不会访问数据库
- queryset加载时,才会访问数据库
2.QuerySet
加载
- Iteration迭代
for u in User.objects.all():
print(u.id)
-
Slicing切片
queryset可以切片,与数组切片一样。
注意:
如果queryset未加载,切片也不会访问数据库(如果切换中有step步长参数,将访问数据库),返回queryset,但是经过切片的queryset不能添加filter,ordering等操作
如果queryset已经加载,切片后返回list -
Pickling/Caching
-
repr()
-
len()
-
list()
-
bool() or if 语句
QuerySet
有缓存
- queryset加载时,不可被调用的属性,会被缓存
- queryset加载时,可被调用的属性,不会被缓存
from blueapps.account.models import User
# 不触发sql查询
users = User.objects.all()
# if语句触发sql查询
if users:
print(users[0].id)
users = User.objects.all()
# 触发一次sql查询
for _u in users:
print(_e.id)
# 使用缓存
for _u in users:
print(_e.username)
user = User.objects.get(id='1')
print(user.get_upper_name()) # 执行数据库查询
print(user.get_upper_name()) # 再执行一次数据库查询
最佳实践
1. 尽量避免读取全部数据,优先使用exists(), count(), only(), []等函数
from blueapps.account.models import User
from django.db import connection
users = User.objects.all()
# 判断queryser是否存在
if users.exits():
pirnt(users[0].id)
users = User.objects.all()
# print(len(users)) 不要使用len()
print(users.count())
# 只取必要的字段,不要取全部的字段
users = User.objects.only('username')
# 使用列表表达式替代fou循环
usernames = [_u.usernmae for _u in users]
# sql
# {'sql': 'SELECT "account_user"."id", "account_user"."username" FROM "account_user"','time': '0.002'}
2. 当queryset非常大时,缓存将占据大量内存,应当避免遍历时,产生大量缓存
以时间换空间,使用iterator避免缓存
users = User.objects.all()
for _u in users.iterator():
print(_u.username)