2008-09-16 16 views
9

Utilizando los modelos integrados de Django, ¿cómo se crearía una unión triple entre tres modelos?Cómo crear una tabla de triple unión con Django

Por ejemplo:

  • usuarios, roles, y los acontecimientos son los modelos.
  • Los usuarios tienen muchos roles y roles en muchos usuarios. (ManyToMany)
  • Los eventos tienen muchos usuarios y muchos eventos. (ManyToMany)
  • Pero para cualquier Evento dado, cualquier Usuario puede tener solo un Rol.

¿Cómo se puede representar esto en el modelo?

Respuesta

8

zacherates escribe:

Me modelo a seguir como una clase de asociación entre los usuarios y las funciones (...)

También me recomendaría mucho esta solución, pero se puede también use un poco de azúcar sintáctica proporcionada por Django: ManyToMany relation with extra fields.

Ejemplo:

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

class Event(models.Model): 
    name = models.CharField(max_length=128) 
    members = models.ManyToManyField(User, through='Role') 

    def __unicode__(self): 
     return self.name 

class Role(models.Model): 
    person = models.ForeignKey(User) 
    group = models.ForeignKey(Event) 
    date_joined = models.DateField() 
    invite_reason = models.CharField(max_length=64) 
+0

Esto es bastante nuevo en Django (desde 1.0). – zgoda

3

Yo recomendaría simplemente crear un modelo completamente separado para esto.

class Assignment(Model): 
    user = ForeignKey(User) 
    role = ForeignKey(Role) 
    event = ForeignKey(Event) 

Esto le permite hacer todas las cosas de modelo habitual, como

user.assignment_set.filter(role__name="Chaperon") 
role.assignment_set.filter(event__name="Silly Walkathon") 

Lo único que queda es para hacer cumplir su restricción de una sola función por usuario-por-evento. Puede hacer esto en la clase de asignación, ya sea reemplazando el método save (http://docs.djangoproject.com/en/dev/topics/db/models/#overriding-predefined-model-methods) o el uso de señales (http://docs.djangoproject.com/en/dev/topics/signals/)

0

Me modelo a seguir como una clase de asociación entre los usuarios y las funciones, por lo tanto,

class User(models.Model): 
    ... 

class Event(models.Model): 
    ... 

class Role(models.Model): 
    user = models.ForeignKey(User) 
    event = models.ForeignKey(Event) 

E imponer el único rol por usuario por evento en un administrador o restricciones de SQL.

0

Mientras trata de encontrar una mesa de tres más rápido se unen para mis propios modelos de Django, me encontré con esta pregunta. De forma predeterminada, Django 1.1 usa INNER JOINs que pueden ser lentas en InnoDB. Para una consulta como:

def event_users(event_name): 
    return User.objects.filter(roles__events__name=event_name) 

esto podría crear el siguiente SQL:

SELECT `user`.`id`, `user`.`name` FROM `user` INNER JOIN `roles` ON (`user`.`id` = `roles`.`user_id`) INNER JOIN `event` ON (`roles`.`event_id` = `event`.`id`) WHERE `event`.`name` = "event_name" 

El uniones interiores puede ser muy lento en comparación con LEFT JOIN.Una consulta aún más rápido se puede encontrar en la respuesta de gimg1: Mysql query to join three tables

SELECT `user`.`id`, `user`.`name` FROM `user`, `roles`, `event` WHERE `user`.`id` = `roles`.`user_id` AND `roles`.`event_id` = `event`.`id` AND `event`.`name` = "event_name" 

Sin embargo, tendrá que utilizar una consulta SQL personalizada: https://docs.djangoproject.com/en/dev/topics/db/sql/

En este caso, se vería algo como:

from django.db import connection 
def event_users(event_name): 
    cursor = connection.cursor() 
    cursor.execute('select U.name from user U, roles R, event E' \ 
        ' where U.id=R.user_id and R.event_id=E.id and E.name="%s"' % event_name) 
    return [row[0] for row in cursor.fetchall()] 
Cuestiones relacionadas