[pjt 422] 개발 일지 - Django Model 상속

Expert Inpyo·2022년 8월 25일
0

PJT 422

목록 보기
4/6

Django Model 상속

쓰레기통 사용 현황에 대한 날짜 / 캠퍼스 / 건물 / 층 / 쓰레기통 별 통계를 만들기 위해 stats앱에서 모델링을 계획했다.

해당 테이블들의 데이터들의 출처는 하드웨어와 서버의 통신으로 생기는 로그 데이터를 기반으로 정의할 예정이다.
로그데이터는 날짜 / 시간 / 건물 pk / 층 pk/ 쓰레기통 식별 토큰 / 쓰레기 종류로 이뤄져있다.

이런 로그데이터를 하루 동안 수집 후, pandas로 데이터를 분류하여 각 날짜별 테이블에 정보를 담을 것을 기획 중이다.

통계 모델은 Class 상속을 사용해 구현해보았다.

참고 자료
공식문서

참고 블로그

Django Model 상속

모델 상속 - 기본

Python에서 일반 클래스 상속과 거의 동일함.
기본 클래스는 django.db.models.Model의 하위클래스이어야 함.
또한, 부모 모델이 자체 db 테이블을 갖는지, 혹은 자식 모델에게 공통 정보만 주는 역할인지를 정의해야 함.

세 가지 상속 스타일 존재
1. 추상 기본 클래스
- 자식 클래스에서 입력을 반복하고 싶지 않은 것
-
2. 다중 테이블 상속
- 기존 모델을 하위 클래스화하고 각 모델에 고유한 데이터베이스 테이블을 제공할 때 사용

  1. Proxy Model
    • 기존 모델의 필드를 수정하지 않고 파이썬 수준의 행동만 수정하려는 경우 사용

추상 기본 클래스

  • 몇가지 공통 정보를 여러 다른 모델에 넣으려고 할 때 유용함
  • 기본 클래스를 작성하고 Meta 클래스 안에 Abstract = True 추가
  • 데이터베이스에 어떠한 테이블도 생성하지는 않음
  • 그 대신, 다른 모델들의 기본 클래스가 되고, 이런 자식 클래스들에 이 클래스의 fields가 추가됨.
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
    총 세 개의 fields를 갖게 됨.
  • CommonInfo 모델은 DB를 가질 수 없음

Meta inheritance - Meta 상속

추상 기본 클래스가 생성되면 Django는 기본 클래스에서 선언한 Meta 내부 클래스를 속성으로 사용할 수 있게 됨.
자식 클래스가 자신의 Meta 클래스를 선언하지 않으면 부모의 Meta를 상속함.
자식이 부모의 Meta를 확장하려는 경우 하위 클래스로 만들 수 있음

Example
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'

abstract = False이면, 클래스의 자식이 추상 클래스가 되지 않는다는 것을 의미함.
다른 클래스에서 상속되는 클래스를 만들기 위해선 abstract = True 설정해야 함

자식 클래스가 여러 추상 기본클래스를 상속하는 경우, 기본적으로 첫번째 나열된 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 Unmanaged(models.Model):
    class Meta:
        abstract = True
        managed = False

class Student(CommonInfo, Unmanaged):	# 이렇게 둘 다 명시적으로 표기하는 방법으로!
    home_group = models.CharField(max_length=5)

    class Meta(CommonInfo.Meta, Unmanaged.Meta):
        pass

ForeignKey 혹은 ManyToManyField에 대해 related_name, related_query_name을 사용하는 경우, 해당 field에 대해 unique한 역방향 이름을 항상 설정해줘야 함.

우선 이렇게 번역을 해 보았다.
더 많은 정보는 위에 첨부한 링크를 참고하려 한다.

How to use

위 내용을 가지고 Django Model을 아래와 같이 변경했다.

class DefaultInfo(models.Model):
    name = models.CharField(max_length=100)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True

모델을 작성 시 이름, 생성 및 수정 일자는 공통적으로 사용되는 것을 느꼈고, 이를 상속받기 위해 다음과 같은 부모 모델을 만들었다.

위 모델을 상속받는 자식 모델은 아래와 같다.

1. Building

class Building(DefaultInfo):
    description = models.TextField()

    def __str__(self):
        return self.name

2. Floor

class Floor(DefaultInfo):
    map_path = models.TextField()
    width = models.FloatField()
    height = models.FloatField()
    trashbin_size = models.FloatField()
    building = models.ForeignKey(Building, on_delete=models.CASCADE, related_name='floor')
    order = models.IntegerField()   # 층 순서
    
    def __str__(self):
        return self.name

3. Group

class Group(DefaultInfo):

    def __str__(self):
        return self.name
profile
도전! 데이터 엔지니어

0개의 댓글