Django Queryset

chan9708·2022년 6월 28일
0

Django

목록 보기
8/12
post-thumbnail

Queryset ?

Queryset전달받은 모델의 객체 목록을 지칭합니다.

쿼리셋을 이용하면 데이터베이스로부터 데이터를 읽고 필터를 걸거나 정렬 등을 할 수 있습니다.
리스트와 구조는 같지만 파이썬 기본 자료구조가 아니기에 읽고 쓰기 위해서는 자료형 변환을 해줘야합니다.
쿼리셋은 데이터베이스의 여러 레코드(row)를 나타냅니다.

from instagram.models import Post

qs = Post.objects.all()
print(type(qs))
print(qs.query)
print(qs)
# 결과
<class 'django.db.models.query.QuerySet'>
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"
<QuerySet [<Post: 첫번째 메세지>, <Post: 두번째 메세지>, <Post: 세번째 메세지>]>

여기서 objectsModel Manager입니다.
Model manager는 DB와 Django Model 사이의 Query Operation(질의연산)의 인터페이스 역할을 합니다.
이 때, objects 를 사용해서 다수의 데이터를 갖고오는 함수를 사용할 때, 반환되는 객체가 QuerySet입니다.

이 Manager 각 모델(클래스)가 최소 하나씩 가지고 있습니다.
Person.objects 의 의미는, objects라는 이름의 manager가 Person 데이터베이스를 QuerySet 형태로 만들겠다는 의미입니다.
그 QuerySet에서 데이터를 검색하게 만들 수 있습니다.


Queryset Method

Create - 데이터 생성 및 입력

  • SQL의 Insert
  • .create() 와 .save() 방식이 존재합니다.

create()

>>> from instagram.models import Post
>>> Post.objcets(author="lim", message="Hello, World")

save()

>>> from instagram.models import Post
>>> post = Post.objcets(author="lim", message="Hello, World")
>>> post.save()

Read - 데이터 조회

  • SQL의 SELECT
  • objects를 통해 가져온 QuerySet에서 조건에 따른 객체를 가져오는 메소드

all()

: 모든 raw들을 가져오는 메소드

>>> Post.objects.all()
<QuerySet [<Post: 네번째 메세지>, <Post: 세번째 메세지>, <Post: 두번째 메세지>, <Post: 첫번째 메세지>]>

value()

: queryset 결과의 내용을 dictionary(딕셔너리)형태의 element를 담은 리스트형태로 반환

>>> Post.objects.values()
<QuerySet [{'id': 4, 'author_id': 1, 'message': '네번째 메세지', 'photo': '', 'is_public': True, 'created_at': datetime.datetime(2022, 6, 24, 15, 29, 51, 705567, tzinfo=<UTC>), 'updated_at': datetime.datetime(2022, 6, 25, 15, 52, 51, 478616, tzinfo=<UTC>)}, {'id': 3, 'author_id': 1, 'message': '세번째 메세지', 'photo': 'instagram/post/2022/06/24/배경.png', 'is_public': True, 'created_at': datetime.datetime(2022, 6, 23, 4, 51, 46, 920689, tzinfo=<UTC>), 'updated_at': datetime.datetime(2022, 6, 24, 5, 21, 42, 626249, tzinfo=<UTC>)}, {'id': 2, 'author_id': 1, 'message': '두번째 메세지', 'photo': '', 'is_public': False, 'created_at': datetime.datetime(2022, 6, 23, 4, 51, 41, 119409, tzinfo=<UTC>), 'updated_at': datetime.datetime(2022, 6, 23, 4, 51, 41, 119409, tzinfo=<UTC>)}, {'id': 1, 'author_id': 1, 'message': '첫번째 메세지', 'photo': '', 'is_public': False, 'created_at': datetime.datetime(2022, 6, 23, 4, 51, 36, 164431, tzinfo=<UTC>), 'updated_at': datetime.datetime(2022, 6, 23, 4, 51, 36, 164431, tzinfo=<UTC>)}]>

