2016-02-15 1 views
1

J'ai deux modèles - Note et Pinboard - avec une relation many to many dans une application Django. Ces deux modèles sont liés par un autre modèle - Pin - afin que je puisse stocker des informations supplémentaires sur la relation.Comment commander par un champ de la table `through` pour une relation M2M dans Django?

Je veux montrer les liées Note cas dans le DetailView pour Pinboard. Ce n'est pas le problème. Mais je veux prefetch les notes et commander eux sur le champ position du tableau through.

Des conseils sur comment archiver ceci (prefetch + ordering sur la troisième table)?

Exemple

C'est ce que j'ai jusqu'à présent ... il fonctionne dans le sens que je n'ai pas à interroger pour chaque entrée, mais je l'ai trouvé aucun moyen de commander la note cas par leur position sans plus de requêtes pour chaque instance.

modèles

from django.db import models 


class Note(models.Model): 

    title = models.CharField(max_lenght=200) 

    content = models.TextField() 


class Pinboard(models.Model): 

    title = models.CharField(max_lenght=200) 

    notes = models.ManyToManyField(
     Note, blank=True, related_name='pinboards', through='Pin' 
    ) 


class Pin(models.Model): 

    class Meta: 
     ordering = ['position', ] 
     get_latest_by = 'position' 

    pinboard = models.ForeignKey(Pinboard, related_name='note_pins') 

    note = models.ForeignKey(Note, related_name='pinboard_pins') 

    position = models.PositiveSmallIntegerField(default=0) 

Voir

from django.views.generic import DetailView 


class PinboardDetailView(DetailView): 

    model = Pinboard 

    queryset = Pinboard.objects.prefetch_related('notes') 

Modèle

{% extends 'base.html' %} 
{% block content %} 
<h1>{{ pinboard.title }}</h1> 
{% if pinboard.notes.all.exists %} 
    <ol> 
    {% for note in pinboard.notes %} 
     <li>{{ note.title }}</li> 
    {% endfor %} 
    </ol> 
{% else %} 
    <p>Nothing here yet…</p> 
{% endif %} 
{% endblock content %} 

Répondre

3

Je vous suggère d'utiliser un Prefetch object.

class PinboardDetailView(DetailView): 
    model = Pinboard 
    queryset = Pinboard.objects.prefetch_related(
     Prefetch(
      'notes', 
      Note.objects.order_by('pinboard_pins__position'), 
     ) 
    ) 

Par ailleurs, vous n'avez pas besoin d'utiliser prefetch_related du tout sur un DetailView car il entraînera le même nombre de requêtes.

Plus, since you're already fetching the pinboard.notes Je vous suggère d'utiliser {% if pinboard.notes.all %} au lieu de {% if pinboard.notes.all.exists %}.

+2

Pas de magie ici :) La méthode 'prefetch_related' aide à résoudre le problème de la requête N + 1 mais dans ce cas N = 1. Voir https://stackoverflow.com/questions/97197/what-is-the-n1- sélectionne-issue –