2019년 3월 7일 목요일

#6 Django 장고에서 모델 이용하기

💾 Django 장고에서 모델 이용하기



모델작업을 하며 우리가 이용하는 장고 패키지들


- django-model-utils:
 
    TimeStampedModel 같은 일반적인 패턴들을 처리하는데 이용

-django-extensions :
 
    모든 앱에 모델클래스를 자동으로 로드해주는 shell_plus라는 강력한 관리명령 제공
    단점은 작지만 역할이 분명한 앱 개념에 맞지않게 너무 다양한 기능



모델은 장고 프로젝트의 토대가 되는 중요한 부분이다
따라서 모델의 생성과 수정에서는 다음의 개념들을 생각해주도록 하자

시작하기

    1. 모델이 너무 많으면 앱을 나눈다(1개의 앱당 모델은 5개를 넘지않아야한다)

    2 . 모델 상속에 주의하자
     
    만약 상속을 하지않는다면?

    모델들 사이에 공통필드가 있으면 두 모델에 전부 필드를 생성

    장점 : DB Table에 어떤식으로 Mapping되든지 상관없이 한눈에 이해하기 쉽게 구성

    단점 : 중복되는 Table이 많을경우 관리의 어려움


모델의 상속

    추상화기초클래스(abstract base class)(파이썬과 다르다)


    (모델사이의 중복된필드가 많을때)

    오직 상속받아 생성된 모델들의 테이블만 생성

    장점 : 추상화된 클래스에 공통부분을 추려놓아 한번만 타이핑을 하면 된다.
            추가 테이블이 생성되지않고 여러테이블에 조인함으로써 발생하는 성능 저하없다

    단점 : 부모클래스를 독립적으로 이용할수 없다

    공통 필드부분을 추상화 기초모델로 이전하는 리팩터링 작업요구


    멀티 테이블 상속(multi-table inheritance)혼란과 부하를 일으키므로 이용 지양

                                       
    부모와 자식 모델에 대해서 모두 테이블 생성, One to One Field는 부모와 자식간에 적용

    장점 : 각 모델에 매칭되는 테이블이 생성, 따라서 부모또는 자식 모델 어디로든 쿼리
        부모로부터 자식객체 호출 가능

    단점 : 자식테이블의 쿼리에 대해 부모 테이블로의 조인이 들어가 부하가 걸린다.
        이용하지말자

    차라리 one to one fields와 foreign Keys를 이용해 컨트롤하자


    프락시 모델(proxy model)


    원래 모델에 대해서만 테이블이 생성

    장점 : 각기 다른 파이썬 작용을 하는 모델들의 별칭을 가질 수 있다.

    단점 : 모델의 필드를 변경할 수 없다


실제 모델 상속해보기


    일반적으로 created 와 modified 와 같은 Time Stamp field 는 모든 모델들이 생성해두는데

    Time Stamped Model을 만들어 우리 대신 필드 추가 처리를 할수있게 해주자

    이때 일반 클래스와 다른점은 우리가 선언하는 Model Class안에

    class Meta:
        abstract = True와 같이 설정해줘 추상화기초클래스로 만들어 주는것이다

    이로써 마이그레이션을 할때 테이블이 생성되지 않는다

    (만약 이게 아닌 멀티테이블 상속이였으면 make migration시 timestamp 테이블도 생성되고
    상속받은 테이블들이 timestamp와 연결되는 외부키로 time stamp를 처리하고 있었을것)

데이터베이스 마이그레이션


장고 1.7부터 django.db.migrations가 south라는 외부 라이브러리 대체하게 되었다


마이그레이션의 생성 Tip


    새로운 앱이나 모델이 생성되면 python manage.py makemigration

    생성된 코드를 실행하기전 생성된 코드를 살펴봐야한다(특히 변경사항이 복잡할수록
    sqlmigrate 명령을 통해 해당 migration으로 어떤 SQL문이 실행되는지도 확인하자)


    만약 자체적인 django migrations 스타일로 이루어지지 않은 외부앱에 대해서는
MIGRATION_MODULES셋팅 이용

    생성되는 migration의 갯수에 연연하지 말자(너무 많아 불편하면 squashmigrations를 이용)


마이그레이션의 배포 및 관리


    배포전에 rollback 할수 잇는지 확인해보자(rollback이 불가능하면 프로젝트에서 버그 트래킹 등의 문제가 될수 있다)

    Table의 데이터가 많다면 운영 서버에서 migration 하기전에 staging서버에서 충분히 테스트 해보자 (운영서버의 migration은 많은 시간이 걸린다)

    MySQL을 이용한다면 다음과 같이
    스키마 변환전 DB 백업해둔다.(MySQL 은 스키마 변경에 대한 트랜잭션을 지원 X
rollback불가)
    가능하다면 DB변환이전에 프로젝트를 read 모드로 변경
    큰 Table의 경우 스키마 변경에 오랜 시간이 소요될수 있다.



