Django Model Inheritance

Model Inheritance

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

모델 상속 3가지 방법

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

추상 기본 클래스

  • 몇 가지 공통된 정보를 여러 다른 model에 넣으려 할 때 유용
  • 기본 클래스를 작성하고 Meta classabstract=True 넣음
  • 데이터베이스 테이블을 만드는 데 사용되지 않는 대신, 다른 model의 기본 클래스로 사용될 때 해당 필드는 자식 클래스의 필드에 추가됨
  • 자식의 이름과 같은 이름(상속 받은 클래스의 이름과 같은 이름의 필드)을 가진 추상 기본 클래스의 필드를 가질 수 없음
  • Python 레벨에서 공통 정보를 제외시키는 방법을 제공하면서, 데이터베이스 레벨에서 하위 model 당 하나의 데이터베이스 테이블만 생성
  • 기본 클래스가 자체적으로 존재하지 않음
# Abstract base classes
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 model
    • name, age, home_group 세 가지 필드 존재
  • CommonInfo model
    • 일반 django model로 사용 불가능
    • manager를 가지지 않음
    • 직접 인스턴스화하거나 저장 불가능
  • Meta inheritance
    • 추상 기본 클래스가 생성되면 django는 기본 클래스에서 선언한 Meta 내부 클래스를 속성으로 사용할 수 있도록 함
    • 자식 클래스가 자신의 Meta 클래스를 선언하지 않으면 부모 클래스의 Meta를 상속받음
from django.db import models

class CommonInfo(models.Model):
    # ...
    class Meta:
        abstract = True
        ordering = ['name']

class Student(CommonInfo):
    # ...
    class Meta(CommonInfo.Meta):
        db_table = 'student_info'
  • django는 추상 기본 클래스의 Meta 클래스를 조정
  • Meta 속성을 적용하기 전에 abstract 속성값을 False로 설정 (추상 기본 클래스의 자식은 자동으로 추상 클래스가 되지 않음)
  • 매번 abstract = True를 명시적으로 설정하면, 다른 추상 기본 클래스에서 상속받은 추상 기본 클래스를 만들 수 있음

다중 테이블 상속

  • 계층 구조와 각 model이 모두 각각 자신을 나타내는 model인 경우
  • 각 model은 자체 데이터베이스 테이블에 해당, 개별적으로 쿼리 및 생성 가능
from django.db import models

class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)

class Restaurant(Place):
    serves_hot_dogs = models.BooleanField(default=False)
    serves_pizza = models.BooleanField(default=False)
# Restaurant에 자동적으로 생성이 된 OneToOneField
place_ptr = models.OneToOneField(
    Place, on_delete=models.CASCADE,
    parent_link=True,
    primary_key=True,
)
  • Restaurant에서 parent_link=True를 사용해 자신의 OneToOneField를 직접 선언하여 해당 필드 재정의 가능

프록시 모델

  • model을 python에서 동작만 변경하고자 할 경우
    • 기본 관리자 변경
    • 새 메소드 추가
  • proxy model 상속
    • 원래 model에 대한 proxy를 만듦
    • proxy model의 인스턴스를 생성, 삭제, 업데이트
    • 원본(비 proxy) model을 사용하는 것처럼 모든 데이터가 저장됨
    • 원본 변경하지 않고 proxy의 기본 model 순서(ordering)나 기본 관리자(default manager) 등 변경 가능
  • proxy model
    • 일반 model처럼 선언
    • django에게 meta 클래스의 proxy 속성을 True로 설정해 proxy model임을 알림
from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

class MyPerson(Person):
    class Meta:
        proxy = True

    def do_something(self):
        # ...
        pass

좋은 웹페이지 즐겨찾기