테이블 간의 관계는 many-to-one, many-to-many, one-to-one 3가지로 나타낼 수 있다. 이 세가지로 모든 관계를 나타낼 수 있다.
그 중 ForeignKey
는 Many-to-one을 나타냄.
자동차 회사와 그 회사가 만들어내는 자동차의 관계. 현대(one)는 아반떼, 그랜져, 제네시스 등(many)를 갖고 있다. 그러한 관계를 Many-to-one이라고 한다.
class Manufacturer(models.Model):
name = models.CharField(max_length=60)
def __str__(self):
return self.name
class Car(models.Model):
manufacturer = models.ForeignKey(
Manufacturer,
on_delete=models.CASCADE,
)
name = models.CharField(max_length=50)
def __str__(self):
return self.name
장고가 데이터베이스의 필드를 ForeignKey필드로 만들어줄 때 필드이름에 _id를 붙여서 이름을 만든다. 따라서 Car의 foreignKey 필드는 manufacturer_id라는 이름의 테이블이 된다.
만약에 같은 클래스안에서 many-to-one을 형성하는 경우를 생각해보자. 예를 들면, 선생과 학생이 될 수 있다. 다 같은 인간이지만 그 안에서 인간끼리의 관계가 형성될 수 있다는 의미이다. 이러한 재귀관계(?)를 형성하려면 ForeignKey의 첫번째 인수에 ‘self’를 주어 자기 자신을 참조하도록 한다.
class User(models.Model):
name = models.CharField(max_length=50)
instructor = models.ForeignKey(
'self',
on_delete=models.SET_NULL,
blank=True,
null=True,
)
def __str__(self):
return self.name
# User 인스턴스 생성
>>> lhy = User.objects.create(name='이한영')
>>> pch = User.objects.create(name='박찬혁')
# pch의 instructor 속성을 lhy로 설정한다.
>>> pch.instructor = lhy
여기서 lhy가 갖고있는 User인스턴스에 접근하려면 다음과 같이 입력해야한다.
>>> lhy.user_set.all()
user_set은 장고에서 기본으로 제공하는 관계 목록에 접근할 수 있도록 하는 매니저이름인데 이를 related_name을 이용해서 바꿀 수 있다.
다시 쉽게 말하면, 매니저는 어떤 모델의 클래스가 있을 때 데이터베이스에 접근할 수 있도록 도와주는 객체. 그 매니저의 이름이 user_set인거다.
이 이름이 적합하지 않거나 좀 더 직관적으로 접근할 수 있도록 related_name을 바꿔준다.
class User(models.Model):
name = models.CharField(max_length=50)
instructor = models.ForeignKey(
'self',
related_name = 'students',
on_delete=models.SET_NULL,
blank=True,
null=True,
)
def __str__(self):
return self.name
related_name = 'student'
를 추가함으로써 instructor필드가 갖고있는 객체들에게 접근하기 위한 이름을 student로 변경한 것이다.
>>> lhy.students.all()
<QuerySet ['박찬혁']>
Many-to-Many
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=50)
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(
Person,
through='Membership',
through_fields=('group', 'person'),
)
class Membership(models.Model):
group = models.ForeignKey(Group, on_delete=models.CASCADE)
person = models.ForeignKey(Person, on_delete=models.CASCADE)
inviter = models.ForeignKey(
Person,
on_delete=models.CASCADE,
related_name="membership_invites",
)
invite_reason = models.CharField(max_length=64)
ManyToManyField.through
중개모델을 추가한다. 중개모델은
ManyToManyField.through_fields
장고는 일반적으로 many-to-many 관계를 자동으로 생성하기 위해 어떤 중개모델의 필드를 사용할지 자동으로 결정한다.
하지만 위의 Membership에서 person과 inviter 두 개의 외래키를 Person 클래스로 갖는다. 그렇게 되면 Membership과 Person의 관계가 모호해지게 된다.
따라서 명시적으로 어떤 foreign key를 사용할 것인지 말해줘야 한다.
through_fields는 (‘field1’, ‘field2’) 튜플 형식으로 받는데 field1은 ManyToMany를 정의하는 소스가 되는 모델, field2는 foreign key의 타겟이 되는 모델의 이름을 적는다.
Comments