프로그래밍/Python

[Django] 장고 기초 - (5) Query Set(2)

Churnobyl 2023. 4. 27. 00:35
728x90
반응형

 

Chapter 06.  장고의 Queryset 2편 (Retrieve 심화)

 

지난 편에 이어서 QuerySet의 조회에 대한 상세한 내용을 정리했다. 

 

 


데이터 객체 조회하기 ⅱ(Retrieving objects)

 

 


단일한 데이터 객체 조회하기(Retrieving a single object with get())

  • get() : 단 하나의 데이터 객체만을 조회한다

 

filter()는 결과가 0개, 1개 혹은 여러개의 QuerySet을 불러올 때 사용할 수 있는 데 반해, get()단 하나의 결과 만을 얻어야 할 때 사용한다. get()은 결과가 0개라면 DoesNotExist(결과가 존재하지 않는다)를 발생(raise)시키고, 여러개라면 MultipleObjectsReturned(여러개의 결과가 리턴됐다)를 발생(raise)시킨다. 따라서 get()은 Primary Key처럼 레코드마다 고유한 값을 가지고 있는 속성을 조회할 때 사용할 수 있다.

 

 

 


데이터 객체 수 제한하기(Limiting QuerySets)

QuerySet의 개수를 제한하는 방법은 파이썬의 Slicing을 이용하면 된다.

아래의 예제들로 slicing을 사용한 각 케이스들의 결과를 보자

from articles.models import Article
article = Article.objects.filter(user_id=1)

# 1
article

# 2
article[:5]

# 3
article[-1]

# 4
article[::2]

# 5
article[::2].filter(title__contains="아")
# 1
<QuerySet [<Article: 야>,<Article: 아>, ... , <Article: 나폴리탄>]>

# 2
<QuerySet [<Article: 야>, <Article: 아>, <Article: 오예>, <Article: 오예>, <Article: 아이>]>

# 3
ValueError: Negative indexing is not supported.

# 4
[<Article: 야>, <Article: 오예>, <Article: 아이>, <Article: 수제비>, <Article: 새벽코딩>]

# 5
AttributeError: 'list' object has no attribute 'filter'

# 1

Article모델에서 user_id가 1인 QuerySet객체가 잘 출력되었다.

 

# 2

1번의 결과에서 slicing을 통해 0~4번 QuerySet객체가 잘 출력되었다

 

# 3

QuerySet을 slicing할 때 음수를 이용한 인덱싱은 지원하지 않는다

 

# 4

2step씩 건너뛰며 slicing을 한 경우에도 QuerySet은 잘 출력된다. 하지만 결과가 QuerySet객체가 아닌 파이썬 리스트 형태로 출력됐다는 점에 주목하자

 

# 5

4번의 결과에 다시 한번 filter()로 조회를 했을 때 AttributeError가 발생했다. QuerySet을 slicing할 때 step을 사용했다면 그 결과에 다시 필터링을 하거나 정렬하는 것은 금지된다.

 

 

 


필드 조회하기(Field lookups)

Field lookups은 SQL의 WHERE절과 같이 어떤 Field의 필터링을 할 때 사용한다. 이는 QuerySet메소드인 filter(), exclude(), get()의 키워드 인수(Keyword Arguments)에 적용해 사용할 수 있다. 형태는 field__lookuptype=value와 같이 던더스코어로 연결된 형태이다. 아래는 몇가지 lookuptype에 대한 예제들이다.(field lookups는 2023년 4월 24일 기준 24가지가 있다)

 

 

  • exact : 정확히 일치한다. lookup의 기본값
Article.objects.filter(title__exact="아")
Article.objects.filter(title="아")

둘의 결과는 완전히 같다. 이는 exact한 조회가 일반적인 형태이기 때문에 lookuptype이 없어도 장고가 알아서 exact한 값을 찾는 것으로 가정하기 때문이다.

 

 

  • iexact : 대소문자 구별하지 않고 정확히 일치한다.
article1 = Article.objects.create(user_id=1, title="Abcd", content="a") 
article2 = Article.objects.create(user_id=1, title="AbCD", content="a")    
article1.save()
article2.save()
Article.objects.filter(title__iexact="abcd")
<QuerySet [<Article: Abcd>, <Article: AbCD>]>

 

 

  • contains : 대소문자 관계없이 어떤 문자열을 포함한다.
article1 = Article.objects.create(user_id=1, title="Abcd", content="a") 
article2 = Article.objects.create(user_id=1, title="AbCD", content="a")    
article1.save()
article2.save()
Article.objects.filter(title__contains="Abc")
<QuerySet [<Article: Abcd>, <Article: AbCD>]>

 

 

  • in : iterable한 값 list, tuple, queryset을 포함한다. 자주 쓰진 않지만 문자열도 가능하다. SQL의 IN과 같다
from articles.models import Article
from users.models import User

# 1
Article.objects.filter(user_id__in=[2,3])


# 2
inner_qs = User.objects.filter(age__gte=20)
Article.objects.filter(user_id__in=inner_qs)
# 1
<QuerySet [<Article: 안녕하세요>, <Article: 안녕하세요 Ganet입니다>, <Article: 김치말이>, <Article: 오늘도>]>

# 2
<QuerySet [<Article: 야>, <Article: 아>, <Article: 오예>, <Article: 오예>, <Article: 아이>, <Article: 감자>, <Article: 수제비>, <Article: 마이클>, <Article: 새벽코딩>, <Article: 나폴리 탄>, <Article: Abcd>, <Article: AbCd>, <Article: Abcd>, <Article: Abcd>, <Article: AbCD>, <Article: 안녕하세요>, <Article: 안녕하세요 Ganet입니다>]>

# 1

위와 같이 list를 값으로 넣어 user_id중에 2, 3을 포함하는 레코드를 조회할 수 있다

 

# 2

inner_qs에 user테이블에서 age가 20 이상인 레코드를 저장하고 이걸 다시 article 테이블의 user_id를 포함하는 값만 추려서 출력했다. 이를 SQL문으로 보면 다음과 같다.

[
{'sql': 'SELECT "articles_article"."id", "articles_article"."user_id", "articles_article"."title", "articles_article"."content", "articles_article"."created_at", "articles_article"."updated_at" FROM "articles_article" WHERE "articles_article"."user_id" IN (SELECT U0."superduper_id" FROM "user" U0 WHERE U0."age" >= 20) LIMIT 21', 'time': '0.000'}
]

inner_qs에 values("필드명")을 한번 더 걸어서 비교할 필드를 user_id가 아닌 다른 필드로 바꿔줄 수도 있다

 

 

이외에도 대소를 비교하는 gt, gte, lt, lte, 시간 관련한 week, date, year, month, day, time, hour, minute, second,심지어 정규표현식으로 검색할 수 있는 regex까지 지원한다.

 

 

 

반응형