Backend/Django

Django Base Model 을 통한 Model 중복 제거 (db_table, primary_key), __init_subclass__

뒷골목프로그래머 2023. 5. 2. 19:31
반응형

안녕하세요. 글쓰는 개발자 입니다.

 Django ORM 을 사용하면, 간편하게 Model을 정의하고 강력한 migration 기능 덕분에 손 쉽게 DB에 Table을 생성 할 수 있습니다. 하지만, 아래와 같이 매번 class Meta 코드를 작성하고 db_table을 정의하는 것이 불편하게 느껴졌습니다.

 

일반적인 Model 생성

 그래서 BaseModel을 만들고 이를 상속 받기만 하면 Model을 생성 할 때 마다 중복 되는 작업을 없앨 수 있도록 하였습니다. 요구 사항은 다음과 같습니다.

 

1. Model 의 Class name을 "Model" 을 제외하고 snake case 로 변환한 값을 Table name으로 세팅

2. id 는 Auth Increment로 적용

3. Mixin을 활용해 TimeStamped Column 적용

 

아래와 같이 BaseModel, TimeStampedModel, TimeStampedUserModel 를 정의 합니다. 각 Model은 abstract = True 로 설정하여, migration 대상에서 제외 시킵니다.

 

 

  • BaseModel
    • primary key를 Auto Increment로 자동 생성
    • 상속 받은 자식 db_table 설정
      • __init_subclass__ : 상속 받은 자식 class name 설정
      • _set_table_name : 상속 받은 자식 class name에서 "Model" 을 제외하고 snake case로 변환

 

  • TimeStampedModel : 생성, 수정 시간 컬럼 추가
  • TimeStampledUserModel : 생성, 수정 시간 및 생성 사용자, 수정 사용자 컬럼 추가

 

사용법은 아래와 같습니다. 상속 받아 사용하고, BaseModel과 TimeStampedModel을 같이 써야하는 경우, Mixin을 활용 합니다.

 

위와 같이 사용했을 때, 각 Model 별 실제 생성되는 Column은 다음과 같습니다.

 

  • SampleBoardModel
    • id = models.BigAutoField(primary_key=True) 
    • title = models.CharField(max_length=100)
    • content = models.TextField()
    • author = models.CharField(max_length=20)

 

  • SampleBoardTimeStampedModel
    • id = models.BigAutoField(primary_key=True) 
    • title = models.CharField(max_length=100)
    • content = models.TextField()
    • author = models.CharField(max_length=20)
    • created_at = models.DateTimeField(auto_now_add=True)
    • updated_at = models.DateTimeField(auto_now=True)

 

  • SampleBoardTimeStampedUserModel
    • id = models.BigAutoField(primary_key=True) 
    • title = models.CharField(max_length=100)
    • content = models.TextField()
    • author = models.CharField(max_length=20)
    • created_at = models.DateTimeField(auto_now_add=True)
    • updated_at = models.DateTimeField(auto_now=True)
    • created_by = models.CharField(max_length=20)
    • updated_by = models.CharField(max_length=20)
반응형