Django를 사용하여 Triple Join 테이블을 만드는 방법
-
09-06-2019 - |
문제
Django의 내장 모델을 사용하여 어떻게 세 모델 사이에 삼중 조인을 생성할 수 있습니까?
예를 들어:
- 사용자, 역할 및 이벤트가 모델입니다.
- 사용자에게는 많은 역할이 있고 역할에는 많은 사용자가 있습니다.(다대다)
- 이벤트에는 많은 사용자가 있고 사용자에는 많은 이벤트가 있습니다.(다대다)
- 그러나 특정 이벤트에 대해 모든 사용자는 하나의 역할만 가질 수 있습니다.
이것이 모델에서 어떻게 표현될 수 있나요?
해결책
자케라테스 쓴다:
나는 사용자와 역할 사이의 연관 클래스로 역할을 모델링하겠습니다(...)
나는 또한 이 솔루션을 추천하지만 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)
다른 팁
이를 위해 완전히 별도의 모델을 만드는 것이 좋습니다.
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-predefed-model-methods) 또는 신호를 사용하여(http://docs.djangoproject.com/en/dev/topics/signals/)
나는 사용자와 역할 사이의 연관 클래스로 역할을 모델링할 것입니다.
class User(models.Model):
...
class Event(models.Model):
...
class Role(models.Model):
user = models.ForeignKey(User)
event = models.ForeignKey(Event)
그리고 관리자 또는 SQL 제약 조건에서 이벤트당 사용자당 하나의 역할을 적용합니다.
내 Django 모델에 대한 더 빠른 3개 테이블 조인을 찾으려고 노력하는 동안 이 질문을 발견했습니다.기본적으로 Django 1.1은 InnoDB에서 속도가 느릴 수 있는 INNER JOIN을 사용합니다.다음과 같은 쿼리의 경우:
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"
INNER JOIN은 LEFT JOIN에 비해 매우 느릴 수 있습니다.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()]