Study/Django

Django Model Queryset API / 장고 모델 쿼리셋 API

SoShin_ 2021. 12. 12. 12:28
반응형

Django에서는 Model을 정의하면 ORM을 통해 데이터베이스와 소통할 수 있는 API를 사용할 수 있습니다!

 

API 란?

<모델이름>.objects.all() # 모든 데이터 가져오기
<모델이름>.objects.get() # 조건에 맞는 데이터 1개 가져오기

API [ Application Programming Interface ] 란 애플리케이션에서 시스템의 기능을 제어할 수 있도록 만든 인터페이스를 말합니다.

쉽게 말하면 어떤 기능을 쉽게 사용할 수 있도록 만든 체계라고 할 수 있습니다!

위 코드처럼 model 에서 모든 데이터를 가져오게 하는 all() , 조건에 맞는 데이터 1개만 가져오는 get()  같은 명령어들이 모두 API입니다.


Queryset

Queryset은 Django Model의 데이터가 담겨있는 목록으로 파이썬의 리스트와 비슷한 형태를 가지고 있습니다. 

이러한 Queryset을 얻기 위해서 아래와 같은 'objects'를 이용합니다.

이 'objects'는 'Model Manager'라고 하는데 Model과 데이터베이스 간에 연산을 수행하는 역할을 합니다.

이 'objects'를 통해 데이터베이스와 연산해서 얻은 여러 모델 데이터가 담겨 있는 것이 바로 Queryset 입니다!

<model>.objects.all() # <model>의 모든 데이터 Queryset 가져오기

 


Queryset API

위에 설명했듯이 Queryset은 데이터베이스에서 가져온 여러 가지 모델 데이터가 담겨있는 리스트 같은 것인데요.

이런 Queryset을 사용자가 원하는 조건에 맞게 가져오기 위해 API를 사용해야 합니다.

 

Queryset을 반환 하는 API
API 설명 예시
all() 해당 모델 테이블의 모든 데이터 조회 Post.objects.all()
filter() 특정 조건에 맞는 모든 데이터 조회 Post.objects.filter(content__contains='coke')
exclude() 특정 조건을 제외한 모든 데이터 조회 Post.objects.exclude(title__contains='code')
order_by() 특정 조건으로 정렬된 데이터 조회(-를 붙이면 오름차순으로 정렬) Post.objects.order_by('-dt_created')
values() Queryset에 있는 모든 모델 데이터의 정보를 사전형으로 갖는 리스트 반환 Post.objects.all().values()

