728x90

7. 쿼리와 데이터베이스 레이어

7-1. 단일 객체에서 get_object_or_404()사용하기

- 단일 객체를 가져오는 세부 페이지와 같은 뷰에서는 get()대신 get_object_or_404()를 사용해준다.

- 해당 객체가 없을경우, 예외처리를 동시에 해주는 유용한 함수 이므로 애용해줘야한다.

- 꼭 뷰에서만 사용하는 걸 권장한다. 뷰를 제외한 곳에서의 사용은 최대한 지양하도록 해야한다.

    - 예전의 사례에서 보면, 뷰가 아닌 여러곳에서 애용하다가 특정 데이터를 지웠을때 모든 페이지에 문제가 생기는 결과가 나타났으므로 굳이 위험한 행동을 사서 하지 않길 바란다.

 

7-2. 예외를 일으킬 수 있는 쿼리를 주의하자

- get_object_or_404를 이용하면 예외처리가 필요없지만 그 외의 모든 경우엔 try-except로 예외처리를 할 필요가 있다.

- ObjectDoesNotExist와 DoesNotExist

    - ObjectDoesNotExist는 어떤 모델에서도 사용가능함

    - DoesNotExist는 특정 모델에서만 사용가능함

def list_flavor_line_item(sku):
    try:
        return Flavor.objects.get(sku=sku, quantity__gt=0)
    excepy Flavor.DoesNotExist:
        msg = "We are out of {0}".format(sku)
        raise OutOfStock(msg)
        
def list_any_line_item(model, sku):
    try:
        return model.objects.get(sku=sku, quantity__gt=0)
    except ObjectDoesNotExist:
        msg = "We are out of {0}".format(sku)
        raise OutOfStock(msg)

-MultipleObjectsReturned

    -여러개의 객체가  반환되었을때 사용

def list_flavor_line_item(sku):
    try:
        return Flavor.objects.get(sku=sku, quantity__gt=0)
    except Flavor.DoesNotExist:
        msg = "We are out of {0}".format(sku)
        raise OutOfStock(msg)
    except Flavor.MultipleObjectReturned:
        msg = "Multiple items have SKU {}. Please fix!".format(sku)
        raise CorruptedDatabase(msg)

7-3. 쿼리를 좀 더 명확하게 하기 위해 지연 연산 이용하기

- 복잡한 쿼리의 경우 한줄에 모두 표현하는것은 최대한 지양해야한다.

- 지연 연산(lazy evaluation): 정말로 데이터가 필요하기 전까지는 장고가 sql을 호출하지 않는 특징

- 지연 연산을 이용해서 여러 쿼리를 여러줄에 나누어 좀더 간결하고 명확하게 구성한 코드 작성이 중요하다.

 

7-4. 필수 불가결한 상황이 아니라면 로우 sql 이용은 지양하자

 

7-5. 필요에 따라 인덱스를 이용하자

- 모델에 index=True만으로 추가가 가능하다

- 하지만 언제 사용을 해야하는지를 결정하고 적절히 사용하는것이 인덱스사용에 가장 중요하다.

 

7-6. 트랜잭션

- 장고는 기본적으로 orm이 모든 쿼리를 호출할 때마다 자동으로 커밋을 진행한다.

    - 매번 .create()나 .update()가 수행 될때마다 sql 값들이 변함을 뜻함

    - 단순 토이 프로젝트 수준에서는 문제없이 편하다고 생각할 수 있겠지만 만약 데이터 베이스상의 충돌이 발생했을때부터는 위험성이 존재하게 되었다는 것을 뜻한다.

- 트랜잭션의 기본 특성 ACID를 이해하고 적용해야 한다.

 

7-6-1. 각각의 HTTP요청을 트랜잭션으로 처리하라

#settings/base.py

DATABASES = {
    'default': {
        ...
        'ATOMIC_REQUESTS': TRUE,
    },
}

- 위와 같이 처리하면 읽기 데이터를 포함한 각요청마다 트랜잭션으로 처리할 수 있게 된다. 이는 데이터베이스 쿼리가 보호되는 안정성을 얻을 수 있지만 단점은 성능 저하를 가져올 가능성이 굉장히 높아질 수 있다는것 이다.

- 이를 해결하기 위해서는 transaction.non_atomic_requests()데코레이터를 선택한다.

    - 모든 요청에 트랜잭션이 아닌 데이터베이스의 영향이 가는작업(create, update, delete)시에만 트랜잭션을 선택적으로 적용해주는 것이다.

 

7-6-2. 명시적인 트랜잭션 선언

-트랜잭션 가이드라인

    1. 데이터베이스에 변경이 생기지 않는 데이터베이스 작업은 트랜잭션으로 처리하지 않는다.

    2. 데이터베이스에 변경이 생기는 데이터베이스 작업은 반드시 트랜잭션으로 처리한다.

- django orm에 기반한 가이드라인

목적 orm 메서드 트랜잭션을 이용할 것인가?
데이터 생성 create(), bulk_create(), get_or_create() yes
데이터 가져오기 get(), filter(), count(), iterate(), exist(), exclude(), in_bulk() no
데이터 수정하기 update() yes
데이터 삭제하기 delete() yes

 

정리

- 장고로 crud를 만드는걸 넘어서서 한단계 더 나아가려면 바로 이런 트랜잭션, 인덱스, 캐시 사용과 같은 것을 다룰수 있어야 한다고 생각이 든다. 신입이라면, 회사의 코드를 확인하며 어떻게 적용하고 있는지에 대해서 알아볼 수 있는 기회가 있을것이라 생각된다!

728x90

+ Recent posts