2012-12-07 107 views
3

我在Django中遇到了一些緩存問題。到目前爲止,我只在運行測試套件時纔看到這個問題。問題在於,有時候(這似乎總是在第二次調用代碼時發生),Django不更新它的緩存,或者它變得不一致。在Django的ManyToManyField中緩存

與一些調試抽出代碼是:

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類是造成這種情況。但是我仍然不清楚爲什麼。

+0

你能指定'auto_create()'的參數嗎? – Oleksiy

+0

這是一個''Reference''實例(新創建)。 –

回答

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找不到匹配Source對象。

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) 
+0

如果不保存引用,那麼''''issue.references.add(...)''將會失敗。事實上,提取的代碼不會暴露這個問題,我不能在這裏發佈整個項目,這太大了。我只是在尋找指針,在我的代碼中可能會出錯。使用真正的應用程序,我可以在SQLite和PostgreSQL後端上重現這些問題。 –