Django/Django Rest Framework

12. Django DRF 외래 키

S.T.Lee 2022. 6. 19. 10:39

외래 키 종류

  • ForeignKey : many-to-one 형태로 특정 테이블에서 다른 테이블을 참조 할 수 있다,
    • 영화관과 시청자의 관계를 나타 낼 때, 시청자 테이블에서 영화관 테이블을 Foreign Key를 사용해 관계를 맺을 수 있다.
  • OneToOneField : one-to-one 형태로 ForeignKey와 동일하지만, 1:1 관계만 가능하다.
    • 사용자 계정 테이블과 사용자 프로필 테이블이 별도로 존재 할 때, 계정 테이블을 프로필에서 1:1로 관계를 맺을 수 있다.
    • ForeginKey(unique=True)로 설정해주는거랑 같다.
  • ManyToManyField : many-to-many 형태로 한 개의 필드에서 여러개의 테이블을 참조 할 수 있다.
    • 영화라는 테이블에서 카테고리 테이블의 object를 참조하고 싶을 때, many to many 관계를 사용해 2개 이상의 object를 참조할 수 있다.
    • Many-to-many 관계로 생성 된 필드는 db에 값이 2개 이상 저장되는 것이 아닌, 중간 테이블이 생성된다.

 

모델 필드에 따른 DB 저장 방식

from ntpath import join
from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser

# Create your models here.
class UserManager(BaseUserManager):
    def create_user(self, username, password=None):
        if not username:
            raise ValueError('Users must have an username')
        user = self.model(
            username=username,
        )
        user.set_password(password)
        user.save(using=self._db)
        return user
    
    def create_superuser(self, username, password=None):
        user = self.create_user(
            username=username,
            password=password
        )
        user.is_admin = True
        user.save(using=self._db)
        return user


class User(AbstractBaseUser):
    username = models.CharField("사용자 계정", max_length=50, unique=True)
    password = models.CharField("비밀번호", max_length=200)
    email = models.EmailField("이메일 주소", max_length=100)
    fullname = models.CharField("이름", max_length=20)
    join_date = models.DateField("가입일", auto_now_add=True)
    
    is_active = models.BooleanField(default=True)
    
    is_admin = models.BooleanField(default=False)
    
    USERNAME_FIELD = 'username'
    
    REQUIRED_FIELDS = []
    
    objects = UserManager()
    
    def __str__(self):
        return f"{self.username} / {self.email} / {self.fullname}"
    
    #권한 설정 #손 건들일이 없다
    def has_perm(self, perm, obj=None):
        return True
    #손 건들일이 없다
    def has_module_perms(self, app_label):
        return True
    
    @property
    def is_staff(self):
        return self.is_admin


class UserProfile(models.Model):
    user = models.OneToOneField(to=User, verbose_name="사용자", on_delete=models.CASCADE, primary_key=True)
    hobby = models.ManyToManyField("Hobby", verbose_name="취미")
    introduction = models.TextField("소개")
    birthday = models.DateField("생일")
    age = models.IntegerField("나이")
    
    def __str__(self):
        return f"{self.user.username} 님의 프로필"


class Hobby(models.Model):
    name = models.CharField("취미", max_length=50)
    
    def __str__(self):
        return self.name

분명 UserProfile에 hobby를 만들었는데 hobby가 없는것을 볼 수 있다. 그 이유는 외래 키에 2개 이상의 id값이 들어갈 수 없어서 DB자체적으로 중간 테이블을 만들기 때문이다. 위에서 userprofile_hobby라는 만들지 않은 테이블이 생성된것을 볼 수 있다.

상단과 같이 userprofile과 hobby가 값으로 있는 중간 테이블 구조를 볼 수 있다.