Si mes modèles ressemblent à:
class Publisher(models.Model):
pass
class Book(models.Model):
publisher = models.ForeignKey(Publisher)
class Page(models.Model):
book = models.ForeignKey(Book)
et je voudrais obtenir le jeu de requêtes pour Publisher
je fais Publisher.object.all()
. Si je veux m'assurer de faire une prélecture, je peux faire:
Publisher.objects.all().prefetch_related('book_set')`
Mes questions sont:
select_related
Ou dois-je utiliser prefetch_related
?page_set
? Cela ne fonctionne pas:Publisher.objects.all().prefetch_related('book_set', 'book_set_page_set')
Non, vous ne pouvez pas utiliser select_related
Pour une relation inverse. select_related
Fait une jointure SQL, donc un seul enregistrement du jeu de requêtes principal doit en référencer exactement un dans la table associée (champs ForeignKey
ou OneToOne
). prefetch_related
Fait en fait une deuxième requête totalement distincte, met les résultats en cache, puis "les joint" dans le jeu de requêtes en python. Il est donc nécessaire pour les champs ManyToMany
ou inverses ForeignKey
.
Avez-vous essayé deux traits de soulignement pour effectuer les pré-prélèvements à plusieurs niveaux? Comme ceci: Publisher.objects.all().prefetch_related('book_set', 'book_set__page_set')
Depuis Django 1.7, les instances de Django.db.models.Prefetch
la classe peut être utilisée comme argument de .prefetch_related
. Prefetch
le constructeur d'objet a un argument queryset
qui permet de spécifier des prélèvements imbriqués sur plusieurs niveaux comme celui-ci:
Project.objects.filter(
is_main_section=True
).select_related(
'project_group'
).prefetch_related(
Prefetch(
'project_group__project_set',
queryset=Project.objects.prefetch_related(
Prefetch(
'projectmember_set',
to_attr='projectmember_list'
)
),
to_attr='project_list'
)
)
Il est stocké dans des attributs avec _list
suffixe car j'utilise ListQuerySet
pour traiter les résultats de la prélecture (filtre/ordre).