2010-07-30 20 views
39

De la documentation Django ...Comment puis-je accéder aux propriétés d'une table "through" many-to-many à partir d'un template django?

Lorsque vous ne traiter qu'avec des simples nombreux à plusieurs relations telles que le mélange et l'appariement des pizzas et des garnitures, un ManyToManyField type est tout ce dont vous avez besoin. Cependant, vous devrez parfois associer des données à la relation entre deux modèles. Par exemple, considérons le cas d'une application qui suit les groupes musicaux auxquels appartiennent les musiciens. Il existe une relation plusieurs-à-plusieurs entre une personne et les groupes dont elle est membre, vous pouvez donc utiliser ManyToManyField pour représenter cette relation. Cependant, il y a beaucoup de détails sur les membres que vous pourriez vouloir collecter, comme la date à laquelle la personne a rejoint le groupe. Pour ces situations, Django vous permet de spécifier le modèle qui sera utilisé pour gérer la relation plusieurs-à-plusieurs. Vous pouvez ensuite placer des champs supplémentaires sur le modèle intermédiaire. Le modèle intermédiaire est associé à ManyToManyField en utilisant l'argument through pour pointer vers le modèle qui servira d'intermédiaire. Pour notre exemple musicien, le code ressemblerait à quelque chose comme ceci:

class Person(models.Model): 
    name = models.CharField(max_length=128) 

    def __unicode__(self): 
     return self.name 

class Group(models.Model): 
    name = models.CharField(max_length=128) 
    members = models.ManyToManyField(Person, through='Membership') 

    def __unicode__(self): 
     return self.name 

class Membership(models.Model): 
    person = models.ForeignKey(Person) 
    group = models.ForeignKey(Group) 
    date_joined = models.DateField() 
    invite_reason = models.CharField(max_length=64) 

Maintenant que vous avez configuré votre ManyToManyField utiliser votre modèle intermédiaire (d'adhésion, dans ce cas), vous êtes prêt à commencer à créer des relations plusieurs-à-plusieurs. Vous faites cela en créant des instances du modèle intermédiaire:

ringo = Person.objects.create(name="Ringo Starr") 
paul = Person.objects.create(name="Paul McCartney") 
beatles = Group.objects.create(name="The Beatles") 

m1 = Membership(person=ringo, group=beatles, 
...  date_joined=date(1962, 8, 16), 
...  invite_reason= "Needed a new drummer.") 

m1.save() 

beatles.members.all() 
[<Person: Ringo Starr>] 

ringo.group_set.all() 
[<Group: The Beatles>] 

m2 = Membership.objects.create(person=paul, group=beatles, 
...  date_joined=date(1960, 8, 1), 
...  invite_reason= "Wanted to form a band.") 

beatles.members.all() 
[<Person: Ringo Starr>, <Person: Paul McCartney>] 

source: http://docs.djangoproject.com/en/dev/topics/db/models/#intermediary-manytomany

Ma question est, comment puis-je configurer mon point de vue et le modèle pour accéder à ces attributs supplémentaires. Dites que j'ai une page de groupe et que je veux afficher le nom du groupe, parcourir les dossiers d'adhésion et les noms d'affichage et date_joint.

Devrais-je transmettre un objet bande au modèle? Ou est-ce que je passe les objets d'adhésion en quelque sorte?

Et comment créer les boucles for dans le modèle?

Merci.

+1

Je considérerais raccourcissant des extraits de documents django un peu. Les personnes susceptibles de répondre sont probablement déjà familières avec elles et il serait plus facile de repérer une question réelle de cette façon. – cji

Répondre

32

La méthode la plus simple consiste simplement à passer la bande au modèle. Les modèles sont capables de naviguer dans les relations entre les modèles et il existe à la fois des membres et des gestionnaires d'ensembles de queues membership_set sur le groupe.Voici donc comment je le ferais:

Vue:

def group_details(request, group_id): 
    group = get_object_or_404(Group, pk=group_id) 
    return render_to_response('group_details.html', 
           {'group': group}) 

modèle:

<h2>{{ group.name }}</h2> 
{% for membership in group.membership_set.all %} 
    <h3>{{ membership.person }}</h3> 
    {{ membership.date_joined }} 
{% endfor %} 
+2

Cela fonctionne parfaitement. J'essayais itérer par group.membership.all. Je dois lire sur _set. Merci! – Alex

+0

Mais si vous avez besoin de quelque chose de plus complexe, par exemple commander, filtrer, etc., la pratique standard consiste à le faire dans la vue, puis à le transmettre via le contexte. – CpILL

+0

Un point important est que le nom de la classe en minuscules de la table à travers est utilisé "adhésion" ,. – MagicLAMP

6

Je ne suis pas sûr que ce soit seulement une solution ou non, mais les objets de relation de passage au modèle fonctionnent certainement. Selon vous, obtenir QuerySet d'objets d'adhésion:

rel = Membership.objects.filter(group = your_group).select_related() 

et le transmettre à modèle, où vous pouvez parcourir avec {% for %}

{% for r in rel %} 
    {{ r.person.name }} joined group {{ r.group.name }} on {{ r.date_joined }}<br /> 
{% endfor %} 

Notez que cela ne devrait pas effectuer des requêtes supplémentaires en raison de select_related() .