[REAL Python – Django] – “Django – Search 구현”
[REAL Python – Django] – “Django – Search 구현”
JavaScript
작업하기
백엔드를 처리하기 전, 자바스크립트로 검색창에 검색어를 입력하고 엔터나 버튼을 누르면, /blog/search/검색어
로 이동하게끔 하는 코드를 작성해 주었습니다.
<script>
function searchPost() {
let searchValue = document.getElementById('search-input').value.trim();
if (searchValue.length > 1) {
location.href = "/blog/search/" + searchValue + "/";
} else {
alert('검색어(' + searchValue + ')가 너무 짧습니다.');
}
};
document.getElementById('search-input').addEventListener('keyup', function(event)
{
if(event.key === 'Enter'){
searchPost();
}
});
</script>
이 부분은 검색 HTML
코드입니다. 버튼이 클릭되었을 때에 searchPost()
함수가 호출되게끔 작성되어 있죠? 함수는 아래와 같이 작성되어 있습니다. id=search-input
인 것을 가져와서 그 값을 searchValue
에 담도록 되어 있습니다.
그리고 검색어를 입력하면 지정된 링크로 이동하도록 되어 있습니다. location.href = "/blog/search/" + searchValue + "/";
예컨대 검색창에 ‘자바스크립트’ 를 검색하고 엔터를 누른다면 "/blog/search/자바스크립트/"
로 이동할 겁니다. 이제 urls.py
에 해당 패턴을 추가해 주고, 그것을 view
에서 어떻게 처리할 것인지를 구현해 주면 됩니다.
urls.py
수정
/blog/search/사용자가 입력한 검색어/
까지 이동하는 것은 성공했습니다. 이제 urls.py
를 작업할 겁니다.
path('search/<str:q>/', views.PostSearch.as_view()),
urls.py
에 해당 코드를 추가해줍니다. 'search/<str:q>/'
는 사용자가 입력한 검색어를 str
로 받아 q
에 저장하겠다는 의미이고, views.PostSearch.as_view
는 views.py
의 PostSearch
클래스에서 그것을 처리하겠다는 의미입니다.
views.py
작성, 핵심은 원하는 글만 가져오는 것
포스트 전체 리스트를 보여주는 것 VS 검색어에 대한 포스트 리스트를 보여주는 것 의 차이는 “검색어에 대한” 뿐 리스트를 보여주는 것 자체는 똑같습니다. 모델도 포스트로 아예 같네요.
class PostSearch(PostList):
def get_queryset(self):
q = self.kwargs['q']
post_list = Post.objects.filter(
Q(title__contains=q) | Q(tags__name__contains=q)
).distinct()
return post_list
def get_context_data(self, **kwargs):
context = super(PostSearch, self).get_context_data()
q = self.kwargs['q']
context['search_info'] = f'Search: {q} ({self.get_queryset().count()})'
return context
위에서 만든 클래스를 상속받고 두 가지 메소드를 재정의했습니다. get_queryset
메소드와 get_context_data
메소드는 각각 어떤 메소드일까요?
1. get_queryset
: 데이터베이스에서 객체 받아오기
Returns the queryset that will be used to retrieve the object that this view will display. By default,
https://docs.djangoproject.com/en/4.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin.get_querysetget_queryset()
returns the value of thequeryset
attribute if it is set, otherwise it constructs aQuerySet
by calling theall()
method on themodel
attribute’s default manager.
get_queryset
은 간단히(?) 말하면 뷰에서 처리할 쿼리셋(데이터베이스에서 받아온 객체들의 목록) 을 받아오는 메서드입니다. 그렇기 때문에 urls.py
에서 얻어온 q
(사용자가 입력한 검색어) 를 받아온 다음,
Q(title__contains=q) | Q(tags__name__contains=q)
코드로 원하는 데이터만 뽑아서(제목에 검색어가 들어가 있는 것과 태그이름에 검색어가 들어가있는 것) 가져오는 쿼리를 실행한 것입니다. 최종 메서드의 결과로는 뽑아온 것을 리턴하도록 되어 있습니다.
2. get_context_data
: context
받아오기
Returns context data for displaying the object.
https://docs.djangoproject.com/en/4.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin.get_context_data
객체를 보여주도록 하는 context
데이터를 받아온다고 적혀져 있습니다. 그런데 과연 context
란 무엇일까요?
{'categories': <QuerySet []>,
'is_paginated': True,
'no_category_post_count': 7,
'object_list': <QuerySet [<Post: [7] hajydb :: goddessana>, <Post: [6] stgshydj :: goddessana>, <Post: [5] afdsfasdgtht :: goddessana>, <Post: [4] qreqwerqwerq :: goddessana>]>,
'page_obj': <Page 1 of 2>,
'paginator': <django.core.paginator.Paginator object at 0x10cac2230>,
'post_list': <QuerySet [<Post: [7] hajydb :: goddessana>, <Post: [6] stgshydj :: goddessana>, <Post: [5] afdsfasdgtht :: goddessana>, <Post: [4] qreqwerqwerq :: goddessana>]>,
'view': <blog.views.PostList object at 0x10cac2560>}
예컨대 이것은 실제 프로젝트에서 /blog/ 로 접속했을 때에 context
데이터를 콘솔에 출력한 것입니다.
결론부터 말하자면 context
는 템플릿에서 쓰이는 변수명과 파이썬 객체를 연결해주는 사전형 값을 의미합니다. 그렇기 때문에 {% if post_list.exists %}
와 같은 코드를 템플릿에서 사용할 수 있는 것이죠. 위의 코드에서는 Search:사용자가입력한검색어(검색결과수)
를 템플릿에서 사용할 수 있도록 작성되어 있다는 것을 알 수 있을 것입니다. 저는 위의 코드를 템플릿에 추가해주었습니다.