如何禁用 Django 查询缓存?
Posted
技术标签:
【中文标题】如何禁用 Django 查询缓存?【英文标题】:How to disable Django query cache? 【发布时间】:2010-12-25 14:34:04 【问题描述】:在我的 Django 应用程序中,我在我的数据库上重复运行相同的查询(例如每 10 秒)。 然后,我在收到的查询集上创建一个 MD5 总和,并将其与我在上一次运行中创建的 MD5 总和进行比较。如果两者相等,则数据没有改变,网页不需要更新。
当我这样做时,数据库中的数据可能会改变。
但是,查询返回相同的查询集,显然是由于query caching。
如何禁用查询缓存并在数据库上显式执行查询?
【问题讨论】:
How do I force Django to ignore any caches and reload data?的可能重复 【参考方案1】:我遇到了我认为是某种缓存的行为,但结果证明是数据库事务在欺骗我。
我有一个问题,在另一个进程中,项目被添加到数据库中,我想监视另一个进程的进度,所以我打开了一个 django shell 并发出以下命令:
>>> MyData.objects.count()
74674
>>> MyData.objects.count()
74674
该值没有改变,即使它实际上在数据库中。我意识到,至少通过我设置 mysql 和 django 的方式,我处于事务中,并且在我打开事务时只会看到数据库的“快照”。
由于在 django 中使用视图,我已经定义了自动提交行为,这对于每个视图来说都可以只看到一个快照,因为下次调用视图时它将在不同的事务中。但是对于一段没有自动提交的代码,它不会看到数据库中的任何更改,除了在此事务中所做的更改。
只是想我会把这个答案抛给任何可能遇到这种情况的人。
要解决,提交您的事务,可以像这样手动完成:
>> from django.db import transaction
>> transaction.enter_transaction_management()
>> transaction.commit() # Whenever you want to see new data
【讨论】:
非常感谢,当我运行一个监听队列并且必须处理一些事件的命令时,我得到了这个确切的行为,当这种情况发生时,处理器不会找到在命令开始运行后创建的用户跨度> 完美解决了我过去多次发现烦人的问题!非常感谢。【参考方案2】:查询缓存仅适用于 QuerySet。换句话说,如果您两次评估同一个查询集对象,查询缓存将运行。但是如果你每 10 秒执行一次查询,大概是通过一个每次生成一个新进程的 cron,所以 Django 不会缓存任何东西。
如果您重复执行完全相同的查询,您的数据库自己的缓存可能会开始运行。您应该查看您的 DBMS 的文档以了解如何正确管理它。
【讨论】:
虽然正确,但这并没有回答明确指向 django 查询集的问题。 @kekoa 答案与 OP 的问题相匹配。【参考方案3】:您提供的 Django 文档链接暗示以下内容:
>>> print [e.headline for e in Entry.objects.all()]
>>> print [e.pub_date for e in Entry.objects.all()]
创建两个对数据库的查询,同时:
>>> queryset = Poll.objects.all()
>>> print [p.headline for p in queryset] # Evaluate the query set.
>>> print [p.pub_date for p in queryset] # Re-use the cache from the evaluation.
使用查询缓存,因为您访问的是相同的评估结果。
【讨论】:
【参考方案4】:非常感谢您的回答,您的回复让我后退了几步重新思考。
为了在 DBMS 级别上测试缓存,我离开了 Django 并使用了一个 shell 脚本,无论如何我都可以方便地定期从 SQLite db 查询数据,同时我在第二个 shell 会话中添加数据。新数据在我添加后立即出现在定期查询中,因此这里没有查询缓存。
这将范围缩小到 Django 部分。所涉及的代码不是很复杂,一点日志输出和代码审查揭示了问题:用于获取查询集的查询又用于创建 MD5 总和有错误并且始终为空。因此,MD5 和始终相同。确实看起来像一个缓存的结果——数据在变化,但查询集保持不变。 该问题未在应用程序中显示,因为使用了不同的查询来获取那里显示的数据。
经验教训:如果您完全感到困惑,请退后一步,重新考虑您的假设。
再次感谢! :-)
【讨论】:
【参考方案5】:我在 django 版本 1.8 上遇到了这个问题。没有直接的方法可以做到这一点,但是有一些方法可以通过访问数据库而不是缓存来重新评估和执行查询集。我在Django Queryset Documentation找到它
我使用其中一个来处理我的问题。它是查询集的exists()
函数。 len()
和 repr()
也可以使用。他们也为我工作。
例子
queryset = ModelClass.objects.filter(....)
queryset.exists()
#or len(queryset)
#or repr(queryset)
#Now queryset is re-evaluated.
【讨论】:
以上是关于如何禁用 Django 查询缓存?的主要内容,如果未能解决你的问题,请参考以下文章