No database activity actually occurs until you do something to evaluate the queryset.
entry_list = list(Entry.objects.all())
if Entry.objects.filter(headline="Test"):
복잡한 쿼리를 할 땐 Q를 사용하자.
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엔 비용이 따른다.
-queryset.reverse()
는 순서를 뒤집는다.
-파이썬의 '-'를 사용한 인덱싱과는 다르다. 장고는 뒤에서부터 접근하는 인덱싱을 지원 안한다.
-ordering이 안된 queryset에 reverse()를 쓰는건 의미 없다.
-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()와 비슷하고 다만 tuple로 된 queryset을 반환한다.
필드가 하나일 경우 flat=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='남성 잡화')]>
특정 필드의 특정 값을 구할 때 사용하면 된다.
>>> MainCategory.objects.values_list("name").get(id=1)
('여성 의류',)
values()와 values_list()는 특정 값을 찾을 때 유용하다.
MtM이나 많은 필드를 가져올 때는 그다지 적절하지 않다.
-kind:
-year
-month
-week
-day
-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
# 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).
tranjection이 끝날 때 까지 외부 영향을 차단한다.