검색 기능을 구현할 때 사용자 경험을 향상시키는 중요한 요소 중 하나는 검색 결과에서 검색어를 시각적으로 강조하는 것입니다. 오늘은 Django에서 검색어 하이라이트 기능을 구현하는 방법을 알아보겠습니다.
먼저 간단한 검색 폼과 결과를 보여주는 기본 구조를 만듭니다:
{# templates/search.html #}
<form method="get">
<select name="search_type">
<option value="title">제목</option>
<option value="content">내용</option>
<option value="all">제목+내용</option>
</select>
<input type="text" name="search_keyword" value="{{ search_keyword }}" placeholder="검색어">
<button type="submit">검색</button>
</form>
<div class="search-results">
{% for item in results %}
<div class="result-item">
<h3>{{ item.title }}</h3>
<p>{{ item.content }}</p>
</div>
{% endfor %}
</div>
templatetags
디렉토리를 생성하고 하이라이트 필터를 구현합니다:
# myapp/templatetags/highlight.py
from django import template
from django.utils.safestring import mark_safe
import re
register = template.Library()
@register.filter
def highlight(text, search):
"""
텍스트 내의 검색어를 하이라이트 처리하는 필터
Args:
text: 원본 텍스트
search: 하이라이트할 검색어
"""
if not search or not text:
return text
# 특수문자가 포함된 검색어 처리를 위한 이스케이프
search = re.escape(search)
# 대소문자 구분 없이 검색어 매칭
pattern = re.compile(f'({search})', re.IGNORECASE)
# 매칭된 부분을 <strong> 태그로 감싸기
highlighted = pattern.sub(r'<strong>\\1</strong>', str(text))
return mark_safe(highlighted)
{% extends 'base.html' %}
{% load highlight %} {# 커스텀 필터 로드 #}
{% block content %}
<form method="get">
<select name="search_type">
<option value="title" {% if search_type == 'title' %}selected{% endif %}>제목</option>
<option value="content" {% if search_type == 'content' %}selected{% endif %}>내용</option>
<option value="all" {% if search_type == 'all' %}selected{% endif %}>제목+내용</option>
</select>
<input type="text" name="search_keyword" value="{{ search_keyword }}" placeholder="검색어">
<button type="submit">검색</button>
</form>
<div class="search-results">
{% for item in results %}
<div class="result-item">
{# 검색 타입에 따라 하이라이트 적용 #}
{% if search_type == 'title' or search_type == 'all' %}
<h3>{{ item.title|highlight:search_keyword }}</h3>
{% else %}
<h3>{{ item.title }}</h3>
{% endif %}
{% if search_type == 'content' or search_type == 'all' %}
<p>{{ item.content|highlight:search_keyword }}</p>
{% else %}
<p>{{ item.content }}</p>
{% endif %}
</div>
{% endfor %}
</div>
{% endblock %}
검색어 하이라이트를 시각적으로 돋보이게 만듭니다:
/* static/css/style.css */
.search-results .result-item strong {
background-color: #fff3cd; /* 연한 노란색 배경 */
padding: 2px 4px;
border-radius: 2px;
font-weight: bold;
color: #856404; /* 진한 갈색 텍스트 */
}
/* 또는 다른 스타일 옵션 */
.search-results .result-item strong {
background: linear-gradient(transparent 60%, #ffd700 60%); /* 밑줄 형태의 하이라이트 */
padding: 0 2px;
}
from django.views.generic import ListView
from django.db.models import Q
class SearchView(ListView):
template_name = 'search.html'
context_object_name = 'results'
def get_queryset(self):
queryset = YourModel.objects.all()
search_type = self.request.GET.get('search_type', '')
search_keyword = self.request.GET.get('search_keyword', '')
if search_keyword:
if search_type == 'title':
queryset = queryset.filter(title__icontains=search_keyword)
elif search_type == 'content':
queryset = queryset.filter(content__icontains=search_keyword)
elif search_type == 'all':
queryset = queryset.filter(
Q(title__icontains=search_keyword) |
Q(content__icontains=search_keyword)
)
return queryset
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['search_type'] = self.request.GET.get('search_type', '')
context['search_keyword'] = self.request.GET.get('search_keyword', '')
return context
re.IGNORECASE
플래그를 사용하여 대소문자 구분 없이 검색어 매칭re.escape()
를 사용하여 특수문자가 포함된 검색어도 안전하게 처리mark_safe()
를 사용하여 HTML 태그가 이스케이프되지 않도록 처리검색어 하이라이트는 작은 기능이지만 사용자 경험을 크게 향상시킬 수 있습니다. Django의 템플릿 필터 시스템을 활용하면 이러한 기능을 깔끔하게 구현할 수 있습니다.
더 나아가 다음과 같은 개선사항을 고려해볼 수 있습니다: