Relationships

모델과 모델간의 관계를 알아보자. Many-to-one, Many-to-many, one-to-one 등이 있다.

Many-to-one relationships

Many : 1 관계를 정의하려면 django.db.models.ForeignKey를 사용하자.

  • 다른 필드 유형(ex - models.CharField)과 마찬가지로 모델의 클래스 속성으로 접근하여 사용된다.(models.ForeignKey)
  • ForeignKey는 첫번째 인자로 참조할 모델 클래스를 필수적으로 적어줘야한다.
from django.db import models

class Manufacturer(models.Model):
	name = models.CharFiemd(max_length=30)

	def __str__(self):
		return self.name

class Car(models.Model):
	manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
	name = models.CharField(max_length=30)

	def __str__(self):
		return self.name

필수는 아니지만 ForeignKey필드의 이름은 참조되는 모델 이름의 lowercase가 권장된다.



Many-to-many relationships

Many to Many도 마찬가지로 django.db.models.ForeignKey를 사용한다.

  • 또한 마찬가지로 모델의 클래스 속성으로 접근하여 사용한다.
  • ManytoManyField 또한 첫번째 인자로 참조할 모델 클래스를 필수적으로 적어준다.
from django.db import models

class Pizza(models.Model):
	name = models.CharField(max_length=30)
	toppings = models.ManyToManyField(
		'Topping',
		'blank=True'
		)

	def __str__(self):
		return self.name

class Topping(models.Model):
	name = CharField(max_length=30)

	def __str__(self):
		return self.name



Tip!

Many-to-one이나 Many-to-many는 자기 자신의 모델 클래스를 첫번째 인자로 넘겨 recursive 관게를 만들 수 있다.

Many-to-one 예제

from django.db import models


class User(models.Model):
    name = models.CharField(max_length=30)
    teacher = models.ForeignKey(
        'self',
        on_delete=models.SET_NULL,
        blank=True,
        null=True
    )

Many-to-Many 예제

symmetrical 옵션을 False로 주면 대칭되는 레코드가 생성되지 않고 단방향으로만 생성된다.

from django.db import models


class InstagramUser(models.Model):
    name = models.CharField(max_length=10)
    following = models.ManyToManyField(
        'self',
        blank=True,
        symmetrical=False
    )

    def __str__(self):
        return self.name


아직 정의되지 않은 관계에 대하여 모델 객체 자체가 아닌 모델 이름을 사용할 수 있습니다.

  • 아래 코드처럼 models.ManyToManyField의 첫번째 인자로 모델 클래스의 객체가 아닌 모델 이름을 string으로 사용 할 수 있다.
from django.db import models


class Pizza(models.Model):
    name = models.CharField(max_length=30)
    toppings = models.ManyToManyField(
        'Topping',
        blank=True,
    )

    def __str__(self):
        return self.name


class Topping(models.Model):
    name = models.CharField(max_length=30)

    def __str__(self):
        return self.name



Extra fields on many-to-many relationships

피자와 토핑을 매칭하는 것과 같은 단순한 many-to-many 관계만 처리 할 때는 표준 ManyToManyField 만 있으면된다. 하지만 때로는 두 모델 간의 관계에 데이터를 연결해야 할 수도 있다.

예를들어, 프로듀스 101에서 우승한 I.O.I는 모두 다른 그룹에 속해있다. 아래 코드를 보면 Idol모델과 Group모델의 관계 이외의 속성들을 정의해서 표시해줘야 할 경우 Membership 모델과 같은 중간 모델이 필요하다.

from django.db import models


class Idol(models.Model):
    name = models.CharField(max_length=30)

    def __str__(self):
        return self.name


class Group(models.Model):
    name = models.CharField(max_length=50)
    debut_date = models.DateField()
    members = models.ManyToManyField(
        Idol,
        through='Membership'
    )
    def __str__(self):
        return self.name


class Membership(models.Model):
    idol = models.ForeignKey(Idol, on_delete=models.CASCADE)
    group = models.ForeignKey(Group, on_delete=models.CASCADE)
    joined_date = models.DateField()
    is_active = models.BooleanField()

    def __str__(self):
        return f'{self.group.name}' \
               f'{self.idol.name}' \
               f'({self.is_active})'



One-to-One relationships

예를들어 User와 Profile 테이블이 있다고 하자. 상식적으로 한명의 유저는 하나의 프로필만 갖게된다. 또한 하나의 프로필은 하나의 유저에게만 해당된다. 그러므로 서로의 User혹은 Profile객체 이외의 다른 객체를 가질 수 없으므로 One-to-one관계이다.

# accounts/models.py
from django.db import models
from django.contrib.auth.models import User


class Profile(models.Model):
    user = models.OneToOneField(User)
    phone_number = models.CharField(max_length=20)
    address = models.CharField(max_length=50)

User모델을 사용하는 세가지 방법

# 방법1) 비추천
user = models.OneToOneField(User)

# 방법2) 비추천
user = models.OneToOneField('auth.User')

# 방법3) 추천
user = models.OneToOneField(settings.AUTH_USER_MODEL)
  • 장고는 장고 사용자 인증에 사용되는 User모델 변경을 지원하므로 방법3으로 쓰는 것이 좋다.

siwon

$_$