values_list()

: queryset 결과의 내용을 tuple(튜플)형태의 element를 담음 리스트형태로 반환
: key는 없고, 오로지 value만 튜플형태로 담습니다.

>>> User.objects.values_list()
<QuerySet [(4, 1, '네번째 메세지', '', True, datetime.datetime(2022, 6, 24, 15, 29, 51, 705567, tzinfo=<UTC>), datetime.datetime(2022, 6, 25, 15, 52, 51, 478616, tzinfo=<UTC>)), (3, 1, '세번째 메세지', 'instagram/post/2022/06/24/배경.png', True, datetime.datetime(2022, 6, 23, 4, 51, 46, 920689, tzinfo=<UTC>), datetime.datetime(2022, 6, 24, 5, 21, 42, 626249, tzinfo=<UTC>)), (2, 1, '두번째 메세지', '', False, datetime.datetime(2022, 6, 23, 4, 51, 41, 119409, tzinfo=<UTC>), datetime.datetime(2022, 6, 23, 4, 51, 41, 119409, tzinfo=<UTC>)), (1, 1, '첫번째 메세지', '', False, datetime.datetime(2022, 6, 23, 4, 51, 36, 164431, tzinfo=<UTC>), datetime.datetime(2022, 6, 23, 4, 51, 36, 164431, tzinfo=<UTC>))]>

first()

: queryset 결과의 내용 중 가장 첫번째 row만 반환

>>> post = Post.objects.all()
<QuerySet [<Post: 네번째 메세지>, <Post: 세번째 메세지>, <Post: 두번째 메세지>, <Post: 첫번째 메세지>]>
>>> post.first()
<Post: 네번째 메세지>

last()

: queryset 결과의 내용 중 가장 마지막 row만 반환

>>> post = Post.objects.all()
<QuerySet [<Post: 네번째 메세지>, <Post: 세번째 메세지>, <Post: 두번째 메세지>, <Post: 첫번째 메세지>]>
>>> post.last()
<Post: 첫번째 메세지>

count()

: queryset 결과의 row의 갯수를 반환

>>> post = Post.objects.all()
<QuerySet [<Post: 네번째 메세지>, <Post: 세번째 메세지>, <Post: 두번째 메세지>, <Post: 첫번째 메세지>]>
>>> post.count()
4

get()

: 하나의 row만 가져오기 위해 사용하는 메소드
: .get() 뒤에 다른 메소드를 추가할 수 없습니다.
: Unique 한 값을 조건으로 조회합니다.
: 조건을 .get()의 매개변수로 지정합니다.
: 조건에 따른 조회 결과가 없을 경우, DoesNotExist 메세지 발생합니다.
: 한 개 이상의 값을 반환할 경우, MultipleObjectsReturned 메세지 발생합니다.
: 리스트 형태의 queryset으로 반환합니다.

