웹알못 dJango로 홈페이지 만들기(관리자페이지) [3]
- Study/python
- 2019. 5. 17. 19:00
목차
2019/05/16 - [Study/python] - 웹알못 dJango로 홈페이지 만들기(관리자페이지) [1]
- 개발환경, 장고설치, 첫화면 만들기, 수정/삭제기능 만들기
2019/05/16 - [Study/python] - 웹알못 dJango로 홈페이지 만들기(관리자페이지) [2]
- 페이징 처리, 검색 기능, 추가 기능
2019/05/17 - [Study/python] - 웹알못 dJango로 홈페이지 만들기(관리자페이지) [3]
- 메뉴바, 로그 페이지 추가
2019/05/20 - [Study/python] - 웹알못 dJango로 홈페이지 만들기(관리자페이지) [4]
- 일별, 월별 데이터 뽑기, 기간 필터링, 차트그리기
git - https://github.com/tkdlek11112/simple_dashboard_python
▷ 검색 카테고리 적용
지난번에 적용한 검색을 보면 제목, 내용, 제목+내용으로 검색할 수 있는 카테고리기능이 있습니다. 기능은 적용하지 않았는데 이번에 적용해보도록 하겠습니다. 일단 views.py
에서 넘어온 search_type
을 읽어서 object.filter
를 변경하면 됩니다. 적용할 때 살짝 애매모호한점이 있는데 바로 제목+내용 구현입니다. 필드 2개에서 OR조건으로 검색되야하기 때문에 특별한 기능을 사용해야 합니다.
#adminpage/view.py
from django.db.models import Q
def listfaqs(request):
search_type = request.GET.get('search_type')
search_keyword = request.GET.get('search_keyword')
if search_keyword is None:
search_keyword = ""
if len(search_keyword) > 0:
if search_type == '1':
faq_list = Faq.objects.order_by('pk').filter(faq_question__contains=search_keyword)
elif search_type == '2':
faq_list = Faq.objects.order_by('pk').filter(faq_answer__contains=search_keyword)
elif search_type == '3':
faq_list = Faq.objects.order_by('pk').filter(Q(faq_question__contains=search_keyword)
| Q(faq_answer__contains=search_keyword))
else:
search_type = '1'
search_keyword = ''
faq_list = Faq.objects.all()
paginator = Paginator(faq_list, 5) # "5" 한페이지에서 보여줄 갯수를 정한다.
page = request.GET.get('page')
faqs = paginator.get_page(page)
return render(request, 'adminpage/list_faqs.html', {'faqs': faqs, 'type': search_type, 'keyword': search_keyword})
Q라는 메서드를 사용하기 위해 django.db.models
에서 가져와서 사용합니다. Q(faq_question__contains=search_keyword) | Q(faq_answer__contains=search_keyword)
가 or조건으로 filter를 사용한 코드입니다.
html도 약간 수정이 필요합니다. 이전에 선택한 카테고리가 유지되도록 설정해야 하거든요.
<select id="search_type" name="search_type">
<option value="1" {% if type == '1' %} selected {% endif %} >질문</option>
<option value="2" {% if type == '2' %} selected {% endif %} >내용</option>
<option value="3" {% if type == '3' %} selected {% endif %} >질문+내용</option>
</select>
각각의 <option>
부분에 만약 넘어온 type
값이 자신의 값이라면 selected
속성을 넣어줍니다. 이렇게 하면 페이지가 이동해도 카테고리가 유지됩니다.
▷ 메뉴바 만들기
이제 질문 데이터를 조회하고 수정하고 추가하는 기능을 얼추 완성되었다. 이제 또 다른 요구사항인 사용자 로그 조회하면을 만들 차례다. 지금까지 만들던 화면과 다른 화면이기 때문에 화면을 새로 만들어야 하는데, 화면을 이동하려면 메뉴바가 있으면 편할 것 같다. 일단 간단하게 메뉴바를 만들어보자.
{# template/adminpage/list_faqs.html #}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="/static/jquery-3.2.1.min.js"></script>
<link rel="stylesheet" href="/static/bootstrap.css">
</head>
<body>
<style type="text/css">
.tg {border-collapse:collapse;border-spacing:0;}
.tg td{font-family:Arial, sans-serif;font-size:14px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg .tg-21xh{font-weight:bold;background-color:#34cdf9;color:#333333;border-color:inherit;text-align:left;vertical-align:top}
.tg .tg-0pky{border-color:inherit;text-align:left;vertical-align:top}
.content_wrap {width: 80%; margin: 0 auto;}
.pagination {text-align: center; width: 100%;}
.menu_wrap {width: 100%; background: yellow;margin-bottom: 30px;}
.menu_wrap > ul {list-style: none;width: 80%;margin: 0 auto;padding: 0;}
.menu_wrap > ul > li {display: inline-block;}
.menu_wrap > ul > li > a {padding: 10px; color: red; display: inline-block;}
.menu_wrap > ul > li > a:hover {text-decoration: none;background: none;}
.create-faq { alignment: right;}
</style>
<script type="text/javascript" src="/static/bootstrap.js"></script>
<script type="text/javascript" src="/static/jquery.bootstrap.modal.forms.js"></script>
<div class="modal fade" tabindex="-1" role="dialog" id="modal">
<div class="modal-dialog" role="document">
<div class="modal-content">
</div>
</div>
</div>
<div class="menu_wrap">
<ul>
<li><a href="">menu1</a></li>
<li><a href="">menu2</a></li>
<li><a href="">menu3</a></li>
<li><a href="">menu4</a></li>
</ul>
</div>
<div class="content_wrap">
<form action="/list_faqs/" method="get">
<fieldset>
<label for="search_type">카테고리</label>
<select id="search_type" name="search_type">
<option value="1" {% if type == '1' %} selected {% endif %} >질문</option>
<option value="2" {% if type == '2' %} selected {% endif %} >내용</option>
<option value="3" {% if type == '3' %} selected {% endif %} >질문+내용</option>
</select>
<label>검색어 <input type="text" name="search_keyword" value="{{ keyword }}" /></label>
<button type="submit">검색</button>
<button id="button_3" class="create-faq btn btn-sm btn-primary" type="button" >질문답변 새로만들기</button>
</fieldset>
</form>
<table class = "tg">
<colgroup>
<col width="10%">
<col width="5%">
<col width="40%" span="2">
<col>
</colgroup>
<tr>
<th class="tg-21xh"> 코드 </th>
<th class="tg-21xh"> 타입 </th>
<th class="tg-21xh"> 질문 </th>
<th class="tg-21xh"> 답변 </th>
<th class="tg-21xh"> 작업 </th>
</tr>
{% for faq in faqs %}
<tr>
<td>{{ faq.faq_id }}</td>
<td>{{ faq.faq_type }}</td>
<td>{{ faq.faq_question }}</td>
<td>{{ faq.faq_answer }}</td>
<td><button id="button_1" class="update-faq btn btn-sm btn-primary" data-id="{% url 'update_faq' faq.pk %}">수정</button>
<button id="button_2" class="delete-faq btn btn-sm btn-primary" data-id="{% url 'delete_faq' faq.pk %}">삭제</button>
</td>
</tr>
{% endfor %}
</table>
<div class="pagination">
<span class="step-links">
{% if faqs.has_previous %}
<a href="?page=1&search_type={{ type }}&search_keyword={{ keyword }}">« first</a>
<a href="?page={{ faqs.previous_page_number }}&search_type={{ type }}&search_keyword={{ keyword }}">previous</a>
{% endif %}
<span class="current">
Page {{ faqs.number }} of {{ faqs.paginator.num_pages }}.
</span>
{% if faqs.has_next %}
<a href="?page={{ faqs.next_page_number }}&search_type={{ type }}&search_keyword={{ keyword }}">next</a>
<a href="?page={{ faqs.paginator.num_pages }}&search_type={{ type }}&search_keyword={{ keyword }}">last »</a>
{% endif %}
</span>
</div>
</div>
</body>
<script type="text/javascript">
$(function() {
$(".create-faq").modalForm({formURL: "{% url 'create_faq' %}"})
$(".update-faq").each(function () {
$(this).modalForm({formURL: $(this).data('id')});
});
$(".delete-faq").each(function () {
$(this).modalForm({formURL: $(this).data('id')});
});
});
</script>
</html>
일단은 현재 사용 중인 list_faqs.html
화면 상단에 메뉴바를 추가해봤다. CSS를 간단하게 만들고 href
를 이용해 간단하게 메뉴 1~4까지 텍스트로 만들어 보았다. 뭐 아직 4개나 필요한지 모르겠지만 일단 만들었다. 아마 1번째는 리스트 보는 거고 2번째가 로그 보는 거겠지?
이 메뉴를 만들기 위한 코드가 꽤 많이 필요한데, 사용해야 하는 화면마다 이 코드를 추가하면 번거로울 것이다. 물론 복붙 하면 되겠지만 나중에 관리하기 힘드니까. 그럼 어떻게 한 곳에서 관리할 수 있을까요? 일단 메뉴 부분만 따로 html로 만듭니다.
{# template/adminpage/menu.html #}
<style type="text/css">
.menu_wrap {width: 100%; background: yellow;margin-bottom: 30px;}
.menu_wrap > ul {list-style: none;width: 80%;margin: 0 auto;padding: 0;}
.menu_wrap > ul > li {display: inline-block;}
.menu_wrap > ul > li > a {padding: 10px; color: red; display: inline-block;}
.menu_wrap > ul > li > a:hover {text-decoration: none;background: none;}
</style>
<div class="menu_wrap">
<ul>
<li><a href="">menu1</a></li>
<li><a href="">menu2</a></li>
<li><a href="">menu3</a></li>
<li><a href="">menu4</a></li>
</ul>
</div>
이제 이 html을 필요한 곳에서 호출하기만 하면 됩니다. 호출하는 방법은 {% include "adminpage/menu.html" %}
을 이용하면 됩니다.
</div>
</div>
{% include "adminpage/menu.html" %}
<div class="content_wrap">
<form action="/list_faqs/" method="get">
요렇게 사이에 넣어주면 완성! 이제 메뉴를 누르면 어디로 이동할지 url만 정해주면 됩니다.
▷ 로그 페이지 만들기
이제 새로운 페이지를 만들어야 합니다. 로그페이지는 여태까지 우리가 사용하던 FAQ모델과는 다른 형태의 데이터이기 때문에 모델부터 새롭게 만들어야합니다.
# adminpage/models.py
from __future__ import unicode_literals
from datetime import datetime
from django.db import models
# Create your models here.
class Faq(models.Model):
faq_id = models.CharField(max_length=16, default='0000000000000001')
faq_type = models.CharField(max_length=10, default='999')
faq_question = models.TextField(default='질문')
faq_answer = models.TextField(default='답변')
def __str__(self):
return self.faq_question
class Log(models.Model):
log_date = models.DateTimeField(default=datetime.now())
log_userid = models.CharField(max_length=60)
log_question = models.TextField(default='질문')
log_answer = models.TextField(default='답변')
새로운 모델은 로그 형태이기 때문에 DateTimeField
가 들어갑니다. 그 외에는 뭐 특이사항은 없는 것 같네요. 그럼 로그 모델을 출력하는 views와 html을 만들어볼까요? Faq에 사용되는 것을 복붙 하면 금방 완성할 수 있습니다.
#adminpage/views.py
def listlogs(request):
search_type = request.GET.get('search_type')
search_keyword = request.GET.get('search_keyword')
if search_keyword is None:
search_keyword = ""
if len(search_keyword) > 0:
if search_type == '1':
log_list = Log.objects.order_by('pk').filter(Log_question__contains=search_keyword)
elif search_type == '2':
log_list = Log.objects.order_by('pk').filter(Log_answer__contains=search_keyword)
elif search_type == '3':
log_list = Log.objects.order_by('pk').filter(Q(Log_question__contains=search_keyword)
| Q(Log_answer__contains=search_keyword))
else:
search_type = '1'
search_keyword = ''
log_list = Log.objects.all()
paginator = Paginator(log_list, 5) # "5" 한페이지에서 보여줄 갯수를 정한다.
page = request.GET.get('page')
logs = paginator.get_page(page)
return render(request, 'adminpage/list_logs.html', {'logs': logs, 'type': search_type, 'keyword': search_keyword})
urlpatterns = [
.
url(r'^list_logs/', view2.listlogs, name='list_logs'),
.
]
{# template/adminpage/list_logs.html #}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="/static/jquery-3.2.1.min.js"></script>
<link rel="stylesheet" href="/static/bootstrap.css">
</head>
<body>
<style type="text/css">
.tg {border-collapse:collapse;border-spacing:0;}
.tg td{font-family:Arial, sans-serif;font-size:14px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg .tg-21xh{font-weight:bold;background-color:#34cdf9;color:#333333;border-color:inherit;text-align:left;vertical-align:top}
.tg .tg-0pky{border-color:inherit;text-align:left;vertical-align:top}
.content_wrap {width: 80%; margin: 0 auto;}
.pagination {text-align: center; width: 100%;}
</style>
<script type="text/javascript" src="/static/bootstrap.js"></script>
<script type="text/javascript" src="/static/jquery.bootstrap.modal.forms.js"></script>
<div class="modal fade" tabindex="-1" role="dialog" id="modal">
<div class="modal-dialog" role="document">
<div class="modal-content">
</div>
</div>
</div>
{% include "adminpage/menu.html" %}
<div class="content_wrap">
<form action="/list_logs/" method="get">
<fieldset>
<label for="search_type">카테고리</label>
<select id="search_type" name="search_type">
<option value="1" {% if type == '1' %} selected {% endif %} >질문</option>
<option value="2" {% if type == '2' %} selected {% endif %} >내용</option>
<option value="3" {% if type == '3' %} selected {% endif %} >질문+내용</option>
</select>
<label>검색어 <input type="text" name="search_keyword" value="{{ keyword }}" /></label>
<button type="submit">검색</button>
</fieldset>
</form>
<table class = "tg">
<colgroup>
<col width="10%">
<col width="10%">
<col width="40%">
</colgroup>
<tr>
<th class="tg-21xh"> 일시 </th>
<th class="tg-21xh"> 사용자 </th>
<th class="tg-21xh"> 질문 </th>
<th class="tg-21xh"> 답변 </th>
</tr>
{% for log in logs %}
<tr>
<td>{{ log.log_date }}</td>
<td>{{ log.log_userid }}</td>
<td>{{ log.log_question }}</td>
<td>{{ log.log_answer }}</td>
</tr>
{% endfor %}
</table>
<div class="pagination">
<span class="step-links">
{% if logs.has_previous %}
<a href="?page=1&search_type={{ type }}&search_keyword={{ keyword }}">« first</a>
<a href="?page={{ logs.previous_page_number }}&search_type={{ type }}&search_keyword={{ keyword }}">previous</a>
{% endif %}
<span class="current">
Page {{ logs.number }} of {{ logs.paginator.num_pages }}.
</span>
{% if logs.has_next %}
<a href="?page={{ logs.next_page_number }}&search_type={{ type }}&search_keyword={{ keyword }}">next</a>
<a href="?page={{ logs.paginator.num_pages }}&search_type={{ type }}&search_keyword={{ keyword }}">last »</a>
{% endif %}
</span>
</div>
</div>
</body>
</html>
순서대로 views.py
, urls.py
, list_logs.html
을 추가하고, ~/list_logs/로 접속해봅시다.
음 데이터가 없어서 그런지 뭔가 제대로 나오고 있는 건지 모르겠네요? ㅋㅋㅋ 일단 DB에 더미 데이터를 넣어봅시다.
이젠 화면에 보이겠죠?
이제 두 개의 화면이 나왔으니 메뉴바에 적용시켜 보죠!
{# template/adminpage/menu.html #}
<style type="text/css">
.menu_wrap {width: 100%; background: orange;margin-bottom: 30px;}
.menu_wrap > ul {list-style: none;width: 80%;margin: 0 auto;padding: 0;}
.menu_wrap > ul > li {display: inline-block;}
.menu_wrap > ul > li > a {padding: 10px; font-size:20px; color: black; display: inline-block;}
.menu_wrap > ul > li > a:hover {text-decoration: none;background: none;}
</style>
<div class="menu_wrap">
<ul>
<li><a href="{% url 'list_faqs' %}" >FAQ 데이터</a></li>
<li><a href="{% url 'list_logs' %}" >LOG 데이터</a></li>
<li><a href="">menu3</a></li>
<li><a href="">menu4</a></li>
</ul>
</div>
가볍게 새로운 페이지를 완성했습니다. 이제 남은 건 통계 페이지인데요. 그래프를 사용할지 표를 사용할지 모르니 천천히 생각해 봐야겠습니다. ㅎㅎ
'Study > python' 카테고리의 다른 글
python 문자열에서 HTTP 링크(URL) 탐지해서 링크생성하기 <a> 태그 이용 (0) | 2019.06.13 |
---|---|
웹알못 dJango로 홈페이지 만들기(관리자페이지) [4] (0) | 2019.05.20 |
웹알못 dJango로 홈페이지 만들기(관리자페이지) [2] (1) | 2019.05.16 |
웹알못 dJango로 홈페이지 만들기(관리자페이지) [1] (1) | 2019.05.16 |
Python 주식종목리스트 만들기, 현재가, 시세 조회하기 .feat 크롤링 (0) | 2018.06.26 |