2012-03-14 5 views
2

J'ai un modèle de « facture » avec une méthode« avec » problèmes d'étiquette dans django

def item_objects(self): 
    return self.invoiceitem_set.filter(kind='item') 

J'ai alors un modèle avec ce modèle dans son contexte « facture »

dans ce modèle que j'utilise un tag pour essayer de cache item_objects

{% with item_object=invoice.item_objects%} 
    {{item_object}} 
    {{item_object}} 
{% endwith %} 

Quelle que soit je frappe encore la base de données pour chaque fois que j'appelle {{}} item_object

Qu'est-ce que je fais mal?

Répondre

1

Votre code simplifié est susceptible de masquer le problème, car le comportement que vous décrivez ne devrait pas se produire. L'objectif entier de la balise de modèle with est de mettre en cache les résultats d'une méthode coûteuse pour une utilisation ultérieure.

Cependant, votre méthode, item_objects, retourne un QuerySet, et lorsque vous attribuez à item_object, il est encore un QuerySet. QuerySet s sont paresseux, donc jusqu'à présent, aucun accès à la base de données n'a été fait. En conséquence, en fonction de ce que vous faites avec item_object, vous pouvez avoir un impact négatif sur les performances de la requête.

Par exemple, ce qui suit se traduira par deux requêtes à la DB, même si vous avez affaire à un cache QuerySet:

{{ item_object.count }} 
{{ item_object|first }} 

Vous devez faire attention à ce que les opérations que vous effectuez sur QuerySets et quel ordre. Par exemple, si vous savez que vous allez boucler le queryset à un moment donné, mais que vous avez besoin d'un compte en premier, il est plus efficace d'utiliser {{ item_object|length }} au lieu de {{ item_object.count }}

+0

en utilisant l'outil de débogage je vois que pour chaque {{ item_object}} Je frappe le db. Je ne regarde pas le compte ou quelque chose d'autre. {{item_object}} Voici le template http://pastebin.com/PJQFYYE6 –

+0

En référençant le jeu de requête lui-même appelle '__repr__'. Django force probablement une nouvelle requête chaque fois que la représentation dépend des résultats en temps réel. Cependant, ce n'est pas quelque chose que vous feriez réellement dans votre modèle (c'est-à-dire que vous allez faire une boucle dans le jeu de requête ou effectuer d'autres opérations dessus comme un compte). Si vous réalisez quelque chose de concret, vous ne devriez plus voir plusieurs hits dans la BD. –

+0

Chris a raison. Je vous recommande de regarder la récente session [Django In Depth] de James Bennett (http://pyvideo.org/video/610/django-in-depth) à Pycon dans laquelle il explique ce qui déclenche l'évaluation d'un QuerySet. De plus, en changeant 'invoice.item_objects' à' 'nvoice.item_objects.all', on évaluerait le jeu de requête une seule fois. – roam