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를 만드는걸 넘어서서 한단계 더 나아가려면 바로 이런 트랜잭션, 인덱스, 캐시 사용과 같은 것을 다룰수 있어야 한다고 생각이 든다. 신입이라면, 회사의 코드를 확인하며 어떻게 적용하고 있는지에 대해서 알아볼 수 있는 기회가 있을것이라 생각된다!
'기술 > Django' 카테고리의 다른 글
처음부터 끝까지 kakao 소셜로그인 구현하기(feat. django) (1) | 2023.07.17 |
---|---|
django 배포 환경 구축하기(1) 환경 분리 (1) | 2023.05.20 |
two scoops of django - django에서 모델이란? (0) | 2022.09.01 |
two scoops of django - settings와 requirements 파일 (0) | 2022.08.31 |
two scoops of django - django 코딩 스타일 맞춰보기(2) (0) | 2022.08.30 |