django QuerySet API 공식문서

yo·2020년 12월 10일
0

No database activity actually occurs until you do something to evaluate the queryset.

queryset은 언제 evaluate되는가?

  1. Slicing
  2. pickling/Caching
  3. repr()
  4. len()
  5. list() 예시: entry_list = list(Entry.objects.all())
  6. bool() 예시: if Entry.objects.filter(headline="Test"):

queryset의 숫자를 구할 땐len()보다 count()가 더 효율적이다!

evaluate되지 않은 queryset을 slicing하면 결과로 evaluate 되지 않은 또다른 queryset이 반환된다.

filter()

복잡한 쿼리를 할 땐 Q를 사용하자.

order_by()

1) order_by(-"id") : 내림차순
2) order_by("id"): 오름차순
3) order_by("?"): 랜덤(참고로 이건 성능상 좋지 않다)
4) 두개 이상 조합할 땐(다른 모델도 가능) 아래처럼 쓸 수도 있다.
Entry.objects.order_by(Coalesce('summary', 'headline').desc())

-queryset.ordered :ordered여부에 따라 boolean반환
-a.objects.order_by("b").order_by("c") : 무조건 뒤에 order_by만 적용된다(c)
-unique하지 않은 값(예를 들면 이름)으로 ordering하면 같은 값 안에서는 매번 다르게 정렬 된다.
-ordering엔 비용이 따른다.

reverse()

-queryset.reverse()는 순서를 뒤집는다.
-파이썬의 '-'를 사용한 인덱싱과는 다르다. 장고는 뒤에서부터 접근하는 인덱싱을 지원 안한다.
-ordering이 안된 queryset에 reverse()를 쓰는건 의미 없다.

values()

-dictionary로 된 queryset을 반환한다. positional args로 필드명을 추가할 수 있다.
예시

# This list contains a Blog object.
>>> Blog.objects.filter(name__startswith='Beatles')
<QuerySet [<Blog: Beatles Blog>]>

# This list contains a dictionary.
>>> Blog.objects.filter(name__startswith='Beatles').values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>

args 더한 예시.

>>> Blog.objects.values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
>>> Blog.objects.values('id', 'name')
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>

-keyword args를 줄 수도 있다. 이땐 annotate()가 작동한다.

>>> from django.db.models.functions import Lower
>>> Blog.objects.values(lower_name=Lower('name'))
<QuerySet [{'lower_name': 'beatles blog'}]>

-이런 식의 예시도 가능하다.

SubCategory.objects.values('main_category__name', c=Count("subcategoryimage"))

<QuerySet [{'main_category__name': '여성 의류', 'c': 3}, {'main_category__name': '여성 의류', 'c': 3},

values_list()

-values()와 비슷하고 다만 tuple로 된 queryset을 반환한다.

flat=True

필드가 하나일 경우 flat=True해주면 하나의 튜플이 반환된다.

named=True

필드명까지 같이 출력된다.

>>> MainCategory.objects.values_list("id", "name")
<QuerySet [(1, '여성 의류'), (2, '여성 가방'), (3, '여성 슈즈'), (4, '여성 주얼리'), (5, '여성 시계'), (6, '여성 잡화'), (7, '남성 의류'), (8, '남성 가방'), (9, '남성 슈즈'), (10, '남성 주얼리'), (11, '남성 시계'), (12, '남성 잡화')]>
>>> MainCategory.objects.values_list("id", "name", named=True)
<QuerySet [Row(id=1, name='여성 의류'), Row(id=2, name='여성 가방'), Row(id=3, name='여성 슈즈'), Row(id=4, name='여성 주얼리'), Row(id=5, name='여성 시계'), Row(id=6, name='여성 잡화'), Row(id=7, name='남성 의류'), Row(id=8, name='남성 가방'), Row(id=9, name='남성 슈즈'), Row(id=10, name='남성 주얼리'), Row(id=11, name='남성 시계'), Row(id=12, name='남성 잡화')]>

values_list().get()

특정 필드의 특정 값을 구할 때 사용하면 된다.

>>> MainCategory.objects.values_list("name").get(id=1)
('여성 의류',)

values()와 values_list()는 특정 값을 찾을 때 유용하다.
MtM이나 많은 필드를 가져올 때는 그다지 적절하지 않다.

dates(field, kind, order='ASC')

-kind:

-year
-month
-week
-day

datetimes()

none()

-never returns any objects and no query will be executed.
-하지만, 결과값은 EmptyQuerySet의 instance이다.

>>> Entry.objects.none()
<QuerySet []>
>>> from django.db.models.query import EmptyQuerySet
>>> isinstance(Entry.objects.none(), EmptyQuerySet)
True

union()

intersection()

difference()

# Hits the database.
e = Entry.objects.get(id=5)

# Hits the database again to get the related Blog object.
b = e.blog
# Hits the database.
e = Entry.objects.select_related('blog').get(id=5)

# Doesn't hit the database, because e.blog has been prepopulated
# in the previous query.
b = e.blog

-filter와 select_related의 사용 순서는 상관없이 같은 결과를 만든다.

Entry.objects.filter(pub_date__gt=timezone.now()).select_related('blog')
Entry.objects.select_related('blog').filter(pub_date__gt=timezone.now())

defer(*fields)

textField처럼 너무 길거나, 파이썬 오브젝트로 변환시키는데 비용이 많이드는 필드인데, 심지어 불러와서 쓰이지도 않는 필드라면 defer(field)로 해당 필드를 retrieve하지 않을 수 있다.
-pk, 조인한 테이블의 fk는 defer가 안먹는다.

정규화에 대한 명언

If you are frequently loading and using a particular subset of your data, the best choice you can make is to normalize your models and put the non-loaded data into a separate model (and database table).

select_for_update()

tranjection이 끝날 때 까지 외부 영향을 차단한다.

profile
Never stop asking why

0개의 댓글