이번에는 django 쿼리셋(queryset)에 대해서 알아보겠습니다.
쿼리셋이란 무엇인가요?
핵심만 말하자면, 쿼리셋(QuerySet)은 전달받은 모델의 객체 목록입니다. 쿼리셋은 데이터베이스로부터 데이터를 읽고, 필터를 걸거나 정렬을 할 수 있습니다.
아래에서 예제와 함께 설명하겠습니다.
다룰 모델
아래에서 쿼리셋을 적용 시켜볼 모델 class입니다!
from django.conf import settings
from django.db import models
from django.utils import timezone
class Post(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(
default=timezone.now)
published_date = models.DateTimeField(
blank=True, null=True)
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
장고 쉘(shell)켜기
manage.py가 있는 디렉토리에 터미널 환경으로 접속해 아래의 명령어를 통해 잘고 쉘을 켜보세요
(venv) ~/djangogirls$ python manage.py shell
실행하면 아래처럼 나올 거에요.
(InteractiveConsole)
>>>
모델클래스명.objects.all()
모델 클래스의 오브젝트를 리스트로 모두 가져온다.
아래는 GuessNumbers 모델의 모든 객체를 조회하는 쿼리셋입니다.
ex)
$ python manage.py shell
>>> from mylotto.models import GuessNumbers
>>> import datetime
>>> Post.objects.all()
<QuerySet [<Post: my post title>, <Post: another post title>]>
여러분은 이제 장고 인터랙티브 콘솔(interactive console)로 들어왔습니다. 파이썬 프롬프트와 비슷하지만, 장고만의 마법을 부릴 수 있는 곳이기도 하지요. 물론 파이썬의 모든 명령어를 여기서 사용할 수 있습니다.
모델클래스명.objecets.get()
모델 클래스의 특정 오브젝트를 가져온다. .save() 메소드를 통해서 DB값을 갱신할 수 있다.
아래 예시에서는 GuessNumbers 클래스에서 name 컬럼에서 로우가 'siwa'인 인스턴스를 가져오는 쿼리셋입니다.
ex)
>>> GuessNumbers.objects.get(name = 'siwa')
<GuessNumbers: siwa - 당첨기원!>
>>> g = GuessNumbers.objects.get(name = 'siwa')>>> g.name
'siwa'
>>> g.name = 'siwaaaaaa'
>>> g.generate()>>> g.save()
객체 생성하기
데이터베이스에 새 글 객체를 저장하는 방법에 대해 알아봅시다.
먼저 Post 모델을 살펴보면 디폴트 값이 설정되어있는 created_date와 널값이 허용되는 published_date를 제외하고는 각 row를 채워줘야 합니다.
그리고 author의 값으로 넣을 유저를 참조하기위해
User모델을 import합니다.
>>> from django.contrib.auth.models import User
>>> User.objects.all()
<QuerySet [<User: lks>]>
User모델의 모든 객체를 조회해보니
슈퍼유저로 등록한 사용자를 볼 수 있습니다. 이제 이 사용자의 인스턴스(instance)를 가져와 봅시다. :
>>> me = User.objects.get(username='lks')
보았듯이 사용자이름(username)이 'lks'인 User 인스턴스를 받아왔어요.
사용자 이름을 바꿨다면, 바뀐 이름을 넣어줘야겠죠.
드디어 우리 게시물을 만들었네요 :
>>> Post.objects.create(author=me, title='Sample title', text='Test')
일단은 오류 없이 작동합니다.
잘 만들어졌는지 객체를 조회해보겠습니다.
>>> Post.objects.all()
<QuerySet [<Post: my post title>, <Post: another post title>, <Post: Sample title>]>
목록에 게시글 하나가 늘었습니다!
필터링하기
쿼리셋의 중요한 기능은 데이터를 필터링하는 겁니다.
예를 들어, 우리는 lks라는 사용자가 작성한 모든 글을 찾고 싶다고 해보겠습니다.
이런 경우 'Post.objects.all()에서 all대신', 'filter'를 사용합니다.
쿼리셋 안에 있는 괄호 안에 원하는 조건을 넣어줄 거예요.
지금 이 경우에는 작성자(author)가 나(me)인 조건을 넣어야겠죠. 이걸 장고로 표현한다면 author=me가 됩니다. 이제 이 조건이 반영된 코드를 보겠습니다.
>>> Post.objects.filter(author=me)
[<Post: Sample title>, <Post: Post number 2>, <Post: My 3rd post!>, <Post: 4th title of post>]
모든 글들 중, 제목(title)에 'title'이라는 글자가 들어간 글들만을 뽑아내서 보고 싶다면?
>>> Post.objects.filter(title__contains='title')
[<Post: Sample title>, <Post: 4th title of post>]
title와 contains 사이에 있는 밑줄()이 2개(_)입니다.
** 장고 ORM은 필드 이름("title")과 연산자과 필터("contains")를 밑줄 2개를 사용해 구분합니다.
밑줄 1개만 입력한다면, FieldError: Cannot resolve keyword title_contains라는 오류가 뜰 거예요.**
맨 아래에는 이러한 조건 키워드를 정리한 표가 있습니다.
게시글 목록을 볼 수 있어요. 게시일(published_date)로 과거에 작성한 글을 필터링하면 목록을 불러올 수 있어요.
>>> from django.utils import timezone
>>> Post.objects.filter(published_date__lte=timezone.now())
[]
안타깝게도, 파이썬 콘솔에서 추가한 게시물은 아직 보이지 않네요.
=> 아직 Post모델 클래스의 published_date 필드의 값이 비어있기 때문입니다.
먼저 게시하려는 게시물의 인스턴스를 얻겠습니다.
>>> post = Post.objects.get(title="Sample title")
그리고 publish메서드를 사용해서 게시합시다!
>>> post.publish()
이제 다시 한번 필터링 해보겠습니다.
>>> Post.objects.filter(published_date__lte=timezone.now())
[<Post: Sample title>]
생각했던대로 나옵니다.
정렬하기
퀘리셋은 객체 목록을 정렬할 수 있습니다.
이제 created_date필드를 정렬해봅시다.
command-line
>>> Post.objects.order_by('created_date')
[<Post: Sample title>, <Post: Post number 2>, <Post: My 3rd post!>, <Post: 4th title of post>]
아래예시처럼 -을 맨 앞에 붙여주면 내림차순 정렬도 가능합니다.
>>> Post.objects.order_by('-created_date')
[<Post: 4th title of post>, <Post: My 3rd post!>, <Post: Post number 2>, <Post: Sample title>]
쿼리셋 연결하기
쿼리셋들을 함께 연결(chaining)할 수 있어요.
>>> Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
이 방법은 정말 강력해 복잡한 쿼리도 작성할 수 있게 해줍니다.
exit() 커맨드를 입력해 종료하겠습니다!
>>> exit()
$
조건 키워드
키워드설 명사용예
__lt / __gt __lte / __gte |
보 다 작다 / 보다 크다 같거나 보다 작다 / 같거나 보다 크다 |
id가 1보다 큰 자료 검색 >>> Department.objects.filter(id__gt=1) [<Department: Computer Science>] |
__in | 주어진 리스트 안에 존재하는 자료 검색 |
id 가 2, 3, 5 인 자료 검색 >>> Department.objects.filter(id__in=[2, 3, 5]) |
__year / __month / __day | 해당 년도, 월, 일 자료 검색 | >>>Entry.objects.filter(pub_date__year=2005) |
__isnull | 해 당 열의 값이 null 인 자료 검색 |
>> Department.objects.filter(dName__isnull=True) [] |
__contains / __icontains |
해당 열의 값이 지정한 문자열을 포함하는 자료 검색 (__icontains 는 대소문자를 구별하지 않음) |
>>> Department.objects.filter(dName__contains='puter') [<Department: Computer Science>] |
__startswith / __istartswith |
해당 열의 값이 지정한 문자열로 시작하는 자료 검색 (__istartswith 는 대소문자를 구별하지 않음) |
>>> Department.objects.filter(dName__startswith='Com') [<Department: Computer Science>] |
__endswith / __iendswith |
해당 열의 값이 지정한 문자열로 끝나는 자료 검색 (__iendswith 는 대소문자를 구별하지 않음) |
>>> Department.objects.filter(dName__contains='nce') [<Department: Computer Science>] |
__range |
문 자, 숫자, 날짜의 범위를 지정함 (SQL의 BETWEEN에 |
>>> Department.objects.filter(id__range=(2, 10)) |
위의 표 출처 : brownbears.tistory.com/63
참조 :
tutorial.djangogirls.org/ko/django_orm/
wayhome25.github.io/django/2017/02/28/django-03-lotto-project-6/
brownbears.tistory.com/63
'django' 카테고리의 다른 글
[Django] 클래스형 뷰 (CBV, Class-Based View) (0) | 2021.02.14 |
---|---|
[Django] 템플릿(template) 언어 (0) | 2021.02.06 |
[Djnago] HttpRequest와 HttpResponse API (1) | 2021.02.02 |
[Django] 프로젝트 및 앱 구조 (0) | 2021.01.31 |
[Django] MTV패턴 (1) | 2021.01.31 |