[REAL Python – Django] – “Django – http method get 파라미터 요청 처리를 통한 검색 기능 구현하기”

[REAL Python – Django] – “Django – http method get 파라미터 요청 처리를 통한 검색 기능 구현하기”

5월 10, 2022

템플릿 작업하기

            <!-- ======= Search Form ======= -->
            <div class="search-form-wrap js-search-form-wrap">
                <form action="/blog/" method="get" class="search-form">
                    <span class="icon bi-search"></span>
                    <input type="text" name="q"  class="form-control" id="q" value="{{ q | default_if_none:"" }}">
                    <button class="btn js-search-close" type="button"></button>
                </form>
            </div><!-- End Search Form -->

위와 같은 form 을 작성해주었습니다. 저는 템플릿을 사용한 것이기 때문에, 검색 폼의 모양은 다를 수 있습니다!

검색 폼에 hello 를 검색하면, ?q=hello 처럼 검색한 내용이 전달되는 것을 볼 수 있습니다.

이전의 방식 VS 현재의 방식

이전에는 검색에 검색어를 입력하면 /blog/입력한 검색어 의 형식으로 URL 패턴을 따로 정해주었는데, 이번에는 get 파라미터를 받을 겁니다.

현재 포스트들의 리스트를 보여주는 뷰 함수들의 상속 관계는 다음과 같습니다.

현재, 필자가 작업하고 있는 블로그의 뷰 클래스들의 상속 구조.

다시 검색 기능에 대해서 잠시 생각해 보겠습니다. 검색창에 검색어를 입력하면 카테고리의 제목, 부제목, 내용에 검색어가 포함되어 있는지 확인하고, 확인된 게시물들을 불러오면 됩니다. 필터링할 게시물들의 대상은 모든 게시물들이므로, BasePostListView 를 건드려야 합니다.

그러할 경우, 이처럼 get_queryset() 함수를 재정의해주면 됩니다.

일단 현재의 쿼리셋들을 저장해 두고, 만약 GET 파라미터가 들어온다면 그것을 필터링한 후 쿼리셋을 바꾸어 주는 코드입니다. 파라미터가 들어오지 않는다면, 당연히 모든 포스트들의 리스트가 쿼리셋에 포함되겠죠.

그리고 검색어가 무엇인지를 받은 후 그것을 템플릿에 뿌려주기 위해서 get_context_data() 메서드를 재정의해 주겠습니다.

이렇게 해 주겠습니다!

템플릿 작업, 검색 결과를 나타내 보자!

템플릿에 추가한 context 를 사용해 보자.
결과. 의도했던 대로 검색이 작동하고, 검색어도 템플릿에 출력되는 것을 볼 수 있다.

이렇게 간단하게(본인은 삽질했지만..) 검색 구현 완료!

혹시 쓰실 분들을 위해 전체 views 코드를 넣습니다!

from django.db.models import Q
from django.http import request
from django.shortcuts import render
from django.views.generic import ListView, DetailView, FormView
from .models import Post, Category


class BasePostListView(ListView):
    '''
    /blog/ 로 들어오면 데이터베이스에 존재하는 모든 게시물이 표시되어야 함
    템플릿의 맨 처음에 "All Posts"
    '''
    model = Post
    ordering = '-pk'
    paginate_by = 9
    template_name = 'blog/base_post_list.html'

    def get_queryset(self, **kwargs):
        queryset = super(BasePostListView, self).get_queryset()
        searchQ = self.request.GET.get('q')
        if searchQ:
            queryset = Post.objects.filter(
                Q(title__contains=searchQ)|
                Q(content__contains=searchQ)|
                Q(tags__name__contains=searchQ)|
                Q(subtitle__contains=searchQ)
            ).distinct()
        return queryset

    def get_context_data(self, **kwargs):
        context = super(BasePostListView, self).get_context_data()
        searchQ = self.request.GET.get('q')
        context['search_word'] = searchQ
        return context


class PostByFirstCategoryListView(BasePostListView):
    # 한 포스트의 카테고리의 부모 카테고리의 부모 카테고리(할아버지 카테고리) 가 존재한다 -> 해당 포스트의 할아버지 카테고리 == 1차 카테고리가 됨
    # 3차 카테고리에만 글을 쓸 수 있도록 할 것이므로, 포스트의->카테고리의->부모카테고리의->부모카테고리 == URL 인자인 포스트들 뽑아와야 함
    def get_queryset(self):
        first_category_from_url = self.kwargs['first_category_slug']
        selected_post_list = Post.objects.filter(
            Q(category__parent__parent__name=first_category_from_url) | Q(
                category__parent__parent__slug=first_category_from_url)
            # URL 인자 == 할아버지 카테고리이거나 URL인자 == 할아버지 카테고리의 slug인 포스트들을 가져옴.
        ).distinct()  # 중복 제거
        return selected_post_list

    def get_context_data(self, **kwargs):
        context = super(PostByFirstCategoryListView, self).get_context_data()
        first_category_from_url = self.kwargs['first_category_slug']
        current_category_name = Category.objects.get(slug=first_category_from_url).name
        context['current_category'] = current_category_name
        return context


class PostBySecondCategoryListView(BasePostListView):
    # 부모 카테고리이름==URL인자 or 부모카테고리의 슬러그==URL인자 인 포스트들 뽑아오기.
    def get_queryset(self):
        second_category_from_url = self.kwargs['second_category_slug']
        selected_post_list = Post.objects.filter(
            Q(category__parent__slug=second_category_from_url) | Q(category__parent__name=second_category_from_url)
        ).distinct()  # 중복 제거
        return selected_post_list

    def get_context_data(self, **kwargs):
        context = super(PostBySecondCategoryListView, self).get_context_data()
        second_category_from_url = self.kwargs['second_category_slug']
        current_category_name = Category.objects.get(slug=second_category_from_url).name
        context['current_category'] = current_category_name
        return context


class PostByThirdCategoryListView(BasePostListView):
    def get_queryset(self):
        third_category_from_url = self.kwargs['third_category_slug']
        selected_post_list = Post.objects.filter(
            Q(category__slug=third_category_from_url) | Q(category__name=third_category_from_url)
        ).distinct()  # 중복 제거
        return selected_post_list

    def get_context_data(self, **kwargs):
        context = super(PostByThirdCategoryListView, self).get_context_data()
        third_category_from_url = self.kwargs['third_category_slug']
        current_category_name = Category.objects.get(slug=third_category_from_url).name
        context['current_category'] = current_category_name
        return context

class PostDetailView(DetailView):
    model = Post
    template_name = 'blog/post_detail.html'

Leave A Comment

Avada Programmer

Hello! We are a group of skilled developers and programmers.

Hello! We are a group of skilled developers and programmers.

We have experience in working with different platforms, systems, and devices to create products that are compatible and accessible.