【问题标题】:Caching in Django's ManyToManyField在 Django ManyToManyField 中缓存
【发布时间】:2012-11-25 15:40:28
【问题描述】:

我在 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 类上订购会导致这种情况。但我仍然不清楚为什么。

【问题讨论】:

  • 你能指定auto_create()的参数吗?
  • 这是一个Reference 实例(新创建的)。

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


【解决方案1】:

我无法使用 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)

【讨论】:

  • 如果不保存引用,issue.references.add(...) 将失败。事实上,提取的代码并没有暴露问题,我只是不能在这里发布整个项目,它太大了。我只是在寻找我的代码中可能有问题的指针。使用真正的应用程序,我能够在 SQLite 和 PostgreSQL 后端重现此类问题。
【解决方案2】:

最后我找到了导致这个问题的原因。这是我自己的缓存代码,而不是 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 找不到匹配的Source 对象。

【讨论】:

    猜你喜欢
    • 2013-04-09
    • 2014-01-21
    • 2019-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-12
    • 2020-05-11
    相关资源
    最近更新 更多