2009-12-11 5 views
20

Dans mon application Django, j'exécute à plusieurs reprises la même requête sur ma base de données (par exemple toutes les 10 secondes). Ensuite, je crée une somme MD5 sur le jeu de requête que je reçois et je compare cela à la somme MD5 que j'ai créée lors de la précédente exécution. Si les deux sont égaux, les données n'ont pas changé et la page Web n'a pas besoin d'être mise à jour.Comment désactiver le cache de requête Django?

Pendant que je fais cela, les données dans la base de données peuvent changer.

Cependant, la requête renvoie le même jeu de requête, apparemment dû à query caching. Comment puis-je désactiver le cache de requête et exécuter explicitement la requête sur la base de données?

+0

double possible de [Comment forcer Django à ignorer les caches et recharger les données?] (Http://stackoverflow.com/questions/3346124/how-do-i-force- django-to-ignore-caches-and-reload-data) –

Répondre

41

J'ai rencontré un comportement que je pensais être une sorte de mise en cache, mais il s'est avéré que les transactions de base de données me trompaient.

J'ai eu le problème où dans un autre processus, des éléments ont été ajoutés à la base de données, et je voulais suivre les progrès de l'autre processus, donc j'ai ouvert une coquille de django et a publié ce qui suit:

>>> MyData.objects.count() 
74674 

>>> MyData.objects.count() 
74674 

La valeur ne changeait pas, même si elle se trouvait réellement dans la base de données. Je me suis rendu compte qu'au moins avec la façon dont j'avais MySQL & configuration django que j'étais dans une transaction et verrait seulement un "instantané" de la base de données au moment où j'ai ouvert la transaction. Comme avec les vues dans django, j'avais un comportement autocommit défini, c'était bien pour chaque vue de ne voir qu'un snapshot, car la prochaine fois qu'une vue était appelée, elle serait dans une transaction différente. Mais pour un morceau de code qui ne commit pas automatiquement, il ne verrait aucun changement dans la base de données, sauf ceux qui ont été faits dans cette transaction. Je pensais juste que je jetterais cette réponse pour tous ceux qui pourraient venir sur cette situation.

Pour résoudre, fondez votre transaction, qui peut être fait manuellement comme ceci:

>> from django.db import transaction 
>> transaction.enter_transaction_management() 
>> transaction.commit() # Whenever you want to see new data 
+2

Merci beaucoup, j'ai eu ce comportement exact lors de l'exécution d'une commande qui écoute une file d'attente et doit traiter certains événements, quand le processeur ne trouve pas les utilisateurs créés après l'exécution de la commande – victorcampos

+1

A 'transaction.commit_unless_managed()' a également travaillé pour moi. –

+1

Réponse parfaite pour un problème que j'ai trouvé énervant tant de fois dans le passé! Merci beaucoup. – Sarang

6

Le lien que vous fournissez à la documentation Django implique que les éléments suivants:

>>> print [e.headline for e in Entry.objects.all()] 
>>> print [e.pub_date for e in Entry.objects.all()] 

crée deux requêtes à la base de données, tandis que:

>>> queryset = Poll.objects.all() 
>>> print [p.headline for p in queryset] # Evaluate the query set. 
>>> print [p.pub_date for p in queryset] # Re-use the cache from the evaluation. 

utilise le cache de requêtes, que vous accédez à la mêmes résultats d'évaluation.

9

La mise en cache de requête s'applique uniquement au sein de un QuerySet. En d'autres termes, si vous évaluez deux fois le même objet de l'ensemble de requêtes, la mise en cache des requêtes fonctionnera. Mais si vous faites une requête toutes les 10 secondes, c'est probablement via un cron qui engendre un nouveau processus à chaque fois, donc il n'y a aucun moyen pour que Django cache tout.

Il est possible que le cache de votre base de données entre en action si vous exécutez à plusieurs reprises la même requête. Vous devriez regarder la documentation de votre SGBD pour voir comment le gérer correctement.

+1

Bien que ce soit correct, cela ne répond pas à la question qui pointe clairement vers le queryset de django. La réponse de @kekoa correspond à la question de l'OP. – sberder

1

Merci beaucoup pour vos réponses, vos réponses m'ont fait prendre quelques pas en arrière et repenser. Pour tester la mise en cache au niveau SGBD, je suis parti de Django et j'ai utilisé un script shell que j'avais de toute façon pour interroger périodiquement les données d'un DB SQLite, pendant que j'ajoutais des données dans une seconde session shell. Les nouvelles données apparaissaient dans les requêtes périodiques juste après les avoir ajoutées, donc pas de mise en cache des requêtes ici.

Ceci l'a réduit à la partie Django. Le code impliqué n'est pas très complexe et une petite sortie de log et une revue de code ont révélé le problème: La requête utilisée pour obtenir le queryset utilisé à son tour pour créer la somme MD5 avait une erreur et était toujours vide. Par conséquent, la somme MD5 était toujours la même. En effet, ressemblait à un résultat mis en cache - les données changent, mais le jeu de requête reste le même. Le problème ne s'est pas affiché dans l'application, car une requête différente a été utilisée pour obtenir les données qui y sont affichées.

Leçon apprise: Si vous êtes complètement perplexe, prenez du recul et repensez vos hypothèses.

Merci encore! :-)

0

J'ai rencontré ce problème sur la version 1.8 django. Il n'y a pas de moyen direct de le faire, mais il existe des moyens de réévaluer et d'exécuter le jeu de requête en accédant à la base de données au lieu du cache. Je l'ai trouvé dans Django Queryset Documentation

J'ai utilisé l'un d'entre eux pour gérer mon problème. C'est exists() fonction des jeux de requête. len() et repr() peuvent également être utilisés. Ils ont travaillé pour moi aussi.

Exemple

queryset = ModelClass.objects.filter(....) 
queryset.exists() 

#or len(queryset) 
#or repr(queryset) 

#Now queryset is re-evaluated. 
Questions connexes