2010-11-27 20 views
1

Si vous avez des modèles:Django - question d'optimisation

class Teacher(models.Model): 
    name = models.CharField(max_length=50) 

class Student(models.Model): 
    age = models.PositiveIntegerField() 
    teacher = models.ForeignKey(Teacher, related_name='students') 

et que vous utilisez comme ceci:

>>> student = Student.objects.get(pk=1) 
>>> student.teacher.name # This hits the database 
'Some Teacher' 
>>> student.teacher.name # This doesn't (``teacher`` is cached on the object) 
'Some Teacher' 

C'est génial. Django met en cache l'objet associé afin que vous puissiez l'utiliser à nouveau sans avoir à abuser de votre base de données.

Mais, si vous l'utilisez comme ceci:

>>> teacher = Teacher.objects.get(pk=1) 
>>> for student in teacher.students.all(): # This hits the database 
...  print(student.age) 
... 
8 
6 
>>> for student in teacher.students.all(): # This does too (obviously) 
...  print(student.age) 
... 
8 
6 

Il n'y a pas de mise en cache ou un accès efficace à des objets connexes cette direction.

Ma question est donc: Y at-il intégré (ou de manière non problématique) pour accéder à l'arrière des objets liés d'une manière efficace (d'une manière en cache), comme vous pouvez dans l'exemple ci-dessus student.teacher?

La raison pour laquelle je veux c'est parce que j'ai un modèle avec plusieurs méthodes qui ont besoin d'accéder aux mêmes objets connexes à plusieurs reprises, donc une page qui devrait avoir 12 requêtes se termine avec environ 30.

Répondre

2

isn Il pas de manière intégrée. J'ai écrit à ce sujet on my blog, avec une technique pour optimiser l'accès aux relations inverses.

+0

excellent! Chaque fois que je rencontre un nouveau problème, vous avez rencontré le même problème bien avant moi. Tu es comme mon Mr Miyagi, même si ironiquement tu t'appelles Daniel :) merci encore. – orokusaki

+0

Est-ce que select_related() ne fonctionne pas dans ce cas-là? – jMyles

+0

@Justin - non, 'select_related' ne fonctionne qu'à l'envers avec les relations' OneToOne', et seulement Django 1.2 +. – orokusaki

1

orokusaki,

Vous avez juste besoin de mettre en cache la queryset comme une variable python

students = teacher.students.all() 

Et puis il suffit d'utiliser les étudiants dans votre pour les boucles.

Voici un lien vers la documentation propre sur cette question spécifique de Django :-)

http://docs.djangoproject.com/en/1.1/topics/db/optimization/#understand-cached-attributes

+0

(nom génial, d'abord) - merci. Le problème est plus que la requête est en cours d'exécution dans plusieurs lieux de contrôle au cours de la même requête, mais de la même classe, donc la réponse était pour moi de créer une version en cache sur le modèle associé réel (par exemple '' foo_teacher._cache_students = teacher.students.all() '' orokusaki