하나의 데이터 객체를 반환하는 API
API 설명 예시
get() 조건에 맞는 하나의 데이터 조회 Post.objects.get(id=1)
create() 하나의 데이터를 생성하고 해당 모델 데이터를 반환 Post.objects.create(title='Django Model API, context='Object API')
get_or_create() 조건에 맞는 데이터를 조회하고 해당 데이터가 없다면 새로 생성 후 생성된 모델 데이터를 반환 Post.objects.get_or_create(title='Learning Django', context='It's good’)
latest() 주어진 필드 기준으로 가장 최신의 모델 데이터를 반환 Post.objects.latest('dt_created')
first() 쿼리셋의 가장 첫번째 모델 데이터를 반환, 정렬하지 않은 쿼리셋이라면 pk를 기준으로 정렬 후 반환, 만약 데이터가 없다면 None Post.objects.order_by('title').first()
last() 연산된 쿼리셋의 가장 가지막 모델 데이터를 반환,만약 데이터가 없다면 None Post.objects.order_by('title').last()

그 외 API
exists() 연산된 쿼리셋에 데이터가 있다면 True 반환 Post.objects.get(pk=812).exists()
count() 쿼리셋의 데이터 개수를 정수로 반환 Post.objects.all().count()
update() 데이터를 수정할 때 사용(여러 데이터 또는 여러 필드를 한 번에 수정 가능),수정된 데이터의 개수를 정수로 반환 Post.objects.filter('dt_created'__yeaer=2021).update(context='codeit')→ 생성일이 2021년인 모든 포스트 데이터들의 context를 'codeit'으로 바꾸고 변경된 데이터의 개수를 리턴
delete() 데이터를 삭제할 때 사용 post = Post.objects.get(pk=1) post.delete()

필드 조건 옵션 (Field Lookups)

Queryset 연산을 할 때 사용할 수 있는 여러 필드 조건 옵션입니다. 필드명 뒤에 __ 를 쓰고 사용할 옵션 인자를 적어 주면 됩니다. 

옵션 설명 예시
__contains 대소문자를 구분하여 문자열 포함 여부 확인 Post.objects.get(title__contains='Codeit')
__icontains 대소문자를 구분하지 않고 문자열 포함 여부 확인 Post.objects.get(title__icontains='Codeit')
__in 반복 가능한 객체 안에서의 포함 여부를 확인 Post.objects.filter(id__in=[1, 2, 3])
__gt 초과 여부 확인 (Greater than) Post.objects.filter(id__gt=4)
__gte 이상 여부 확인 (Greater than or equal to) Post.objects.get(id__gte=4)
__lt 미만 여부 확인 (Less than) Post.objects.get(id__lt=4)
__lte 이하 여부 확인 (Less than or equal to) Post.objects.get(id__lte=4)
__startswith 대소문자를 구분하여 해당 문자열로 시작하는지 여부 확인 Post.objects.filter(title__startswith='code')
__istatswith 대소문자를 구분하지않고 해당 문자열로 시작하는지 여부 확인 Post.objects.filter(context__istartswith='code')
__endswith 대소문자를 구분하여 해당 문자열로 끝나는지 여부 확인 Post.objects.filter(title__endswith='code')
__iendswith 대소문자를 구분하지않고 해당 문자열로 끝나는지 여부 확인 Post.objects.filter(title_iendswith='code')
__range range로 제시하는 범위 내에 포함되는지 확인(시작과 끝 범위 모두 포함) import datetime
start_date = datetime.date(2021, 1, 1)
end_date = datetime.date(2021, 3, 1)

Post.objects.filter(dt_created__range=(start_date, end_date))
__isnull 해당 필드가 Null 인지 여부를 확인 Post.objects.filter(context__isnull=True)

Lazy Evaluation (지연연산)

Django의 모든 Query 연산은 병합(Chain)이 가능합니다. 예를 들어, Post 중에 id가 1 이상이면서 제목에 'test'가 들어가는 모든 데이터 중 가장 마지막에 작성된 데이터를 가져오고 싶다고 할 때, 코드는 아래와 같이 작성할 수 있습니다.

Post.objects.filter(id__gte=1, content__contains='test').order_by('-dt_created').last()

__gte를 통해 1 '이상', __contains를 통해 'test' 문자 포함 여부, order_by(-) 를 통해 정렬 후 last()를 이용해 가장 마지막 값을 가져옵니다.

이렇게 하나의 Query 연산에 여러 개를 체인으로 엮어서 구현하는 것이 코드를 짧게 작성하니까 좋다고 생각할 수 있지만 너무 많은 연산을 묶는 것은 지양해야 합니다.

모든 코드는 항상 명확하게 작성해야 합니다. 위처럼 하나의 Query에서 여러 연산을 수행하도록 하는 것은 가독성을 매우 떨어뜨리므로 복잡한 Query를 한 번에 체인으로 묶는 것은 피해야 합니다.

이럴 땐 아래 코드와 같이 작성하는 것이 좋습니다.

post_data = Post.objects.filter(id__gte=10, content__contains='codeit')
post_data = post_data.order_by('dt_created')
post_data = post_data.last()

하지만 이렇게 여러 개로 나누어 작성할 경우 코드가 느려질 수도 있다고 걱정할 수 있지만 그렇지 않습니다.

Django의 Query는 기본적으로 지연 연산을 지원하기 때문입니다.

지연 연산이란 실제로 데이터가 필요하기 전까지 Query 연산을 수행하지 않고 지연 [ lazy ] 하는 것을 말합니다.

첫 번째로 작성한 것과 같이 체인을 통해 한 줄로 적은 것과 두 번째처럼 여러 줄로 나누어 작성하는 것이 결국 같은 시점에 연산을 수행하게 되는 것입니다.

그래서 한 줄에 모든 Query 연산과 기능을 작성하는 것 대신 여러 줄에 얼마든지 Query를 연결해서 작성할 수 있고, 이것은 가독성을 엄청나게 크게 향상시키고 유지보수를 편리하게 해 줍니다.

반응형