파비의 매일매일 공부기록

Two Scoops of Django - #6장 본문

Study/Python

Two Scoops of Django - #6장

fabichoi 2021. 6. 7. 23:30

이번장은 장고에서 모델 이용하기에 대한 내용이다.

모델은 장고 프로젝트의 토대가 되는 부분으로 깊게 고려하지 않고 성급하게 작성하다 보면 낭패를 겪을 수 있다.

 

종종 급한 마음에 결과를 생각하지 않고 부주의하게 모델을 변경하거나 추가하기도 하는데

그러다 보면 임시방편으로 내린 결정으로 인한 나비효과로 더 괴로워지는 경우가 생길 수 있다.

그러므로 새 모델을 추가하거나 기존 모델 수정 시 깊게 생각해야 하며 탄탄하고 안전하게 토대를 다지는 방향으로 디자인해야 한다.

 

1. 모델이 너무 많으면 앱을 나눈다 : 앱 하나에 모델이 스무 개 이상 있다면 작은 앱으로 분리하는 걸 고려하라. 각 앱이 가진 모델수가 다섯 개를 넘지 않아야 함.

2. 모델 상속에 주의하라 : 멀티 테이블 상속을 피할 것. 모델들 사이에서 좀 더 명확한 OneToOneFields와 ForeignKeys를 이용하여 Join이 난립할 때도 좀 더 수월하게 컨트롤 가능

 

추상화 기초 클래스를 만드는 방법 :

class Meta:
	abstract = True

접합 기반 상속은 심각한 성능 문제를 일으킬 소지가 있으며, 더욱이 여러 번 서브클래스 화해서 이용하면 문제가 될 소지가 더 커진다 => 접합 기반 상속의 예를 아직 못 봐서 어떤 내용인지 모르겠음. 아니면 이미 쓰고 있는데 인지를 못하는 걸지도..?

 

3. 마이그레이션에 대해 : 생각보다 마이그레이션 관련 이슈가 실무에서는 많이 일어난다. 마이그레이션 생성 팁은 다음과 같다.

 - 새로운 앱이나 모델이 생성되면 새 모델에 대해 django.db.migrations를 실행. python manage.py makemigrations

 - 생성된 마이그레이션 코드를 실행 전 생성된 코드를 살펴볼 것. 특히 복잡한 변경 사항이 적용된 경우 더 꼼꼼히 살펴볼 것. sqlmigrate 명령을 통해 어떤 SQL문이 실행되는지도 확인할 것

 - 외부 앱에 대해 마이그레이션 처리 시 MIGRATION_MODUELS 세팅 활용

 - 생성되는 마이그레이션 개수에 연연하지 말 것. 너무 많아서 불편할 경우 squashmigrations를 이용할 것.

 - 배포 전 마이그레이션을 롤백할 수 있는지 확인 필요.

 - 테이블에 이미 수백만 개의 데이터가 존재한다면 스테이징 서버 등에서 비슷한 크기의 데이터로 충분히 테스트해야 함. 운영 서버의 경우 마이그레이션이 더 오래 걸릴 수 있음

 - MySQL 사용 시 : 스키마 변환 전 데이터베이스 반드시 백업할 것. MySQL은 스키마 변경에 대한 트랜젝션 지원하지 않음. 가능하면 DB 변환 전 읽기 전용 모드로 변경할 것. 큰 테이블의 경우 스키마 변경에 상당한 시간(ex: 수 시간)이 걸릴 수 있으므로 유의할 것.

 

나도 실무를 하다 보면 모델을 어떻게 디자인하는 게 좋을지 고민하게 되는데(아직은 모델 설계 까지는 안 하지만)

저자도 가장 어려운 주제 중 하나가 좋은 장고 모델을 디자인하는 방법이라고 한다. 여러 가지 전략을 다음에 소개한다.

1. 정규화하기 : 미숙하게 비 정규화하는 것을 최대한 피할 것. 데이터의 형태와 틀에 대한 지각이 필요

2. 캐시 활용 : 적절한 위치에서 캐시를 세팅하면 모델을 비정규화 할 때 발생하는 문제들을 상당수 해결할 수 있음

3. 반드시 필요한 경우에만 비정규화 : 비정규화가 만병통치약이 처럼 보일 수 있지만 실제로는 프로젝트를 복잡하게 만들고 데이터 손실의 위험을 증가시킬 수 있음.

4. 언제 null을 사용하고 언제 blank를 사용할지 결정 : 모델 정의 시 null=True, blank=True 설정 옵션 선택 가능.(디폴트로는 모두 False) 책에 자세한 가이드라인을 소개함.

