Query Set
- 쿼리셋은 모델로 DB의 데이터를 제어할 수 있도록 해주는 객체.
- ORM의 속성 3가지 : LazyLoading, Caching, EagerLoading
- 쿼리셋은 캐싱된 데이터를 재사용(Caching)해서 SQL 호출을 줄이고 연산을 최대한 지연(LazyLoading)시킨다.
- LazyLoading을 통해 N+1 문제가 발생할 수 있다. 문제를 피하기 위해 Eager Loading을 통해 해결해야 한다.
- Eager Loaing 메소드인 select_related()와 prefetch_related()를 사용해서 원하는 데이터를 한 번의 질의를 통해 반환받아 N+1문제를 방지할 수 있다.
- select_related() : Join을 사용한 정방향 참조 모델 Eager Loading.
- prefetch_related() : 추가 쿼리셋 역방향 참조 모델 Eager Loading.
주요 함수
get()
: 하나의 데이터만 반환받을 수 있기 때문에 2개 이상의 데이터가 존재하는 경우 예외 발생(MultipleObjectsReturned)
filter()
: 쿼리셋을 반환한다. 즉, 질의하지 않음. sql문의 where절로 생각하자.
first()
: 데이터가 존재하지 않을 때 예외가 발생하지 않고 None을 리턴한다. 조심스럽게 사용하거나 get()으로 호출해서 예외가 발생하도록 유도하자.
{field}__contains='keyword'
: sql의 Like
{field}__startswith='keword'
: 시작 문자열 Like
{field}__endswith='keword'
: 끝 문자열 Like
{field}__isnull=True/False
: isnull
{field}__in='keyword'
: 리스트 단위 검색
{field}__gt/lt/gte/lte={number}
: 초과, 미만, 이상, 이하
{field}__rnage=(a,b)
: between a and b
- AND절은 filter 내에 ,로 구분짓고 OR절은 django.db.models의 Q를 이용해서 필터내에서 사용하자.
- OR절 예시 :
Post.objects.filter( Q(title='keyword') | ~Q(content='keyword) )
~Q()의 ~는 NOT연산
- annotate() : annotate()에 선언된 값이 모델에서 프로퍼티로 사용된다. sql문의 as
- aggregate() : 통계 정보를 작성 결과값을 dictionary로 리턴
- 더 알아보기 : QuerySet API reference, Query
Subquery()
Subquery() : 공식 문서 예시
Exsits() : 존재 여부에 대한 True/False만 가짐.
SQL 사용하기
- raw() : 쿼리셋 자체를 SQL로 대체
- RawSQL() : 서브쿼리를 쿼리셋이 아닌 SQL로 작성.
트랜잭션
트랜잭션 제어
- @transaction.atomic 데코레이터를 사용하면 All or Nothing이 보장된다. 즉, 함수 내부에서 에러 발생 시 롤백된다.
배타적 잠금
- 장고 ORM은 배타적 잠금을 쿼리셋으로 선언할 수 있도록 select_for_update() 메서드를 제공한다.
- select_for_update()는 성능 저하와 데드락의 원인이 되기 때문에 중요한 비즈니스 로직에 사용하자.
매니저
장고는 모델과 쿼리셋을 매핑해서 사용할 수 있도록 매니저라는 모듈을 제공한다.
(우리가 흔히 쓰는 모델의 objects라는 인스턴스가 매니저)
- 매니저는 재사용이 가능한 메서드로 구성하자
- 매니저로 사용할 커스텀 쿼리셋 구현 시 커스텀 쿼리셋 내부에서 쿼리셋이 질의하지 않도록 한다.
- ForeignKey 또는 ManyToManyField를 선언하면 매핑되는 모델에 order_set이라는 관계 매니저가 생성된다.
- 관계 매니저 매서드로 create(), add(), set(), remove(), clear()를 사용할 수 있다.