django QuerySet 기본
Model Manager
데이터베이스의 질의 인터페이스를 제공
디폴트 Manager 로서 ModelCls.objects 가 제공
# SELCT * FROM app_model;
ModelsCls.objects.all()
# SELCT * FROM app_model ORDER BY ID DESC LIMIT 10;
ModelsCls.objects.all().order_by('-id')[:10]
# INSERT INTO app_model (title) VALUES ("New Title");
ModelsCls.objects.create(title="New Title")
>>> qs = Post.objects.all()
>>> print(qs)
<QuerySet [<Post: 첫번째 메세지>, <Post: 두번째 메세지>, <Post: 세번째 메세지>]>
>>>
>>> print(type(qs))
<class 'django.db.models.query.QuerySet'>
>>>
print(qs.query)
SELECT "instagram_post"."id", "instagram_post"."message", "instagram_post"."photo", "instagram_post"."is_public", "instagram_post"."created_at", "instagram_post"."updated_at" FROM "instagram_post"
>>>
오름차순
- 단, 여러개의 필드를 정렬할 수 있지만
1~2개 정도만 정렬을하고
그 이상은 성능저하를 야기 시킬수 있기 때문에
사용하지 않는다.
ex) order_by('id', 'is_pulic')
>>> qs = Post.objects.all().order_by('id')
>>> print(qs.query)
SELECT "instagram_post"."id", "instagram_post"."message", "instagram_post"."photo", "instagram_post"."is_public", "instagram_post"."created_at", "instagram_post"."updated_at" FROM "instagram_post" ORDER BY "instagram_post"."id" ASC
>>>
>>> qs
<QuerySet [<Post: 첫번째 메세지>, <Post: 두번째 메세지>, <Post: 세번째 메세지>]>
>>>
## id 에 대해서 내림차순
>>> qs = Post.objects.all().order_by('-id')
>>> print(qs.query)
SELECT "instagram_post"."id", "instagram_post"."message", "instagram_post"."photo", "instagram_post"."is_public", "instagram_post"."created_at", "instagram_post"."updated_at" FROM "instagram_post" ORDER BY "instagram_post"."id" DESC
>>> qs
<QuerySet [<Post: 세번째 메세지>, <Post: 두번째 메세지>, <Post: 첫번째 메세지>]>
>>>
내림차순
- 단, 여러개의 필드를 정렬할 수 있지만
1~2개 정도만 정렬을하고
그 이상은 성능저하를 야기 시킬수 있기 때문에
사용하지 않는다.
ex) order_by('-id', '-is_pulic')
>>> qs = Post.objects.all().order_by('-id')[:2]
>>> print(qs.query)
SELECT "instagram_post"."id", "instagram_post"."message", "instagram_post"."photo", "instagram_post"."is_public", "instagram_post"."created_at", "instagram_post"."updated_at" FROM "instagram_post" ORDER BY "instagram_post"."id" DESC LIMIT 2
>>> qs
<QuerySet [<Post: 세번째 메세지>, <Post: 두번째 메세지>]>
>>>
순회 가능 (for, loop 가능하다)
>>> for post in qs:
... print(post.id, post.message, post.created_at)
... print("id: {id}, message: {message} {created_at}".format(**post.__dict__))
...
4 세번째 메세지 2022-01-12 11:07:37.336965+00:00
id: 4, message: 세번째 메세지 2022-01-12 11:07:37.336965+00:00
2 두번째 메세지 2022-01-11 10:56:29.125509+00:00
id: 2, message: 두번째 메세지 2022-01-11 10:56:29.125509+00:00
>>>
QuerySet은 Chaining 을 지원
- 속성에 따라서 filter 를 사용하는 것이 다름.
- (ex) message__startswith='첫번째'
message 필드에서 첫번째로 시작하는 것을 필터링
- (ex) message__startswith='첫번째'
- TIP. 한줄이 길어지면
\
사용
>>> qs = Post.objects.all().filter(message__startswith='첫번째')
>>> print(qs.query)
SELECT "instagram_post"."id", "instagram_post"."message", "instagram_post"."photo", "instagram_post"."is_public", "instagram_post"."created_at", "instagram_post"."updated_at" FROM "instagram_post" WHERE "instagram_post"."message" LIKE 첫번째% ESCAPE '\'
>>> qs
<QuerySet [<Post: 첫번째 메세지>]>
>>>
>>> qs = Post.objects.all().filter(message__icontains='첫번째').order_by('-id')
>>> print(qs.query)
SELECT "instagram_post"."id", "instagram_post"."message", "instagram_post"."photo", "instagram_post"."is_public", "instagram_post"."created_at", "instagram_post"."updated_at" FROM "instagram_post" WHERE "instagram_post"."message" LIKE %첫번째% ESCAPE '\' ORDER BY "instagram_post"."id" DESC
>>> qs
<QuerySet [<Post: 첫번째 메세지>]>
>>>
>>> qs = Post.objects.all()\
... .filter(message__icontains='첫번째')\
... .order_by('-id')
>>>
>>> qs
<QuerySet [<Post: 첫번째 메세지>]>
>>>
QuerySet
- SQL 을 생성해주는 인터페이스
- 순회가능한 객체 (for, loop 에서 사용 가능)
- Model Manager 를 통해, 해당 Model 에 대한 QuerySet 을 획득
- Post.objects.all() 코드는 "SELECT * FROM post ...;"
- Post.objects.create(...) 코드는 "INSERT INTO ...;"
- QuerySet은 Chaining 을 지원
- Post.objects.all().filter(...).exclude(...).filter(...)
- QuerySet은 Lazy한 특성
- QuerySet을 만드는 동안에는 DB접근을 하지 않는다.
- 실제로 데이터가 필요한 시점에 접근을 합니다.
- 데이터가 필요한 시점은 언제?
1) queryset- repr : 파이썬 인터프리터를 위한 것, API를 인터프리터로 사용할 때 즉시 결과를 볼 수 있다.
3) list(queryset)
4) for instance in queryset: print(instance)
- 데이터가 필요한 시점은 언제?
다양한 조회 요청 방법 (SECLT SQL 생성)
조건을 추가한 Queryset, 획득할 준비
- queryset.filter(...) -> queryset
- queryset.exclude(...) -> queryset
# filter : WHERE 문
>>> qs = Post.objects.all().filter(message__icontains='첫번째').order_by('-id')
>>> print(qs.query)
SELECT "instagram_post"."id", "instagram_post"."message", "instagram_post"."photo", "instagram_post"."is_public", "instagram_post"."created_at", "instagram_post"."updated_at" FROM "instagram_post" WHERE "instagram_post"."message" LIKE %첫번째% ESCAPE '\' ORDER BY "instagram_post"."id" DESC
>>>
# exclude : WHERE NOT 문
>>> qs = Post.objects.all().exclude(message__icontains='첫번째').order_by('-id')
>>> print(qs.query)
SELECT "instagram_post"."id", "instagram_post"."message", "instagram_post"."photo", "instagram_post"."is_public", "instagram_post"."created_at", "instagram_post"."updated_at" FROM "instagram_post" WHERE NOT ("instagram_post"."message" LIKE %첫번째% ESCAPE '\') ORDER BY "instagram_post"."id" DESC
>>> qs
<QuerySet [<Post: 세번째 메세지>, <Post: 두번째 메세지>]>
>>>
특정 모델객체 1개 획득을 시도
- queryset[숫자인덱스]
- 모델 객체 혹은 예외발생 (IndexError)
>>> qs = Post.objects.all()
>>> qs[1]
<Post: 두번째 메세지>
>>> qs[0]
<Post: 첫번째 메세지>
>>>
>>> qs[3]
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/root/django-with-react-study/venv/lib/python3.8/site-packages/django/db/models/query.py", line 318, in __getitem__
return qs._result_cache[0]
IndexError: list index out of range
- queryset.get(...)
- 모델 객체 혹은 예외 발생 (DoseNotExist, MultipleObjectsReturned)
>>> qs = Post.objects.all()
>>> qs.get(pk=1)
<Post: 첫번째 메세지>
>>> qs.get(pk=2)
<Post: 두번째 메세지>
>>>
>>> qs.get(pk=3)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/root/django-with-react-study/venv/lib/python3.8/site-packages/django/db/models/query.py", line 435, in get
raise self.model.DoesNotExist(
instagram.models.Post.DoesNotExist: Post matching query does not exist.
>>>
# lte: less than equal
>>> qs.get(id__lte=2)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/root/django-with-react-study/venv/lib/python3.8/site-packages/django/db/models/query.py", line 439, in get
raise self.model.MultipleObjectsReturned(
instagram.models.Post.MultipleObjectsReturned: get() returned more than one Post -- it returned 2!
>>>
- queryset.first()
- 모델 객체 혹은 None
>>> qs = Post.objects.all()
>>> qs.first()
<Post: 첫번째 메세지>
>>>
>>> qs.none()
<QuerySet []>
>>> qs.none().first()
>>>
- queryset.last()
- 모델 객체 혹은 None
>>> qs = Post.objects.all()
>>> qs.last()
<Post: 세번째 메세지>
>>>
filter < - > exclude
- filter 와 exclude는 서로 반대되는 개념
- SELECT 쿼리에 WHERE 조건 추가
- 인자로 '필드명 = 조건값' 지정
- 1개 이상의 인자 지정 -> 모두 AND 조건으로 묶임.
>>> qs = Post.objects.all()
>>> qs = qs.exclude(id__gte=2, message__icontains="첫번째")
>>> print(qs.query)
SELECT "instagram_post"."id", "instagram_post"."message", "instagram_post"."photo", "instagram_post"."is_public", "instagram_post"."created_at", "instagram_post"."updated_at" FROM "instagram_post" WHERE NOT ("instagram_post"."id" >= 2 AND "instagram_post"."message" LIKE %첫번째% ESCAPE '\')
>>> qs
<QuerySet [<Post: 첫번째 메세지>, <Post: 두번째 메세지>, <Post: 세번째 메세지>]>
>>>
>>>
>>> qs = Post.objects.all()
>>> qs = qs.filter(id__gte=2, message__icontains="첫번째")
>>> print(qs.query)
SELECT "instagram_post"."id", "instagram_post"."message", "instagram_post"."photo", "instagram_post"."is_public", "instagram_post"."created_at", "instagram_post"."updated_at" FROM "instagram_post" WHERE ("instagram_post"."id" >= 2 AND "instagram_post"."message" LIKE %첫번째% ESCAPE '\')
>>> qs
<QuerySet []>
>>>
- OR 조건을 묶으려면, django.db.models.Q 활용
>>> from django.db.models import Q
>>> qs = Post.objects.all()
>>> qs = qs.filter(Q(id__gte=2) | Q(message__icontains="첫번째"))
>>> qs.query
<django.db.models.sql.query.Query object at 0x7f68dbe7ab80>
>>> print(qs.query)
SELECT "instagram_post"."id", "instagram_post"."message", "instagram_post"."photo", "instagram_post"."is_public", "instagram_post"."created_at", "instagram_post"."updated_at" FROM "instagram_post" WHERE ("instagram_post"."id" >= 2 OR "instagram_post"."message" LIKE %첫번째% ESCAPE '\')
>>> qs
<QuerySet [<Post: 첫번째 메세지>, <Post: 두번째 메세지>, <Post: 세번째 메세지>]>
>>>
>>> qs = Post.objects.all()
>>> cond = Q(id__gte=2) | Q(message__icontains='첫번째')
>>> qs = qs.filter(cond)
>>> print(qs.query)
SELECT "instagram_post"."id", "instagram_post"."message", "instagram_post"."photo", "instagram_post"."is_public", "instagram_post"."created_at", "instagram_post"."updated_at" FROM "instagram_post" WHERE ("instagram_post"."id" >= 2 OR "instagram_post"."message" LIKE %첫번째% ESCAPE '\')
>>> qs
<QuerySet [<Post: 첫번째 메세지>, <Post: 두번째 메세지>, <Post: 세번째 메세지>]>
>>>
필드 타입별 다양한 조건 매칭
주의) 데이터베이스 타입에 따라서 생성되는 SQL이 다릅니다.
숫자/날짜/시간 필드의 경우
1) 필드명__lt = 조건값
- less than
- 필드명 < 조건값
2) 필드명__lte = 조건값 - less than equal
- 필드명 <= 조건값
3) 필드명__gt = 조건값 - greater than
- 필드명 > 조건값
4) 필드명__gte = 조건값 - greater than equal
- 필드명 >= 조건값
문자열 필드의 경우
1) 필드명__startswith = 조건값
- 필드명 LIKE "조건값%"
2) 필드명__istartswith = 조건값 - 필드명 ILIKE "조건값%"
- I는 ignore case : 대소문자 구별 안함
3) 필드명__endswith = 조건값 - 필드명 LIKE "%조건값"
4) 필드명__iendswith = 조건값 - 필드명 ILIKE "%조건값"
- I는 ignore case : 대소문자 구별 안함
5) 필드명__contains = 조건값 - 필드명 LIKE "%조건값%"
6) 필드명__icontains = 조건값 - 필드명 ILIKE "%조건값%"
- I는 ignore case : 대소문자 구별 안함
정렬 조건 추가
SELECT 쿼리에 ORDER BY 추가
정렬 조건을 추가하지 않으면 일관된 순서를 보장받을 수 없음
DB에서 다수의 필드에 대한 정렬을 지원
하지만 가급적 단일 필드로 하는 것이 성능에 이익
시간숙/역순 정렬이 필요할 경우, ID 필드를 활용
정렬 조건을 지정하는 2가지 방법
- 모델 클래스의 Meta 속성으로 ordering 설정: list 로 지정
class Post(models.Model):
class Meta:
ordering = ['-id']
-
모든 Queryset에 order_by(...)에 지정
- queryset에서 order_by 를 지정했다면,
모델 클래스의 Meta 속성을 통해서 기본 정렬한게 무시됨.
- queryset에서 order_by 를 지정했다면,
>>> Post.objects.all().order_by('created_at')
SELECT "instagram_post"."id",
"instagram_post"."message",
"instagram_post"."photo",
"instagram_post"."is_public",
"instagram_post"."created_at",
"instagram_post"."updated_at"
FROM "instagram_post"
ORDER BY "instagram_post"."created_at" ASC
LIMIT 21
Execution time: 0.000249s [Database: default]
<QuerySet [<Post: 첫번째 메세지>, <Post: 두번째 메세지>, <Post: 세번째 메세지>]>
>>>
QuerySet에 범위 조건 추가
슬라이싱을 통한 범위조건 추가
- SELECT 쿼리에 OFFSET/LIMIT
- 슬라이싱 지원됨. 단, 역순슬라이싱은 지원 안됨
- 왜 지원이 안되는가? 데이터베이스에서 지원하지 않기 때문에
객체[start:stop:step]
- offset : start
- LIMIT : stop - start
- STEP은 Query에 대응되지 않음.
>>> Post.objects.all()[:2]
SELECT "instagram_post"."id",
"instagram_post"."message",
"instagram_post"."photo",
"instagram_post"."is_public",
"instagram_post"."created_at",
"instagram_post"."updated_at"
FROM "instagram_post"
ORDER BY "instagram_post"."id" DESC
LIMIT 2
Execution time: 0.000153s [Database: default]
<QuerySet [<Post: 세번째 메세지>, <Post: 두번째 메세지>]>
>>> Post.objects.all()[-2:]
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/root/django-with-react-study/venv/lib/python3.8/site-packages/django/db/models/query.py", line 294, in __getitem__
assert ((not isinstance(k, slice) and (k >= 0)) or
AssertionError: Negative indexing is not supported.
>>>
>>> Post.objects.all().order_by('id')[:2]
SELECT "instagram_post"."id",
"instagram_post"."message",
"instagram_post"."photo",
"instagram_post"."is_public",
"instagram_post"."created_at",
"instagram_post"."updated_at"
FROM "instagram_post"
ORDER BY "instagram_post"."id" ASC
LIMIT 2
Execution time: 0.000208s [Database: default]
<QuerySet [<Post: 첫번째 메세지>, <Post: 두번째 메세지>]>
>>>
- step 이 들어가면
STEP 사용하지 않으면 QuerySet 으로 return 됨.
STEP을 사용하면 List 로 return 이됨.- step 사용 X : <QuerySet [<Post: 두번째 메세지>, <Post: 첫번째 메세지>]>
- step 사용 O: [<Post: 두번째 메세지>, <Post: 첫번째 메세지>]
- STEP은 SQL에 개념이 없음.
STEP은 django의 QuerySet이 처리함. - 밑에 예제를 기준으로 [1:3] 만큼 SQL로 처리를 한 다음 django가
2
(STEP) 을 처리함.
>>> Post.objects.all()[1:3]
SELECT "instagram_post"."id",
"instagram_post"."message",
"instagram_post"."photo",
"instagram_post"."is_public",
"instagram_post"."created_at",
"instagram_post"."updated_at"
FROM "instagram_post"
ORDER BY "instagram_post"."id" DESC
LIMIT 2
OFFSET 1
Execution time: 0.000204s [Database: default]
<QuerySet [<Post: 두번째 메세지>, <Post: 첫번째 메세지>]>
>>>
>>> Post.objects.all()[1:3:1]
SELECT "instagram_post"."id",
"instagram_post"."message",
"instagram_post"."photo",
"instagram_post"."is_public",
"instagram_post"."created_at",
"instagram_post"."updated_at"
FROM "instagram_post"
ORDER BY "instagram_post"."id" DESC
LIMIT 2
OFFSET 1
Execution time: 0.000120s [Database: default]
[<Post: 두번째 메세지>, <Post: 첫번째 메세지>]
>>>
Author And Source
이 문제에 관하여(django QuerySet 기본), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@engineer_km/기본-django-QuerySet저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)