【Django】QuerySet以及Pickle 序列化在Django中的深度运用详解

2022-12-13 18:29:10 浏览数 (1)

QuerySet

QuerySet本身可以在不访问数据库的情况下构造、过滤、切片或复制和分配。只需要在需要从数据库检索数据或将数据保存到数据库时访问数据库。 可以通过以下方式执行QuerySet:迭代。

代码语言:javascript复制
for e in Entry.objects.all():
    print(e.headline)

QuerySet是迭代的。当第一次迭代它时,它将执行其数据库查询。例如,这将打印数据库中所有条目的标题。

代码语言:javascript复制
async for e in Entry.objects.all():
  results.append(e)

部分如限制QuerySet条目数量中所述,可以使用Python的数组切片语法对QuerySet进行切片。切片未执行的QuerySet通常会返回另一个未执行的Query Set。但是,如果使用切片语法的step参数,Django将执行数据库查询并返回一个列表。对执行的QuerySet进行切片也会返回一个列表。 还要注意,即使对未执行的QuerySet进行切片并返回另一个未执行的Query Set,也不允许对其进行进一步修改(例如,添加更多筛选器或修改排序),因为它无法很好地转换为SQL,也没有明确的含义。

代码语言:javascript复制
entry_list = list(Entry.objects.all())

Pickle序列化/缓存。有关拾取QuerySet的详细信息,请参阅下一节。在本节中,从数据库中读取结果非常重要。 repr()调用repr()时,将执行QuerySet。这是为了方便Python交互式解释器,因此当以交互方式使用API时,可以立即看到结果。 len()调用len()时,将执行QuerySet。正如所期望的,这将返回结果列表的长度。

代码语言:javascript复制
if Entry.objects.filter(headline="Test"):
   print("There is at least one Entry with the headline Test")

注意:如果只需要确定集合中的记录数(而不是实际对象),那么使用SQL SELECT COUNT(*)在数据库级别处理计数将更有效。Django为此提供了count()方法。

Pickle 序列化 QuerySet

如果pickle以序列化QuerySet,这将强制在pickle序列化之前将所有结果加载到内存中。Pickle序列化通常用作缓存的前奏。重新加载缓存的查询集时,希望结果存在并可用(从数据库读取可能需要一些时间,这违反了缓存的目的)。这意味着当取消缓存QuerySet时,它包含缓存时的结果,而不是数据库中当前的结果。 如果只想提取将来从数据库中重新创建QuerySet所需的信息,请提取QuerySet的查询属性。然后,可以使用这样的代码重新创建原始QuerySet(不加载任何结果):

代码语言:javascript复制
>>> import pickle
>>> query = pickle.loads(s)     
>>> qs = MyModel.objects.all()
>>> qs.query = query 
代码语言:javascript复制
>>> import pickle
>>> qs = Blog.objects.values_list('id', 'name')
>>> qs
<QuerySet [(1, 'Beatles Blog')]>
>>> reloaded_qs = Blog.objects.all()
>>> reloaded_qs.query = pickle.loads(pickle.dumps(qs.query))
>>> reloaded_qs
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>

类QuerySet(模型=无,查询=无,使用=无,提示=无) 通常,当与QuerySet交互时,将通过链过滤器使用它。为了实现这一点,大多数QuerySet方法返回一个新的查询集。本节稍后将详细介绍这些方法。 QuerySet类具有以下公共属性,可用于内省: 有序 True如果QuerySet是有序的–有一个order_by()子句或模型的默认排序。否则,这是错误的。 数据库 如果现在执行此查询,将使用数据库。

代码语言:javascript复制
SELECT ...
WHERE NOT pub_date > '2005-1-3'
AND NOT headline = 'Hello'

使用提供的查询表达式列表注释QuerySet中的每个对象。表达式可以是简单值、对模型(或任何相关模型)字段的引用,或计算与QuerySet中的对象相关的对象的聚合表达式(平均值、总和等)。 annotation()的每个参数都是一个注释,将添加到返回的QuerySet中的每个对象。 Django提供的聚合函数在以下聚合函数中进行了描述。 使用关键字参数指定的注释使用关键字作为注释的别名。匿名参数将根据聚合函数的名称和聚合模型字段为其生成别名。只有引用单个字段的聚合表达式才能成为匿名参数。其他所有内容都必须是关键字参数。 例如,如果正在处理日志列表,可能需要确定每个日志中有多少记录:

代码语言:javascript复制
Blog.objects.alias(entries=Count('entry')).annotate(
    entries=F('entries'),
).aggregate(Sum('entries'))
代码语言:javascript复制
Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')
代码语言:javascript复制
Entry.objects.order_by(Coalesce('summary', 'headline').desc())

如果不想在查询中应用任何排序,即使是默认排序,也可以在不带参数的情况下调用order() 可以检查QuerySet有序属性确定查询是否排序。如果QuerySet以任何方式排序,则此属性为true。 每个order_by()调用清除以前的排序。例如,此查询将_排序日期而不是标题:

代码语言:javascript复制
Entry.objects.order_by('headline').order_by('pub_date')

0 人点赞