장고 초급)게시물 검색하기(queryset filter)

하얀설표 | 작성시간 2024.07.02.

(2024.07.02. 수정됨.)

주요 파일 경로

blog
|- entry
|  |- forms.py
|  |- urls.py
|  |- views.py
|- templates
   |- base.html

검색폼 작성하기

검색창에 사용할 폼을 작성합니다.
검색어 너무 짧으면 검색 결과가 너무 많아지므로 min_length를 이용해 최소 3글자 이상을 입력해야 작동하도록 설정합니다.

# entry/forms.py
from django import forms
...
class Form(forms.ModelForm):
    ...
class Search(forms.Form):
    page = forms.IntegerField(
        required=False,
        widget=forms.HiddenInput,
        initial=1,
    )
    keyword = forms.CharField(
        max_length=19,
        min_length=3,
        label='검색어',
    )

뷰 수정하기

검색 작업을 수행할 search 함수를 작성합니다.
또한 글 목록 페이지에서 검색창을 확인할 수 있도록 index 함수의 context에 "search"라는 이름으로 앞서 작성한 검색폼을 추가합니다.

# entry/views.py
...
from .forms import Form, Search # 추가
...
def index(request: HttpRequest, page: int=1):
    ...
    context.update({
        'title': '글 목록',
        'paginator': paginator,
        'page_obj': page_obj,
        'object_list': page_obj.object_list,
        'search': Search(), # 추가
    })
    ...
...
# 추가
def search(request: HttpRequest):
    context = {}
    form = Search(request.GET)
    context.update({
        'title': '검색 결과',
        'object_list': [],
        'search': form,
    })
    if form.is_valid():
        keyword = form.cleaned_data['keyword']
        queryset = Post.objects.filter(title__icontains=keyword)|Post.objects.filter(content__icontains=keyword)
        paginator = Paginator(queryset, 8)
        page_obj = paginator.get_page(form.cleaned_data['page'])
        context.update({
            'paginator': paginator,
            'page_obj': page_obj,
            'object_list': page_obj.object_list,
        })
    return render(request, 'index.html', context)
...

Post.objects.filter()|Post.objects.filter()

"|"은 장고에서 OR 검색을 하기 위해 사용하는 연산자입니다.
장고 queryset의 filter method는 기본적으로 AND 조건을 부여하는데, OR 조건을 부여하려면 위 코드와 같이 queryset을 묶어주면 됩니다.

__icontains

"__icontains"는 인수로 넣은 문자열을 대소문자 구분없이 탐색하는 명령어입니다.
"title__icontains='ASDF'"을 넣었다면 title field에 대소문자 구분없이 asdf가 포함된 obejct를 가져옵니다.

"__icontains"가 아닌 "__contains" 명령을 사용하면 대소문자를 구분합니다.

url 추가하기

search라는 이름의 url에 접근하면 검색 함수가 작동하도록 url을 추가해줍니다.

# entry/urls.py
from django.urls import path
from . import views
app_name = 'entry'
urlpatterns = [
    ...
    path('search/', views.search, name='search'), # 추가
    ...
]

템플릿 수정하기

검색창이 페이지의 상단에 위치하도록 하기 위해 base.html을 수정합니다.

# templates/base.html
<head>
    {% include 'style.html' %}
</head>
<body>
    <header>
        <p><a href="/"><span style="font-size: 28px;"><b>하얀설표 블로그</b></span></a></p>
    </header>
    <hr>
    <div style="display: flex;">
        {% include 'is_login.html' %}
        {% if search %}
        <div style="margin-left: auto;">
            <form action="{% url 'entry:search' %}" method="get" style="display: flex;">
                {{ search }}
                <input type="submit" value="검색">
            </form>
        </div>
        {% endif %}
    </div>
    <hr>
    <h1>{% block title %}{% endblock %}</h1>
    <hr>
    <main>
        {% block main %}{% endblock %}
    </main>
    <hr>
</body>
<footer>
    <p>this site Powered by <a href="https://www.djangoproject.com/">Django</a></p>
    <p>Designed by 하얀설표 from <a href="https://django.seolpyo.com/">설표의 장고</a></p>
</footer>

검색해보기

이제 검색 기능을 사용할 수 있게 되었습니다.
검색폼에서 설정한 것처럼 3글자 미만의 검색어를 입력하면 경고 문구가 노출되는 것을 확인할 수 있습니다.

검색 기능 확인



이 글의 댓글 기능은 일부러 막아놓았습니다. 궁금한 내용이 있다면 게시판을 이용해주세요!