Django Model Inheritance

GreenBeanยท2021๋…„ 11์›” 18์ผ
0
post-thumbnail

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 class์— abstract=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
profile
๐ŸŒฑ Backend-Dev | hwaya2828@gmail.com

0๊ฐœ์˜ ๋Œ“๊ธ€