Django Models 11 다중 테이블 상속

Multi-Table inheritance

장고가 지원하는 모델 상속의 두 번째 유형으로 계층 구조의 각 모델이 모두 하나의 모델 일 때 이다. 이전에 봤던 Abstract base classes과 정 반대 이다. 추상 기본 클래스에서는 추상 모델이 하나의 테이블이 되지 않았지만 Multi-table inheritance에서는 부모도 테이블을 가지며 개별적으로 쿼리하고 생성이 가능하다. 상속 관계는 자동으로 생성 된 OneToOneField를 통해 자식 모델과 각 부모간의 링크를 도입한다.

Multi-table inheritance를 하면 부모와 자식을 OneToOneField로 자동으로 연결 시켜 준다. 그래서 자식을 하나 만들 때 마다 부모의 OneToOne필드에 자식의 pk를 만들고 가리키게 된다. 문제는 속성을 접근 할 때마다 테이블을 거쳐 가는것인데 만약 여러 단계의 상속을 했다면 속도 상으로 매우 좋지 않다. 속성을 하나 탐색 할 때마다 상속된 테이블을 모두 거쳐 가기 때문에 매우 느리다. 대부분 한 두단계 정도만 상속을 하는것을 추천하다.

이 모델의 장점을 부모 모델에 대해 직접 쿼리가 가능 하다는 것이다. 자식 모델에 대한 공통된 정보를 가져오기에 편리하다.

from django.db import models

__all__ = (
    'Place',
    'Restaurant',
)


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

    def __str__(self):
        return f'{self.name} | {self.address}'


class Restaurant(Place):
    serves_hot_dogs = models.BooleanField(default=False)
    serves_pizza = models.BooleanField(default=False)

    def __str__(self):
        return f'Restaurant {self.name} | {self.address}'

레스토랑을 만들어 보자

#<Restaurant: Restaurant 맥도날드 | 신사역>
Restaurant.objects.create(name='맥도날드', address='신사역', serves_hot_dogs=True)

이렇게 만들어진 모델의 자동으로 생성된 OneToOneField는 이렇게 생겼다

place_ptr = models.OneToOneField(
    Place, on_delete=models.CASCADE,
    # 이 필드가 부모와의 링크를 나타내기 위해 존재 한다는걸 표현함
    parent_link=True,
)

parent_link=TrueOneToOneField를 직접 새로 만들면 자동으로 생성되는 위의 필드가 생기지 않는다.

Meta and Multi-table inheritance

다중 테이블 상속 상황에서 자식 클래스가 부모의 Meta클래스에서 상속 받는 것은 의미가 없다. 모든 메타 옵션은 이미 상위 클래스에 적용되었고 다시 적용하면 모순된 행동 만 발생 시킨다.

따라서 자식모델은 부모의 메타 클래스에 액세스 할 수 없다. 그러나 자식이 부모로부터 동작을 상속 하는 몇가지 제한된 경우가 있다. ordering이나 get_latest_by특성을 지정하지 않으면 해당 특성은 부모로부터 상속 한다.

다중 테이블 상속은 암시적으로 OneToOneField를 사용하여 부모와 자식을 연결하기 때문에 부모에서 자식으로 이동 할 수 있다. 그러나 이는 ForeignKey, ManyToManyField 관계에 대한 기본 related_name값인 이름을 사용한다. 이러한 관계 유형을 부모모델이 자식 모클래스에 배치하는 경우 해당 필드 각각에 related_query_name 특성을 지정 해야 한다. 잊어버리면 장고는 Reverse query name 이 충돌하여 유효성 검사오류를 발생 시킨다.

OneToOneFieldrelated_namerelated_query_name이 같다. 그래서 만약 자식 모델에 ForeignKeyManyToManyFieldrelated_query_name이 없을 경우 해당 모델의 부모와 관계형 필드들이 가지고 있는 related_query_name이 충돌한다.

Comments