장고 모델 디자인


    1. DB정규화 (http://en.wikipedia.org/wiki/Database_normalization
                 (http://en.wikibooks.org/wiki/Relational_Database_Design/Normalization

    이미 모델에 포함된 data가 중복되어 다른 모델에 포함되지 않도록 하자

    2. 캐시와 비정규화
    적절한 위치에서 캐시를 세팅하는 것은 모델의 비정규화에서 발생하는 문제를 해결

    3. 반드시 필요한 경우에만 비정규화

    4. 언제 Null을 쓰고 언제 공백을 쓸까

        일반적 가이드

        Null = True O

        Integer,Float,Decimal,Duration(값이 DB에 NULL로 들어가도 된다면)
        DateTime,Date,Time,ForeignKey,ManyToMany,OneToOne,GenericIPAddress (DB에서 NULL값 설정이 가능하면)


        Null = True X

        Char,Text,Slug,Email,CommaSeparatedInteger,UUID,File,Image,BooleanField


        blank = True O

        Char,Text,Slug,Email,CommaSeparatedInteger,UUID,File,Image,Integer,Float,Decimal,
       Duration,DateTime,Date,Time,ForeignKey,ManyToMany,OneToOne,GenericIPAddress


        blank = True X

        BooleanField

 
 
    5. 언제 BinaryField를 이용할것인가

        filter, exclude, 등의 SQL액션이 적용되지 않는다
        메시지팩 형식의 콘텐츠 , 원본 센서 데이터, 압축된 데이터
        하지만 DB필드에 이처럼 파일을 직접 저장하게 되면 DB의 속도가 느려질수 있다.
        
        따라서 fileField에 reference만 저장하는 방법으로 해결을 할수 있다.

    6. 범용관계 피하기

    범용관계란 한 테이블로 부터 다른 테이블을 서로 제약조건 없는 foreign key로 바인딩 하는것

    문제점 : 모델간의 인덱싱이 존재하지 않으면 쿼리속도에 손해
                다른 테이블에 존재하지 않는 레코드를 참조할수있는 데이터 충돌 위험성

    하지만 앱을 새로 제작함에 있어 편하기에 즐겨찾기, 태깅 등의 앱이 범용관계로 만들어 졌는데

    그래도 범용 관계와 GenericForeignKey 이용은 피하고
    범용관계가 필요하면 모델 디자인을 바꿔보자
    불가피하게 이용해야한다면 서드 파티 앱을 사용해보자 외부앱의 경우 데이터를 깔끔하게 유지하는데 도움을 준다



모델의 _mata API



    _meta기능이 필요한 이유
    
        모델 필드의 리스트를 가져올때
        모델의 특정필드의 클래스를 가져올때(혹은 상속관계나 상속을 통해 생성된 정보)
        정보를 어떻게 가져오게 되었는지 확실하게 상수로 남기려고

    _mata기능이 필요할때

        장고 모델의 자체 검사도구
        라이브러리를 이용해 특별하게 customizing된 장고를 만들때
        장고의 모델 데이터를 조정하거나 변경할수있는 관리도구 제작할때
        시각화 또는 분석 라이브러리를 제작할때

        추가로 알아보기 위해선 django공식문서를 참고해보자


모델 매니저


    모델에 질의를 던지면 장고의 ORM을 통하게 되는데
    이때 model manager라는 DB와 연동하는 interface를 호출한다
    우리가 원하는 클래스를 제어하기위해 모델 클래스의 모든 인스턴스 세트에 작동

    기본 모델 매니저를 제공하지만 우리가 제작할수도 있다.
    이때 기존 모델 매니저를 교체하는 것이 좋아보이는데 이 방법은 주의를 기울여야하고
    모델 클래스에서 objects = models.Manager()을 커스텀 모델 매니저 위에 정의해주자




거대 모델 이해하기


    거대모델은 데이터 관련 코드를 뷰나 템플릿에 넣기 보다 모델 메서드, 클래스 메서드,       특성, 심지어는 매니저 메서드 안에 넣어서 캡슐화 하는것

    이럴경우 어떤 뷰나 다른 작업이라도 로직을 이용할수 있기때문이다.
     거대모델은 코드재사용을 개선할수 있는 최고의 방법이다

    그런데! 모든 로직을 모델 안으로 넣으려는데 따르는 문제점은
    모델의 크기를 흔히 신의 객체 (god object)수준으로 증가시키는데 있다.
    이런경우 이해도 어렵고 테스트, 유지보수도 어려워진다

    따라서 로직을 모델로 이전할때 객체지향의 아이디어를 염두해두며 코드를 분리하자
    로직들을 모델 행동이나 상태없는 헬퍼함수로 이전한다(클래스메서드,메서드,특성은 유지)


    모델 행동


    믹스인을 통한 캡슐화와 구성화의 개념으로 이루어졌다
    모델은 추상화 모델로부터 로직을 상속
    참고 : http://blog.kevinastone.com/django-model-behaviors.html
 

    상태없는 헬퍼함수

    
    모델로부터 로직을 떼어내 유틸함수로 넣으면 독립적인 구성이 가능해지고
    테스트가 쉬워진다 단 자신의 상태를 안가지기에 많은 인자를 필요로 한다


정리하면서


즉 모델은 기본적으로 정규화를 하고 다른 선택지를 고려해 봄에도 없으면 비정규화를 하자

그리고 index를 사용하자(프로젝트 전반에 데이터 이용이 익숙해 졌다면)

상속을 하려하면 멀티 모델이 아닌 추상화 기초 클래스로 상속하자

null과 blank 옵션은 주의해서 사용하자
django-model-utils 와 django-extensions를 유용하게 사용할수도 있을것

거대 모델 또한 주의해서 사용하자

출처 : two scoops of django

댓글 1개:

가장 많이 본 글