Django 3.1 DB 설계 - 모델 상속(Model Inheritance) 1. 추상 기본 클래스(Abstract base classes)

Kwon, Hyojin·2021년 3월 28일
0

Django

목록 보기
8/9
post-thumbnail
post-custom-banner

해당 글은 Django 공식 문서의 Models - Model Inheritance 내용을 번역 및 정리한 내용입니다.

모델을 잘 설계하기 위해서는 모델의 관계들을 잘 이해할뿐만 아니라, 모델의 3가지 상속 방법을 알고 이를 적절한 case에 이용할 수 있어야 합니다.

<Django의 모델 상속>

  • Python의 클래스 상속과 작동하는 방식이 거의 동일합니다.
  • 반드시 따라야하는 기본 사항 2가지
    1. 기본 클래스가 django.db.models.Model을 상속받아야 합니다.
    2. 부모 모델이 자체 DB 테이블을 갖는 모델이 될지, 부모가 자식 모델에게 전달할 정보만 갖고 있는지 여부만 정하면 됩니다.

<상속을 제공하는 스타일 3가지>

  1. 추상 기본 클래스(Abstract base classes)
    • 부모 클래스를 사용해 각 하위 모델에 대해 일일이 입력하지 않으려는 정보를 제공하는 경우
    • 클래스를 따로 분리해 사용하지 않고, 가장 일반적
  2. 다중 테이블 상속(Multi table inheritance)
    • 기존 모델을 하위 클래스화하고, 각 모델이 자체 DB 테이블을 갖길 원하는 경우
  3. Proxy model
    • 모델 필드를 변경하지 않고 모델의 Python 수준의 동작만 수정하려는 경우

<1. 추상 기본 클래스>

  • 몇가지 공통된 정보를 여러 다른 모델에 넣으려 할 때 유용
  • 기본 클래스를 작성하고 Meta class에 abstract = True 추가
  • DB 테이블을 만드는데 사용되지 않는 대신, 다른 모델의 기본 클래스로 사용될 때 해당 필드는 자식 클래스 필드에 추가
  • 자식(상속받은 클래스) 이름과 같은 이름을 가진 추상 기본 클래스의 필드를 가질 수 X
  • Python 레벨에서 공통 정보를 제외시키는 방법을 제공하면서, DB 하위 모델 당 하나의 테이블만 생성
  • 기본 클래스가 자체적으로 존재하지 X
# velog/inheritances/models.py
from django.db import models


class CommonInfo(models.Model):
    name = models.CharField(max_length=100)
    age = models.PositiveIntegerField()

    class Meta:
        abstract = True


class Student(CommonInfo):
    home_group = models.CharField(max_length=5)
  • Student 모델
    • name, age, home_group 세가지 필드 존재
  • CommonInfo 모델
    • Manager을 갖지 X
    • 일반 Django 모델로 사용 불가능
    • 직접 인스턴스화 혹은 저장 불가능

Meta inheritance

추상 기본 클래스가 생성되면 Django는 기본 클래스에서 선언한 Meta 내부 클래스를 속성으로 사용할 수 있도록 합니다.

자식 클래스가 자신의 Meta 클래스를 선언하지 않으면 부모 클래스의 Meta를 상속받습니다.

from django.db import models


class CommonInfo(models.Model):
    name = models.CharField(max_length=100)
    age = models.PositiveIntegerField()

    class Meta:
        abstract = True
        ordering = ['name']


class Student(CommonInfo):
    home_group = models.CharField(max_length=5)

    class Meta:
        db_table = 'student_info'
  • Django는 추상 기본 클래스의 Meta 클래스를 조정
  • Meta 속성을 적용하기 전 abstract 속성값을 False로 설정 (추상 기본 클래스 자식은 자동으로 추상 클래스가 되지 X)
  • 매번 abstract = True를 명시적으로 설정하면 다른 추상 기본 클래스에서 상속받은 추상 기본 클래스 생성 가능

ForeignKey 또는 ManyToManyField에서 related_name 또는 related_query_name 사용하는 경우

  • 필드의 고유한 역이름(reverse name)과 쿼리 이름(query name)을 항상 지정 필수
  • ForeignKey 또는 ManyToManyField 필드를 가진 추상 기본 클래스를 상속받은 경우 항상 related_name 또는 related_query_name 속성값 동일
  • 이 문제를 해결하기 위해, 추상 기본 클래스에서 값 일부에 %(app_label)s%(class)s 포함
    • %(app_label)s: 하위 클래스가 포함된 앱 이름의 lower-cased 이름
    • %(class)s: 필드가 사용되는 하위 클래스의 lower-cased 이름
# velog/common/models.py
from django.db import models


class OtherModel(models.Model):
    pass


class Base(models.Model):
    m2m = models.ManyToManyField(OtherModel)

    class Meta:
        abstract = True


class ChildA(Base):
    pass


class ChildB(Base):
    pass

  • related_name 속성을 지정하지 않으면, common.ChildA.m2m 필드와 common.ChildB.m2m 필드의 reverse name은 각각 childa_set, childb_set
# ...
class Base(models.Model):
    m2m = models.ManyToManyField(
        OtherModel,
        # related_name, related_query_name 지정
        related_name='%(app_label)s_%(class)s_related',
        related_query_name='%(app_label)s_%(class)ss',
    )

    class Meta:
        abstract = True
# ...

  • common.ChildA.m2m 필드와 common.ChildB.m2m 필드의 reverse name은 각각 common_childa_related, common_childb_related

  • common.ChildA.m2m 필드와 common.ChildB.m2m 필드의 reverse query name은 각각 common_childas, common_childbs
profile
파이썬 웹 백엔드 개발자
post-custom-banner

0개의 댓글