2012-12-07 3 views
3

Je suis confronté à un problème de mise en cache dans Django. Jusqu'à présent, j'ai vu ce problème uniquement lors de l'exécution de testsuite. Le problème est que parfois (il semble que cela arrive toujours lors de la deuxième invocation du code), Django ne met pas à jour son cache ou il devient incohérent.Mise en cache dans ManyToManyField de Django

Le code extrait avec un certain débogage est:

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() 

Au premier appel, je reçois correctement la sortie suivante:

0 [] 
1 [<Reference: test>] 

Cependant deuxième appel à auto_create, Django pense qu'il ya une référence, mais il ne me le donne pas:

0 [] 
1 [] 

Ce comportement brise bien sûr le code. Une idée de ce qui peut mal se passer ici ou du moins comment le déboguer? PS: Cela ressemble à une commande sur la classe Reference qui en est la cause. Mais je ne comprends toujours pas pourquoi.

+0

pouvez-vous spécifier les arguments pour 'auto_create()'? – Oleksiy

+0

C'est une instance '' Reference'' (nouvellement créée). –

Répondre

0

En fin de compte, j'ai trouvé ce qui cause ce problème. C'était mon propre code de cache plutôt que celui de Django.

j'avais gestionnaire personnalisé Source en place, qui est retourné et mis en mémoire cache une source standard:

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() 

Cela fonctionne parfaitement bien dans l'application - une fois que la source est créée, le gestionnaire, il se souvient de son existence que les sources ne change pas au cours de leur vie. Cependant, dans les tests, ils disparaissent car l'ensemble du test est exécuté en une seule transaction et ensuite retourné.

Ce que je trouve étrange est que models.ForeignKey ne se plaignaient pas faire l'objet non existant, mais l'erreur est apparue plus tard, lors du tri par source__quality comme SELECT underlaying REJOIGNEZ n'a pas pu trouver l'objet correspondant à Source.

0

Je n'étais pas capable de reproduire avec sqlite3. Se pourrait-il que l'instance de Reference transmise ne soit pas enregistrée? Ce qui suit couru sans un hoquet:

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

Si la référence ne pouvait pas être enregistrée, '' issue.references.add (...) '' aurait échoué. Et en effet le code extrait n'expose pas le problème, je ne peux pas poster tout le projet ici c'est trop énorme. Je suis simplement à la recherche de pointeurs qui pourraient être mauvais dans mon code. Avec l'application réelle, je suis capable de reproduire de tels problèmes sur les backends SQLite et PostgreSQL. –