>>> from instagram.models import Post
>>> post = Post.objects.get(message = "첫번째 메세지)
<User: User object (4)>

filter()

: 하나 이상의 row들을 가져오기 위해 사용하는 메소드
: 조건을 .filter()의 매개변수로 지정합니다.
: 조건에 따른 조회 결과가 없을 경우, DoesNotExist 메세지 발생합니다.
: 객체 형태의 queryset으로 반환합니다.

  • .exists()
    • DB에서 filter를 통해 원하는 조건의 데이터 유무에 따라 True, False 를 반환합니다.
  • .reverse()
    • 역순으로 반환한다. 즉, 쿼리셋의 순서를 반대로 변경합니다.
  • .select_related()
    • ForeignKey나 OneToOneField에 사용이 가능합니다.
    • 쿼리를 실행할 때 추가적인 관련 객체 데이터를 선택해서 외래키 관계를 팔로우 할 QuerySet을 반환합니다.
>>> from instagram.models import Post
>>> Post.objects.filter(is_public=True)
<QuerySet [<Post: 네번째 메세지>, <Post: 세번째 메세지>]>

exclude()

: 특정 조건을 제외한 나머지 row들을 가져오기 위해 사용하는 메소드
: 조건을 .exlude()의 매개변수로 지정
: 조건에 일치하지 않는 객체를 포함한 queryset으로 반환

>>> from instagram.models import Post
>>> Post.objects.exclude(is_public=True)
<QuerySet [<Post: 두번째 메세지>, <Post: 첫번째 메세지>]>

AND, OR 조건()

: .filter() 메소드 사용 시, 두개 이상의 조건을 AND 또는 OR로 사용이 가능합니다.
: 단, OR 조건을 사용하기 위해서는 django의 Q객체가 필요합니다.

>>> from django.db.models import Q
>>> query = '첫번째'

# AND 조건
>>> qs = qs.filter(Q(id__gte=1) & Q(message__icontains=query)) 
# OR 조건
>>> qs = qs.filter(Q(id__gte=1) | Q(message__icontains=query))

>>> print(qs1)
>>> print(qs2)

<QuerySet [<Post: 첫번째 메세지>]>
<QuerySet [<Post: 네번째 메세지>, <Post: 세번째 메세지>, <Post: 두번째 메세지>, <Post: 첫번째 메세지>]>

Update - 데이터 수정

  • SQL의 UPDATE
  • 이미 존재하는 객체에 대한 필드값을 수정하는 메소드

save()

: 한 개의 객체에 대해 수정할 경우 사용하는 메소드

>>> post = Post.objects.get(message="첫번째 메세지")
>>> post.message 
'첫번째 메세지'
>>> post.message = "첫번째 포스팅"
>>> post.save()
>>> post.message
'첫번째 포스팅'

update()

: 여러개의 객체를 한꺼번에 수정할 경우 사용하는 메소드

>>> post = Post.objects.filter(is_public=True)
>>> post
<QuerySet [<Post: 네번째 메세지>, <Post: 세번째 메세지>]>
>>> post.update(is_public=False)

>>> use_post = Post.objects.filter(is_use=True)
>>> use_post
<QuerySet []>

Delete - 데이터 삭제

  • SQL의 DELETE절
  • 객체를 삭제하기 위해 사용하는 메소드

delete()

  • 한 개 이상 또는 모든 레코드를 삭제하는 메소드
# filter 조건에 의한 레코드 삭제
>>> post = Post.objects.filter(is_use=True)
>>> post
<QuerySet [<Post: Post object (1)>, <Post: Post object (2)>]>
>>> post.delete()
>>> post
<QuerySet [<Post: Post object (3)>, <Post: Post object (4)>, <Post: Post object (5)>]>


# all 조건에 의한 모든 레코드 삭제
>>> post = Post.objects.all()
<QuerySet [<Post: Post object (1)>, <Post: Post object (2)>, <Post: Post object (3)>, <Post: Post object (4)>]>
>>> post.delete()
>>> post
<QuerySet []>

CRUD를 제외한 메소드

order_by()

: queryset 결과를 지정하는 매개변수의 조건으로 정렬하는 메소드
: 기본 지정된 컬럼 기준 오름차순 정렬
: 내림차순 정렬 시 - 붙여서 매개변수로 지정
: ex) id 오름차순 기준 정렬 : order_by('id')
: ex) id 내림차순 기준 정렬 : order_by('-id')
: 랜덤 정렬을 원할 경우 ? 를 사용하면 된다.

>>> post = Post.objects.all().order_by('id')
>>> post
<QuerySet [<Post: 첫번째 메세지>, <Post: 두번째 메세지>, <Post: 세번째 메세지>, <Post: 네번째 메세지>]>

>>> post = Post.objects.order_by('?')
>>> post
<QuerySet [<Post: 첫번째 메세지>, <Post: 세번째 메세지>, <Post: 네번째 메세지>, <Post: 두번째 메세지>]>

slicing

