如何强制Django忽略任何缓存并重新加载数据? [英] How do I force Django to ignore any caches and reload data?

查看:770
本文介绍了如何强制Django忽略任何缓存并重新加载数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Django数据库模型从未从HTTP请求中调用的进程。该过程应该每隔几秒轮询新的数据,并对其进行一些处理。我有一个睡眠几秒钟的循环,然后从数据库中获取所有未处理的数据。

I'm using the Django database models from a process that's not called from an HTTP request. The process is supposed to poll for new data every few seconds and do some processing on it. I have a loop that sleeps for a few seconds and then gets all unhandled data from the database.

我看到的是,在第一次提取后,该过程永远不会看到任何新的数据。我运行了几个测试,看起来Django正在缓存结果,即使我每次都在构建新的QuerySets。为了验证这一点,我从Python shell中这样做了:

What I'm seeing is that after the first fetch, the process never sees any new data. I ran a few tests and it looks like Django is caching results, even though I'm building new QuerySets every time. To verify this, I did this from a Python shell:

>>> MyModel.objects.count()
885
# (Here I added some more data from another process.)
>>> MyModel.objects.count()
885
>>> MyModel.objects.update()
0
>>> MyModel.objects.count()
1025

如您所见,添加新数据不改变结果数。但是,调用manager的update()方法似乎解决了这个问题。

As you can see, adding new data doesn't change the result count. However, calling the manager's update() method seems to fix the problem.

我找不到关于该update()方法的任何文档,不知道有什么其他的坏

I can't find any documentation on that update() method and have no idea what other bad things it might do.

我的问题是,为什么我看到这个缓存行为,这与 Django docs 说?如何避免这种情况发生?

My question is, why am I seeing this caching behavior, which contradicts what Django docs say? And how do I prevent it from happening?

推荐答案

发现这个问题并找到了两个确定的解决方案,我觉得值得发贴另一个答案。

Having had this problem and found two definitive solutions for it I thought it worth posting another answer.

这是MySQL的默认事务模式的问题。 Django在开始时打开一个事务,这意味着默认情况下,您将看不到数据库中的更改。

This is a problem with MySQL's default transaction mode. Django opens a transaction at the start, which means that by default you won't see changes made in the database.

演示如下

在终端1中运行一个django shell

Run a django shell in terminal 1

>>> MyModel.objects.get(id=1).my_field
u'old'

终端2中的另一个

>>> MyModel.objects.get(id=1).my_field
u'old'
>>> a = MyModel.objects.get(id=1)
>>> a.my_field = "NEW"
>>> a.save()
>>> MyModel.objects.get(id=1).my_field
u'NEW'
>>> 

返回终端1来演示问题 - 我们仍然从数据库中读取旧值。 p>

Back to terminal 1 to demonstrate the problem - we still read the old value from the database.

>>> MyModel.objects.get(id=1).my_field
u'old'

在终端1中演示解决方案

Now in terminal 1 demonstrate the solution

>>> from django.db import transaction
>>> 
>>> @transaction.commit_manually
... def flush_transaction():
...     transaction.commit()
... 
>>> MyModel.objects.get(id=1).my_field
u'old'
>>> flush_transaction()
>>> MyModel.objects.get(id=1).my_field
u'NEW'
>>> 

新数据现在读取

这是一个容易粘贴的文本块中的代码,从docstring

Here is that code in an easy to paste block with docstring

from django.db import transaction

@transaction.commit_manually
def flush_transaction():
    """
    Flush the current transaction so we don't read stale data

    Use in long running processes to make sure fresh data is read from
    the database.  This is a problem with MySQL and the default
    transaction mode.  You can fix it by setting
    "transaction-isolation = READ-COMMITTED" in my.cnf or by calling
    this function at the appropriate moment
    """
    transaction.commit()

替代解决方案是更改My.cnf for MySQL以更改默认事务模式

The alternative solution is to change my.cnf for MySQL to change the default transaction mode

transaction-isolation = READ-COMMITTED

请注意,这是Mysql的一个相对较新的功能并具有二进制日志记录/从事的一些后果。你也可以把它放在django连接序言中,如果你愿意的话。

Note that that is a relatively new feature for Mysql and has some consequences for binary logging / slaving. You could also put this in the django connection preamble if you wanted.

3年后更新

现在,Django 1.6具有在MySQL中启用自动提交这不再是一个问题。以上示例现在可以正常工作,没有$ code> flush_transaction()代码,无论您的MySQL是否在 REPEATABLE-READ (默认)或$ code> READ-COMMITTED 事务隔离模式。

Now that Django 1.6 has turned on autocommit in MySQL this is no longer a problem. The example above now works fine without the flush_transaction() code whether your MySQL is in REPEATABLE-READ (the default) or READ-COMMITTED transaction isolation mode.

在非自动提交模式下运行的以前版本的Django发生了什么是第一个选择语句打开一个事务。因为MySQL的默认模式是 REPEATABLE-READ 这意味着后续的选择语句不会读取数据库的更新 - 因此,需要上面的 flush_transaction()代码停止交易并开始新的交易。

What was happening in previous versions of Django which ran in non autocommit mode was that the first select statement opened a transaction. Since MySQL's default mode is REPEATABLE-READ this means that no updates to the database will be read by subsequent select statements - hence the need for the flush_transaction() code above which stops the transaction and starts a new one.

有仍然是为什么你可能想要使用 READ-COMMITTED 事务隔离的原因。如果你要将终端1放在一个交易中,并且你想看到终端2的写入,你将需要 READ-COMMITTED

There are still reasons why you might want to use READ-COMMITTED transaction isolation though. If you were to put terminal 1 in a transaction and you wanted to see the writes from the terminal 2 you would need READ-COMMITTED.

flush_transaction()代码现在在Django 1.6中生成了一个弃用警告,所以我建议你删除它。

The flush_transaction() code now produces a deprecation warning in Django 1.6 so I recommend you remove it.

这篇关于如何强制Django忽略任何缓存并重新加载数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