2010-07-30 15 views
39

De la documentación de Django ...¿Cómo puedo acceder a las propiedades de una tabla "a través" de muchos a muchos desde una plantilla django?

Cuando sólo está tratando con simples relaciones muchos-a-muchos, tales como mezclar y combinar las pizzas y coberturas, un ManyToManyField estándar es todo lo que necesita. Sin embargo, a veces puede necesitar asociar datos con la relación entre dos modelos.

Por ejemplo, considere el caso de una aplicación que rastrea los grupos musicales a los que pertenecen los músicos. Existe una relación de muchos a muchos entre una persona y los grupos de los que son miembros, por lo que podría usar ManyToManyField para representar esta relación. Sin embargo, hay muchos detalles sobre la membresía que podría querer recopilar, como la fecha en que la persona se unió al grupo.

Para estas situaciones, Django le permite especificar el modelo que se utilizará para regular la relación muchos a muchos. A continuación, puede poner campos adicionales en el modelo intermedio. El modelo intermedio está asociado con ManyToManyField utilizando el argumento through para apuntar al modelo que actuará como intermediario. Para nuestro ejemplo músico, el código sería algo como esto:

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) 

Ahora que ha configurado su ManyToManyField utilizar su modelo intermediario (afiliación, en este caso), ya está listo para comienza a crear algunas relaciones de muchos a muchos. Esto se hace mediante la creación de instancias del modelo intermedio:

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>] 

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

Mi pregunta es, ¿cómo puedo configurar mi punto de vista y la plantilla para acceder a estos atributos adicionales. Supongamos que tengo una página de banda y deseo mostrar el nombre de la banda, repetir los registros de membresía y mostrar los nombres y la fecha_unidada.

¿Debo pasar un objeto de banda a la plantilla? ¿O paso los objetos de membresía de alguna manera?

¿Y cómo crearía los bucles for en la plantilla?

Gracias.

+1

yo consideraría acortando extractos de documentos django un poco. Las personas que probablemente respondan probablemente ya estén familiarizadas con ellas y sería más fácil detectar la pregunta real de esa manera. – cji

Respuesta

32

La manera más fácil es simplemente pasar la banda a la plantilla. Las plantillas son capaces de navegar por las relaciones entre los modelos y hay tanto miembros como administradores de conjunto de consultas de membership_set en el Grupo.Así que aquí es cómo lo haría:

vista:

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

plantilla:

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

Eso funciona perfectamente. Intentaba iterar a través de group.membership.all. Necesito leer en _set. ¡Gracias! – Alex

+0

Pero si necesita algo más complejo, es decir, ordenar, filtrar, etc., la práctica estándar es hacerlo en la vista y luego pasarlo a través del contexto. – CpILL

+0

Un punto importante es que el nombre de clase en minúsculas de la tabla directa se usa como "membresía". – MagicLAMP

6

No estoy seguro de si es solo solución o no, pero pasar objetos de relación a la plantilla ciertamente funciona. En su opinión, obtener QuerySet de los objetos de Cuenta:

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

y pasarlo a la plantilla, donde se puede iterar sobre ella con {% for %}

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

Tenga en cuenta que esto no debe realizar ninguna consulta adicional debido a select_related() .

Cuestiones relacionadas