: queryset 결과를 특정 지정 인덱스 기준으로 slicing(슬라이싱) 하는 방법
: iterable한 결과에서 슬라이싱 가능합니다.
: 역순 슬라이싱은 지원하지 않습니다.
: pagination 시 사용을 많이 합니다.

>>> post = Post.objects.all()[:2]
>>> post
<QuerySet [<Post: 네번째 메세지>, <Post: 세번째 메세지>]>

aggregate()

: 사전적의미로 '총액', '합계'라는 의미로 집계함수모듈를 사용시 사용하는 메소드
: 즉, 집계함수모듈 django의 Avg, Max, Min, Count, SUM등을 사용할 때 사용하는 메소드

집계함수란?
테이블의 여러 행이나 전체 행으로부터 하나의 값을 집계하여 반환하는 함수이다.
COUNT, SUM, AVG, MAX, MIN 등이 있다.

: 위 집계함수를 매개변수로 지정하여 사용
: 결과는 dictionary(딕셔너리)형태로 반환합니다.

>>> post = Post.objects.aggregate(Count('id'))
>>> post
{'id__count': 4}

annotate()

: 사전적의미로 '주석을 달다'라는 의미로 aggregate()는 queryset의 전체row에 대한 집계함수를 반환한 반면, annotate()는 각 컬럼별 주석을 달고 집계함수를 사용하여 반환한다
: 즉, SQL의 GROUP BY와 같은 의미로, queryset결과를 컬럼별 group by하여 반환합니다.
: 결과는 queryset(쿼리셋)형태로 반환합니다.

avg

: queryset 결과에서 특정 컬럼기준 평균값을 구할 때 사용하는 매개변수
: django.db.models의 Avg 모듈을 가져와야 합니다.
: Alias처럼 결과의 key값을 변경 가능합니다.

Max, Min

: queryset 결과에서 특정 컬럼기준 최대값 또는 최소값을 구할 때 사용하는 매개변수
: django.db.models의 Max, Min 모듈을 가져와야 합니다.
: Alias처럼 결과의 key값을 변경 가능합니다.

Count

: queryset 결과에서 특정 컬럼기준 count를 구할 때 사용하는 매개변수
: django.db.models의 Count 모듈을 가져와야 함
: Alias처럼 결과의 key값을 변경 가능

distinct()

: queryset 결과에서 중복되는 값을 제거하고 고유값만 반환하는데 사용하는 메소드
: SQL의 SELECT DISTINCT


: django의 objects가 데이터베이스에 접근 시 foreign key가 설정되어 있는 테이블들까지 조회하는 메소드
: SQL의 join
: OneTonOneField 관계 그리고 정방향으로 참조하는 형태로 조회합니다.
: 매개변수로는 참조키를 지정합니다.

>>> Post.objects.select_related('author').filter(id=1)
<QuerySet [<Post: 첫번째 메세지>]>

: select_related() 와 같이 foreign key가 설정되어 있는 테이블에서 사용하는 메소드
: OneTonOneField, ManyToManyField, ManyToOneField 관계 그리고 역방향으로 참조하는 형태로 조회합니다.
: models.py에서 ManyToManyField 또는 relate_name 매개변수로 지정된 키들을 참조해서 사용합니다.
: query를 확인해보면 역 참조되는 테이블과 참조하고 있는 테이블 각각 쿼리가 2번 실행됩니다.
: 테이블의 row수의 따라 참조 구성에 따라 query lazy 현상이 일어날 수 도 있습니다.
: 따라서 왠만하면 select_related() 사용을 권장합니다.

>>> Post.objects.prefetch_related('author').filter(id=1)
<QuerySet [<Post: 첫번째 메세지>]>

Reference

파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트
[Django] QuerySet by inyong_pang.log
Re:Django by magnoliarfsit.log
Django document_Aggregation
Django document_queryset_api_reference

profile
DevOps, Cloud, Back-End, Python에 관하여 관심이 많은 '임찬'입니다.

0개의 댓글