5. 언제 BinaryField를 이용할지 결정 : 웬만하면 안 쓰는 게 좋을 듯. 정 필요하다면 FileField에 레퍼런스만 저장하는 방식 활용. 파일을 직접 해당 필드를 통해 서비스하는 건 지양할 것.

6. 범용 관계 피하기 : 한 테이블로부터 다른 테이블을 서로 제약 조건이 없는 외부 키로 바인딩하는 범용 관계를 피할 것. 쿼리 속도 느려질 수 있으며 데이터 충돌의 위험성 존재

7. PostgreSQL 사용 시 언제 null, 언제 blank 사용할지 결정 : 책에 자세한 가이드 제공.

 

모델의 _meta API : 지금까지는 따로 이런 걸 사용해본 적은 없지만 만약 필요한 경우는 다음과 같은 이유일 수 있다고 한다.

- 모델 필드의 리스트를 가져올 때

- 모델의 특정 필드의 클래스를 가져올 때(or 상속 관계나 상속 등을 통해 생성된 정보를 가져올 때)

- 앞으로의 장고 버전들에서 이러한 정보를 어떻게 가져오게 되었는지 확실하게 상수로 남기기를 원할 때

- 장고 모델의 자체 검사 도구로 사용되는 상황

- 라이브러리를 이용해서 특별하게 커스터마이징 된 자신만의 장고를 만들려는 상황

- 장고의 모델 데이터를 조정하거나 변경할 수 있는 관리 도구를 제작하려는 상황

- 시각화나 분석 라이브러리를 제작하려는 상황

 

모델 매니저 : 모델에 질의를 하게 되면 장고의 ORM을 통하게 되는데, 이때 우리는 모델 매니저라는 데이터베이스와 연동하는 인터페이스를 호출한다. 모델 매니저는 원하는 클래스들을 제어하기 위해 모델 클래서의 모든 인스턴스 세트에 작동하게 됨. 장고는 각 모델 클래스에 대한 기본 모델 매니저를 제공하며 따로 제작할 수도 있음.

 

마지막으로 거대 모델 이해하기에 대한 내용이다.

거대 모델(fat model) : 데이터 관련 코드를 뷰나 템플릿에 넣지 않고 모델 메서드, 클래스 메서드, 프로퍼티 혹은 매니저 메서드 안에 넣어 캡슐화한 모델.

거대 모델을 사용하면 코드 재사용을 개선할 수 있는 최고의 방법일 수 있지만, 모델 코드 크기를 '신의 객체(god object) 수준으로 증가시키므로 모델 클래스 자체가 수천-수만 줄이 될 수 있어 테스트 및 유지보수가 용이하지 않다. 그러므로 여러 작은 크기로 분리하는 방향으로 선회하는 게 좋은데 모델 행동(model behavior)이나 헬퍼 함수(stateless helper function)로 이전할 수 있다.

1. 모델 행동(Mixin) : mixin을 실무에서 꽤 많이 봐왔는데 이런 이유로 쓰는지는 몰랐다. 근데 생각보다 디버깅할 때 불편한데.. 같은 파일이 아니다 보니 왔다 갔다 하면서 헷갈리는 경우가 발생하긴 한다. 여하튼 저자는 믹스인 활용을 추천한다.

2. 상태 없는 헬퍼 함수 : 모델로부터 로직을 띄어 유틸리티 함수로 넣어 좀 더 독립적인 구성이 가능. 로직에 대한 테스트가 좀 더 용이해지나 해당 함수들이 자신의 stateless함수에 더 많은 인자를 필요로 할 수 있다.

 

마지막으로 저자는 정규화 이후 비정규화를 수행할 것을 추천하며

raw SQL이나 적절한 캐시, 인덱스 등을 활용하여 성능 문제 해결을 추천한다.

만약 모델 간 상속을 이용하려고 한다면 접합 모델(concreate model)이 아니라 추상화 기초 클래스로부터 상속할 것을 추천한다.

django-model-utils와 django-extensions를 유용하게 쓸 것을 추천(실무에서는 쓰는 중)

 

다음장에서는 쿼리와 데이터베이스 레이어에 대해 다룰 예정이라고 한다.

 

 

 

반응형

'Study > Python' 카테고리의 다른 글

Two Scoops of Django - #8장  (0) 2021.06.09
Two Scoops of Django - #7장  (0) 2021.06.08
Two Scoops of Django - #5장  (0) 2021.06.06
Two Scoops of Django - #4장  (0) 2021.06.05
Two Scoops of Django - #3장  (0) 2021.06.04
Comments