为什么Django会返回过时的缓存数据?

Saq*_*Ali 9 python django django-cache django-cache-machine

我有两个Django模型,如下所示,MyModel1&MyModel2:

class MyModel1(CachingMixin, MPTTModel):
    name = models.CharField(null=False, blank=False, max_length=255)
    objects = CachingManager()

    def __str__(self):
        return "; ".join(["ID: %s" % self.pk, "name: %s" % self.name, ] )

class MyModel2(CachingMixin, models.Model):
    name = models.CharField(null=False, blank=False, max_length=255)
    model1 = models.ManyToManyField(MyModel1, related_name="MyModel2_MyModel1")
    objects = CachingManager()

    def __str__(self):
        return "; ".join(["ID: %s" % self.pk, "name: %s" % self.name, ] )
Run Code Online (Sandbox Code Playgroud)

MyModel2有一个ManyToMany字段来MyModel1授权model1

现在看看当我向这个ManyToMany字段添加一个新条目时会发生什么.据Django说,它没有效果:

>>> m1 = MyModel1.objects.all()[0]
>>> m2 = MyModel2.objects.all()[0]
>>> m2.model1.all()
[]
>>> m2.model1.add(m1)
>>> m2.model1.all()
[]
Run Code Online (Sandbox Code Playgroud)

为什么?它似乎绝对是一个缓存问题,因为我看到在数据库表myapp_mymodel2_mymodel1中有一个新条目,用于m2&之间的此链接m1.我应该怎么解决?

e4c*_*4c5 9

真的需要django-cache-machine吗?

MyModel1.objects.all()[0]
Run Code Online (Sandbox Code Playgroud)

粗略地翻译成

SELECT * FROM app_mymodel LIMIT 1
Run Code Online (Sandbox Code Playgroud)

像这样的查询总是很快.无论是从缓存还是从数据库中获取速度,速度都不会有显着差异.

当您使用缓存管理器时,实际上在这里添加了一些开销,这可能会使事情变得更慢.大多数情况下,这种努力将被浪费,因为可能没有缓存命中,如下一节所述.

django-cache-machine如何工作

无论何时运行查询,CachingQuerySet都会尝试在缓存中查找该查询.查询是关键的{prefix}:{sql}.如果它在那里,我们返回缓存的结果集,每个人都很高兴.如果查询不在缓存中,则执行运行数据库查询的正常代码路径.当迭代结果集中的对象时,它们将被添加到一个迭代完成后将被缓存的列表中.

来源:https://cache-machine.readthedocs.io/en/latest/

因此,如果在您的问题中执行的两个查询相同,则缓存管理器将从memcache获取第二个结果集,前提是缓存尚未被无效.

相同的链接解释了缓存键的无效方式.

为了支持轻松缓存失效,我们使用"刷新列表"来标记对象所属的缓存查询.这样,当该对象发生更改时,找到对象的所有查询都将失效.刷新列表将对象键映射到查询键列表.

保存或删除对象时,将删除其刷新列表中的所有查询键.此外,将清除其外键关系的刷新列表.为了避免过时的外键关系,当外键指向的对象无效时,将刷新任何缓存的对象.

很明显,保存或删除对象会导致缓存中的许多对象无效.因此,您通过使用缓存管理器来减慢这些操作.另外值得注意的是,失效文档根本没有提到多个字段.这是一个悬而未决的问题,从你对这个问题的评论来看,很明显你也发现了它.

查克缓存机.缓存所有查询几乎都不值得.它导致各种难以发现的错误和问题.最好的方法是优化表格并微调查询.如果您发现某个特定查询太慢,请手动缓存它.