Django使用分页删除查询集,而不是捕获集合的所有部分
Posted
技术标签:
【中文标题】Django使用分页删除查询集,而不是捕获集合的所有部分【英文标题】:Django deleting querysets with paging, not catching all parts of the set 【发布时间】:2018-01-23 01:15:07 【问题描述】:我有一个奇怪的问题,我不太能解释。
我有一个 django 项目,周围有一些陈旧的物品。例如,假设我的对象看起来像这样:
class blog_post(models.Model):
user_account = models.ForeignKey('accounts.Account')
text = models.CharField(max_length=255)
authors = models.ManyToManyField(author)
created = models.DateTimeField(blank=True, null=True)
这不是我模型的精确副本,但足够接近。
我创建了一个管理命令来构建这些对象的有序查询集,然后使用分页器删除
我的命令看起来像这样:
all_accounts = Account.objects.all()
for act in all_accounts.iterator():
stale_objects = blog_post.objects.filter(user_account=act,
created=django.utils.timezone.now() - datetime.timedelta(days=7))
paginator = Paginator(stale_objects.order_by('id'), 100)
for page in range(1, paginator.num_pages + 1):
page_stale_objects = blog_post.objects.filter(id__in=paginator.page(page).object_list.values_list('id'))
page_stale_objects.delete()
我遇到的问题是,在我用我的命令删除这些对象后,仍然有符合查询集参数但没有被删除的对象。因此,我必须运行该命令 3 次以上才能正确找到并删除所有对象。
我首先发现我的日期范围奇怪地位于 DateTime 的边缘,因此在我的命令时间过后 1 周后不久就没有捕捉到对象。情况并非如此,我已经从查询集中删除了 created=... 过滤器,并且得到了相同的结果。
为什么我的查询集在该命令第一次运行时没有捕获所有对象?没有过多的对象,最多约 30,000 行。
【问题讨论】:
Paginator 分页您的数据。我假设如果您删除page_stale_objects
,则只会删除 1 页(这意味着您找到的对象数量超过了分页器的 per_page
值)
【参考方案1】:
查询集的分页被转换为连续的 LIMIT/OFFSET 调用。所以,考虑一下顺序:
获取偏移量为 0 且限制为 20 的项目 删除那些项目 获取下一页,即偏移 21 处的 20 个项目但是等等!一旦我们删除了第一组,查询集现在再次从 0 开始。跳过现在从 0 到 20 的项目。
解决方案是,不要这样做。分页用于显示对象,而不是删除它们。
【讨论】:
啊,是的,这是我通过更多测试开始得出的结论。谢谢。【参考方案2】:如果您只想删除查询集,我不明白您为什么要使用分页器。如果我错了,请纠正我,但看起来您正在执行以下操作:
获取查询集 按 id 对该查询集进行排序 分页 从每个列表中获取对象 删除它们什么时候可以这样做:
获取查询集 删除查询集如果您有很多对象,这将极大地提升性能。
所以,我建议你这样做:
stale_objects = blog_post.objects.filter(...)
stale_objects.delete()
希望对你有帮助!
【讨论】:
这并没有真正尝试回答核心问题,而且我已经展示了对查询集删除的理解。但是,为了回答你的问题,我这样做有几个原因,1)在此过程中还有其他相关对象正在更新或删除,2)在大型查询集上使用 delete() 需要更长的时间与一次分页和删除一个子集相比,删除。我已经对此进行了多次测试,发现它适用于我的所有案例。以上是关于Django使用分页删除查询集,而不是捕获集合的所有部分的主要内容,如果未能解决你的问题,请参考以下文章