당신은 멋쟁이, 우리는 장고쟁이~

0%

Django Models 19편 - Model 상속 Multi-table inheritance 1편

Model 상속 (Multi-table inheritance )


Django 모델을 상속 받는데에 있어서 3가지 스타일이 존재합니다.


  1. Abstract base classes
  2. Multi-table inheritance
  3. Proxy Models

Multi-table inheritance


Django 모델에서 지원하는 두번째 모델 상속 방식은, Multi-table inheritance 입니다.


각 모델이 계층구조에서, 자체적으로 모델일 경우 입니다.

각 모델은 각자의 데이터베이스 테이블에 해당 되고, 각각 쿼리문을 보내거나 생성될수 있습니다.


상속 관계는, 자식 모델과 부모 모델의 연결고리를 만들어 놓습니다.


예를들면,


1
2
3
4
5
6
7
8
9
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)

Place 의 모든 필드들은, Restaurant 에서도 사용할수 있습니다.


하지만, 데이터는 다른 데이터베이스 테이블에 존재하게 됩니다. 따라서, 아래 상황들 둘다 가능합니다.


1
2
3
4
5
6
7
8
9
10
>>> Place.objects.filter(name="Bob's Cafe")
>>> Restaurant.objects.filter(name="Bob's Cafe")

In [1]: bobscafe = Place.objects.create(name="Bob's Cafe", address="Bob ba di rara")

In [2]: Place.objects.filter(name="Bob's Cafe")
Out[2]: <QuerySet [<Place: Place object (1)>]>

In [3]: Restaurant.objects.filter(name="Bob's Cafe")
Out[3]: <QuerySet []>

만약 Place 이면서, Restaurant 인 경우,


Place 객체에서 Restaurant 객체를 얻을수 있는데, 모델 이름의 소문자 형태를 사용하여 얻을수 있습니다.


1
2
3
4
5
6
7
8
9
10
11
12
In [4]: p = Restaurant.objects.create(name="pizza hut", address="789 Hume Highway", serves_hot_dogs=False, serves_pizza=True)                                             

In [5]: Place.objects.all()
Out[5]: <QuerySet [<Place: Place object (1)>, <Place: Place object (2)>]>

In [7]: Restaurant.objects.all()
Out[7]: <QuerySet [<Restaurant: Restaurant object (2)>]>

In [8]: p = Place.objects.get(id=2) # p 가 Restaurant 객체 일때, 자식 클래스를 제공한다

In [10]: p.restaurant
Out[10]: <Restaurant: Restaurant object (2)>

하지만, 위 예제에서, p 라는 인스턴스가 Restaurant 이 아니라, Place 객체로 직접 생성 되었다면,

p.restaurant 은 Restaurant DoesNotExist 예외를 발생 시켰을 겁니다.


Restaurant 을 Place 에 연결해 주는, 자동 생성된 OneToOneField 는 아래와 같이 생겼습니다.


1
2
3
4
5
Place_ptr = models.OneToOneField(
Place, on_delete=models.CASCADE,
parent_link = True,
primary_key = True,
)

Restaurant 에서 OneToOneField 의 paraent_link=True 로 설정해 줌으로써, 필드를 오버라이드 할수 있습니다.


Meta and Multi-table inheritance


multi-table 상속 상황속에서는, 자식 클래스가 부모의 Meta 클래스를 상속 받는게 있을수 없는 일입니다.


모든 Meta 옵션들은 이미 부모 클래스에 적용 되어 있고, 이것을 다시 적용 한다는것은 단지 모순된 동작으로 이어지게 할 뿐입니다.


따라서, 자식 모델은, 부모의 Meta 클래스에 접근할수 없습니다. 그렇지만, 자식 모델이 부모 모델의 동작을 상속받는 몇가지 제한적 경우가 있습니다.


만약,

자식 모델이 ordering 속성 혹은 get_latest_by 속성을 지정하고 있지 않다면,

이 속성들을 부모 클래스에서 상속 받을수 있습니다.


만약 부모 모델이 ordering 을 가지고 있고, 자식 모델이 자연스러운 ordering 을 가지게 하고 싶으면,


명시적으로 비활성화를 시켜주면 됩니다.


1
2
3
4
5
class ChildModel(ParentModel):
# ...
class Meta:
# 부모 모델의 ordering 을 제거 해주기
ordering = []