2008-09-16 7 views
9

Используя встроенные модели Django, как создать тройное соединение между тремя моделями.Как создать таблицу с тройным соединением с Django

Например:

  • Пользователи, Роли и события являются модели.
  • Пользователи имеют много ролей и ролей многих пользователей. (ManyToMany)
  • События имеют много пользователей и пользователей много событий. (ManyToMany)
  • Но для любого данного события любой пользователь может иметь только одну роль.

Как это можно представить в модели?

ответ

8

zacherates пишет:

я модель роли как класс ассоциации между пользователями и ролями (...)

Я также reccomed это решение, но вы можете также используют некоторый синтаксический сахар, предоставленный Django: ManyToMany relation with extra fields.

Пример:

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

Это совершенно новое в Django (начиная с версии 1.0). – zgoda 2008-09-17 10:05:13

3

Я бы рекомендовал просто создать совершенно отдельную модель для этого.

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

Это позволяет делать все обычные модели вещи, такие как

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

Единственное, что осталось, чтобы обеспечить соблюдение вашей одной ролевой каждого пользователя-в-случае ограничение. Вы можете сделать это в классе уступке либо переопределение метода сохранения (http://docs.djangoproject.com/en/dev/topics/db/models/#overriding-predefined-model-methods) или с помощью сигналов (http://docs.djangoproject.com/en/dev/topics/signals/)

0

я модель роли как класс ассоциации между пользователями и ролями, таким образом,

class User(models.Model): 
    ... 

class Event(models.Model): 
    ... 

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

И применяйте одну роль для каждого пользователя на событие либо в менеджере, либо в SQL-ограничениях.

0

При попытке найти более быстрый три стола присоединиться для моих собственных моделей Django, я наткнулся на этот вопрос. По умолчанию Django 1.1 использует INNER JOINs, который может замедляться на InnoDB. Для запроса типа:

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

это может создать следующий 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" 

внутренние объединения может быть очень медленным по сравнению с ЛЕВЫЙ соединениями.Еще быстрее запрос может быть найден в ответ 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" 

Однако, вам нужно будет использовать пользовательские SQL-запрос: https://docs.djangoproject.com/en/dev/topics/db/sql/

В этом случае, это будет выглядеть примерно так:

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