장고 - Q 객체를 이용한 키워드 검색 기능 학습
- 이번에는 게시판 기능 중, 사용자가 글제목/작성자/글내용에 포함되어 있는 특정 키워드를 검색 시 해당 키워드를 가진 객체를 필터링해주는 방법에 대해 알아볼 것이다.
유저가 게시판에서 특정 키워드로 검색 시, 해당 키워드를 가진 글 목록 제공하기
1. 모델 작성
- 경로 : board_project > board(앱) > models.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24class Document(models.Model):
category = models.ForeignKey(Category, on_delete=models.SET_NULL,
null=True, blank=True, related_name='documents')
author = models.ForeignKey(get_user_model(), on_delete=models.CASCADE,
related_name='documents')
# on_delete=models.SET_NULL : 참조하고 있는 Category 객체가 지워져도 삭제되지 않음
title = models.CharField(max_length=100)
# db_index=True : DB에 인덱싱 가능
slug = models.SlugField(max_length=120, db_index=True, unique= True,
allow_unicode=True, blank=True)
text = models.TextField()
image = models.ImageField(upload_to='board_images/%Y/%m/%d')
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
def save(self, *args, **kwargs):
self.slug = slugify(self.title, allow_unicode=True)
super(Document, self).save(*args, **kwargs)
def get_absolute_url(self):
return reverse('board:detail', args=[self.id])
2. 경로 설정
- 경로 : board_project > board > urls.py
1
2
3
4
5
6
7
8from django.urls import path
from .views import *
app_name = 'board'
urlpatterns = [
path('', document_list, name='list'),
...
3. 뷰 작성
경로 : board_project > board > templates > board > document_list.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26<form action="" method="get" id="search_form" class="">
{%csrf_token%}
<div class="form-row align-items-center justify-content-center">
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="inlineCheckbox1" value="username" name="search_type">
<label class="form-check-label" for="inlineCheckbox1">작성자</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="inlineCheckbox2" value="title" name="search_type" checked>
<label class="form-check-label" for="inlineCheckbox2">제목</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="inlineCheckbox3" value="text" name="search_type">
<label class="form-check-label" for="inlineCheckbox3">본문</label>
</div>
</div>
<div class="form-row align-items-center justify-content-center">
<div class="col-sm-3 my-1">
<input type="text" class="form-control" placeholder="Search Keyword" name="search_key">
</div>
<div class="col-auto my-1">
<button type="submit" class="btn btn-primary">Search</button>
</div>
</div>
</form>경로 : board_project > board > views.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40from django.shortcuts import render
from django.db.models import Q
from .models import Document
def document_list(request):
# search_type = ['username', 'title', 'text']
search_type = reqeust.GET.getlist('search_type', None)
search_q = None
# search_key = 유저가 입력한 키워드(문자열 형태로 수신)
search_key = request.GET.get('search_key', None)
# 유저가 검색한 키워드가 있는 경우
if search_key:
# 유저가 '제목' checkbox 선택한 경우
if 'title' in search_type:
# Document 객체 title 필드에 search_key를 포함하는 키워드가 있는 경우 그 객체들을 temp_q 변수가 참조한다.
temp_q = Q(title__icontaions=search_key)
# search_q가 있다면, (search_q 또는 temp_q)를 search_q 변수가 참조하게 하고,
# search_q가 없다면, temp_q가 참조하고 있는 객체를 search_q 변수가 참조하게 한다.
search_q = search_q | temp_q if search_q else temp_q
# 유저가 '본문' checkbox 선택한 경우
if 'text' in search_type:
# Document 객체의 text 필드에 search_key 포함하는 키워드가 있는 경우, 그 객체들을 temp_q 변수가 참조한다.
temp_q = Q(text__icontains=search_key)
search_q = search_q | temp_q if search_q else temp_q
# 유저가 '작성자' checkbox 선택한 경우
if 'username' in search_type:
# Document 객체의 author__username 데이터에 search_key 포함하는 키워드가 있는 경우, 그 객체들을 temp_q 변수가 참조한다.
temp_q = Q(author__username__icontaions=search_key)
search_q = search_q | temp_q if search_q else temp_q
# Document 에서 search_q 가 참조하고 있는 객체들을 documents 변수가 참조하게 한다.
documents = get_list_or_404(Document, search_q)
# 유저가 검색한 키워드가 없는 경우
else:
# 모든 Document 객체들을 documents 변수가 참조하게 한다.
documents = Document.objects.all()
# context data로 documents 변수를 'object_list' 변수가 참조하게 하여 board/document_list.html 페이지에 보낸다.
return render(request, 'board/document_list.html', {'object_list':documents})
Posted