在Django的ManyToManyField中缓存

时间:2012-12-07 12:50:16

标签: python django many-to-many manytomanyfield django-orm

我在Django中遇到一些缓存问题。到目前为止,我只在运行testsuite时才看到这个问题。问题是有时候(似乎总是在代码的第二次调用时发生),Django不会更新它的缓存或它变得不一致。

通过一些调试提取的代码是:

class Source(models.Model):
    name = models.CharField(max_length = 50)
    quality = models.IntegerField(default = 0)

class Reference(models.Model):
    url = models.URLField()
    source = models.ForeignKey(Source)

    class Meta:
        ordering = ['-source__quality']

class Issue(models.Model):
    references = models.ManyToManyField(Reference)
    master = models.ForeignKey(Reference, related_name = 'mastered_issue_set')

def auto_create(instance):
    issue = Issue.objects.create(master = instance)
    print issue.references.count(), issue.references.all()
    issue.references.add(instance)
    print issue.references.count(), issue.references.all()

在第一次调用时,我正确地得到以下输出:

0 []
1 [<Reference: test>]

然而,在第二次调用auto_create时,Django认为有一个引用,但它没有给我:

0 []
1 []

这种行为当然会打破进一步的代码。知道这里可能出现什么问题或者至少如何调试它?

PS:看起来Reference类的排序导致了这一点。但我仍然不清楚为什么。

2 个答案:

答案 0 :(得分:0)

我无法用sqlite3重现。可能是传入的Reference实例未保存吗?以下是没有打嗝的:

def auto_create(instance):
    issue = Issue.objects.create(master = instance)
    print issue.references.count(), issue.references.all()
    assert issue.references.count()==0, "initial ref count is not null"
    assert len(issue.references.all())==0, "initial ref array is not empty"
    issue.references.add(instance)
    print issue.references.count(), issue.references.all()
    assert issue.references.count()==1, "ref count is not incremented"
    assert len(issue.references.all())==1, "initial ref array is not populated"


def test_auto():
    s = Source()
    s.save()
    r = Reference(source=s)
    r.save()
    auto_create(r)

答案 1 :(得分:0)

最后我发现了造成这个问题的原因。这是我自己的缓存代码,而不是Django的。

我有自定义的源管理器,它返回并缓存了一些标准源:

class SourceManager(models.Manager):
    url_source = None
    def get_generic(self):
        if self.url_source is None:
            self.url_source, created = self.get_or_create(name = 'URL', quality = 0)
        return self.url_source

class Source(models.Model):
    name = models.CharField(max_length = 50)
    quality = models.IntegerField(default = 0)

    objects = SourceManager()

这在应用程序中运行得非常好 - 一旦创建了源代码,管理器会记住它的存在,因为源代码在其生命周期内不会发生变化。然而,在测试中,它们随着整个测试在单个事务中运行然后还原而消失。

我觉得奇怪的是models.ForeignKey没有抱怨获取不存在的对象,但是错误出现了,而source__quality排序时因为底层JOIN SELECT找不到匹配的{{1}对象。