Как создать таблицу с тройным соединением с Django

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

Например:

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

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

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
10
0
5 892
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

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

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")

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

Разве unique_together = ('user', 'event') не достаточно для одной роли на пользователя на каждое ограничение события?

Amaro Vita 23.04.2019 12:12

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

class User(models.Model):
     ...

class Event(models.Model):
     ...

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

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

Ответ принят как подходящий

зачерат пишет:

I'd model Role as an association class between Users and Roles (...)

Я также рекомендовал бы это решение, но вы также можете использовать некоторый синтаксический сахар, предоставляемый Django: Отношение ManyToMany с дополнительными полями.

Пример:

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)

Это довольно новая возможность в Django (начиная с версии 1.0).

zgoda 17.09.2008 14:05

Пытаясь найти более быстрое объединение трех таблиц для моих собственных моделей Django, я столкнулся с этим вопросом. По умолчанию Django 1.1 использует ВНУТРЕННИЕ СОЕДИНЕНИЯ, которые могут быть медленными на 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 для объединения трех таблиц

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

Другие вопросы по теме