[uscript] 9장. 조회 화면 만들기
조회 화면을 가장 마지막에 한 것은 기능이 가장 복잡해서이다.
원래는 처음에 간략히 조회하는 기능을 구현하고 뒤에서 개선하는 방향으로 작성하려고 했는데 이미 만들어진 소스를 가지고 하다보니 가장 나중에 넣게 되었다.
조회 기능은 1. 페이지 기능 2. 검색기능이 들어간다.
URL엔 root 에서 search_page 함수를 호출하기로 정의하였다.
url(r'^$', views.search_page, name='index'),
조회함수가 상당히 길어졌는데 pagination과 search를 title, content, tag 검색을 넣다보니 조금 길어졌다.
페이지 기능은 Paginator를 import 하여 사용한다. paginator에는 데이터 객체와 한페이지에 보여줄 개체수를 입력하면 num_pages에 전체페이지 수가 나오고 page(숫자) 함수에서 한 페이지 단위로 조회를 한다.
여기에 조금 더 기능을 추가하여 게시판에 10개의 페이지수만 나오고 페이지블록단위로 조회를 할 수 있게 로직을 구성하였다.
ITEMS_PER_PAGE = 10
PAGE_GROUP = 10
두개의 변수가 페이지 구성을 해준다.
ITEM_PER_PAGE는 한번에 보여주는 개수를 나타내고, PAGE_GROUP은 페이징으로 보여줄 숫자 개수를 나타낸다. 즉 1~10과 같이 10개 페이지 목록을 보여준다.
검색은 models에 있는 Q를 사용한다. 보통 models 객체를 상속 받은 클래서에서 직접 쿼리를 하지만 포함이나 같음, and 조건과 같이 복잡한 쿼리는 Q를 이용하여 검색을 한다.
Q에 대해서는 별도로 다시 정리를 하겠다.
q 객체를 생성해서 조회할 클래스 객체와 조건을 입력한다.
q에서 만든 조건식을 클래스에 filter함수로 걸어주면 검색이 완료된다.
객체.objects.all() 이라고 하면 select * from 객체 와 같은 쿼리가 되고,
filter() 함수를 이용하면 where 절이 된다.
여기에 q를 넣으면 where ... 에 조건절이 완성된다.
html 페이지는 다음과 같이 추가한다.
{% csrf_token %}
<p>
<select class="form-control" name="query_type">
<option value="title" {% if query_type == 'title' %} selected {% endif %}>Title</option>
<option value="contents" {% if query_type == 'contents' %} selected {% endif %}>Contents</option>
<option value="tag" {% if query_type == 'tag' %} selected {% endif %}>Tag</option>
</select>
<input class="form-control" type="text" name="query" value="{{ query }}"/>
<button class="btn btn-default" type="submit"><span class="glyphicon glyphicon-search" aria-hidden="true"></span> Search</button>
</p>
<div id="search-results">
{% if scripts_list %}
<table class="table table-hover">
<tr>
<th style="">제목</th>
<th style="width:100px">Download</th>
<th style="width:100px">작성자</th>
<th style="width:100px">작성일</th>
</tr>
{% for scripts in scripts_list %}
<tr>
<td><a href="{% url 'scripts:detail' scripts.id %}">{{ scripts.title }}</a></td>
<td><a class="btn btn-default" href='/scripts/{{ scripts.id }}/download' >
<span class="glyphicon glyphicon-download" aria-hidden="true"></span> Download</a></td>
<td>{% if scripts.user.last_name %}
{{ scripts.user.last_name }}{{ scripts.user.first_name }}
{% else %}
{{ scripts.user.username }}
{% endif %}
</td>
<td>{{ scripts.pub_date|date:"Y-m-j" }}</td>
</tr>
{% endfor %}
</table>
{% else %}
<p>No contents</p>
{% endif %}
</div>
{% if show_paginator %}
<nav style="text-align:center;">
<ul class="pagination" >
{% if has_prev %}
<li><a href="javascript:nextpage({{ prev_page }});">Prev</a></li>
{% endif %}
{% for page_num in page_list %}
<li><a href="javascript:nextpage({{ page_num }});">{{ page_num }}</a></li>
{% endfor %}
{% if has_next %}
<li><a href="javascript:nextpage({{ next_page }});">Next</a></li>
{% endif %}
<!-- (Page {{ page }} of {{ pages}}) -->
</ul>
</nav>
<input type="hidden" id="page" name="page" value="{{ page }}" />
{% endif %}
원래는 처음에 간략히 조회하는 기능을 구현하고 뒤에서 개선하는 방향으로 작성하려고 했는데 이미 만들어진 소스를 가지고 하다보니 가장 나중에 넣게 되었다.
조회 기능은 1. 페이지 기능 2. 검색기능이 들어간다.
URL엔 root 에서 search_page 함수를 호출하기로 정의하였다.
url(r'^$', views.search_page, name='index'),
from django.core.paginator import Paginator from django.db.models import Q ITEMS_PER_PAGE = 10 PAGE_GROUP = 10 def search_page(request): scripts = [] query_type = 'title' if request.POST.has_key('query_type'): query_type = request.POST['query_type'] query = "" if request.POST.has_key('query'): query = request.POST['query'].strip() if query: keywords = query.split() q = Q() for keyword in keywords: if query_type == 'title': q = q & Q(title__icontains=keyword) elif query_type == 'contents': q = q & Q(contents__icontains=keyword) elif query_type == 'tag': q = q & Q(tag_title__icontains=keyword) if query_type == 'tag': tags = [ tag.scripts.all() for tag in Tag.objects.filter(q) ] scripts = [] for tag in tags: for script in tag: if not script in scripts: scripts.append(script) else: scripts = Scripts.objects.filter(q).order_by('-pub_date') else: # query is empty scripts = Scripts.objects.all().order_by('-pub_date') else: # no query scripts = Scripts.objects.all().order_by('-pub_date') paginator = Paginator(scripts, ITEMS_PER_PAGE) page_group_total = int(paginator.num_pages / PAGE_GROUP) if paginator.num_pages % PAGE_GROUP > 0: page_group_total = page_group_total + 1 try: page = int(request.POST['page']) except: page = 1 page_group_no = int((page - 1) / PAGE_GROUP) + 1 prev_page = 0 next_page = 0 if page_group_no < page_group_total: next_page = page_group_no * PAGE_GROUP + 1 if page_group_total > 1 and page_group_no > 1: prev_page = (page_group_no - 1) * PAGE_GROUP if page_group_total == page_group_no: page_group_mod = paginator.num_pages - (page_group_no - 1) * PAGE_GROUP else: page_group_mod = PAGE_GROUP page_list = [ (page_group_no - 1) * PAGE_GROUP + i + 1 for i in range(page_group_mod)] try: if paginator.num_pages < page: page = 1 result_scripts = paginator.page(page) except: raise Http404 variables = RequestContext(request, { 'scripts_list': result_scripts, 'query_type': query_type, 'query': query, 'show_paginator': paginator.num_pages > 1, 'has_prev': prev_page > 0, 'has_next': next_page > 0, 'page': page, 'page_list': page_list, 'pages': paginator.num_pages, 'next_page': next_page, 'prev_page': prev_page}) return render_to_response('scripts/index.html', variables)
조회함수가 상당히 길어졌는데 pagination과 search를 title, content, tag 검색을 넣다보니 조금 길어졌다.
페이지 기능은 Paginator를 import 하여 사용한다. paginator에는 데이터 객체와 한페이지에 보여줄 개체수를 입력하면 num_pages에 전체페이지 수가 나오고 page(숫자) 함수에서 한 페이지 단위로 조회를 한다.
여기에 조금 더 기능을 추가하여 게시판에 10개의 페이지수만 나오고 페이지블록단위로 조회를 할 수 있게 로직을 구성하였다.
ITEMS_PER_PAGE = 10
PAGE_GROUP = 10
두개의 변수가 페이지 구성을 해준다.
ITEM_PER_PAGE는 한번에 보여주는 개수를 나타내고, PAGE_GROUP은 페이징으로 보여줄 숫자 개수를 나타낸다. 즉 1~10과 같이 10개 페이지 목록을 보여준다.
검색은 models에 있는 Q를 사용한다. 보통 models 객체를 상속 받은 클래서에서 직접 쿼리를 하지만 포함이나 같음, and 조건과 같이 복잡한 쿼리는 Q를 이용하여 검색을 한다.
Q에 대해서는 별도로 다시 정리를 하겠다.
q 객체를 생성해서 조회할 클래스 객체와 조건을 입력한다.
q에서 만든 조건식을 클래스에 filter함수로 걸어주면 검색이 완료된다.
객체.objects.all() 이라고 하면 select * from 객체 와 같은 쿼리가 되고,
filter() 함수를 이용하면 where 절이 된다.
여기에 q를 넣으면 where ... 에 조건절이 완성된다.
html 페이지는 다음과 같이 추가한다.
{% csrf_token %}
<p>
<select class="form-control" name="query_type">
<option value="title" {% if query_type == 'title' %} selected {% endif %}>Title</option>
<option value="contents" {% if query_type == 'contents' %} selected {% endif %}>Contents</option>
<option value="tag" {% if query_type == 'tag' %} selected {% endif %}>Tag</option>
</select>
<input class="form-control" type="text" name="query" value="{{ query }}"/>
<button class="btn btn-default" type="submit"><span class="glyphicon glyphicon-search" aria-hidden="true"></span> Search</button>
</p>
<div id="search-results">
{% if scripts_list %}
<table class="table table-hover">
<tr>
<th style="">제목</th>
<th style="width:100px">Download</th>
<th style="width:100px">작성자</th>
<th style="width:100px">작성일</th>
</tr>
{% for scripts in scripts_list %}
<tr>
<td><a href="{% url 'scripts:detail' scripts.id %}">{{ scripts.title }}</a></td>
<td><a class="btn btn-default" href='/scripts/{{ scripts.id }}/download' >
<span class="glyphicon glyphicon-download" aria-hidden="true"></span> Download</a></td>
<td>{% if scripts.user.last_name %}
{{ scripts.user.last_name }}{{ scripts.user.first_name }}
{% else %}
{{ scripts.user.username }}
{% endif %}
</td>
<td>{{ scripts.pub_date|date:"Y-m-j" }}</td>
</tr>
{% endfor %}
</table>
{% else %}
<p>No contents</p>
{% endif %}
</div>
{% if show_paginator %}
<nav style="text-align:center;">
<ul class="pagination" >
{% if has_prev %}
<li><a href="javascript:nextpage({{ prev_page }});">Prev</a></li>
{% endif %}
{% for page_num in page_list %}
<li><a href="javascript:nextpage({{ page_num }});">{{ page_num }}</a></li>
{% endfor %}
{% if has_next %}
<li><a href="javascript:nextpage({{ next_page }});">Next</a></li>
{% endif %}
<!-- (Page {{ page }} of {{ pages}}) -->
</ul>
</nav>
<input type="hidden" id="page" name="page" value="{{ page }}" />
{% endif %}
댓글
댓글 쓰기