이번 포스트에서는 Django로 설문조사 앱을 만들어 볼 것이다.
(이 포스트는 YOUTUBE : LIFE SOFT 님이 게시하시는 글을 통해 공부하고 작성한 것이다.)
1. 새로운 프로젝트 만들기
File -> New -> Other (Ctrl + N)을 누르면 다양한 옵션들이 뜰 것이다.
Django를 검색하면 나오는 PyDev의 Django를 선택하고, 이름을 정해서 만들어주자.
2. 기본 테이블 생성 및 관리자 계정 (super user) 생성
python manage.py migrate
Anaconda Prompt에서 해당 프로젝트의 디렉토리로 간 뒤 이 코드를 입력해서 db.sqlite3라는 기본 테이블을 해당 디렉토리에 생성하자.
python manage.py createsuperuser
또한, 이 코드를 입력해서 관리자 계정을 만들어주자.
3. 설문조사 앱 만들기 및 세팅
Anaconda prompt에서 해당 프로젝트의 디렉토리에 다음 코드를 입력한다.
python manage.py startapp survey
그러면 해당 디렉토리에 설문조사 앱에 관련된 디렉토리가 추가된다.
이 작업 후에 projname/settings.py를 조금 수정해야한다.
INSTALLED_APPS라는 항목 안에 ‘survey’,를 추가해주고, LANGUAGE_CODE을 ‘ko-kr’, TIME_ZONE을 ‘Asia/Seoul’로 수정해준다.
이전 포스팅에서 디버깅 툴바에 대해 다뤘는데, 이 포스팅에서부터는 디버깅 툴바를 사용할 것이다.
디버깅 툴바에 대한 설정도 해주자.
우선 아래 코드를 추가해준다.
INTERNAL_IPS = ('127.0.0.1',)
또한, INSTALLED_APPS라는 항목 안에 ‘debug_toolbar’,를 추가해주고, MIDDLEWARE라는 항목 안에 ‘debug_toolbar.middleware.DebugToolbarMiddleware’,를 추가해준다.
4. 모델 클래스 정의와 Admin 사이트 설정
survey/models.py
from django.db import models
class Survey(models.Model):
survey_idx = models.AutoField(primary_key=True)
question = models.TextField(null=False)
ans1 = models.TextField(null=True)
ans2 = models.TextField(null=True)
ans3 = models.TextField(null=True)
ans4 = models.TextField(null=True)
status = models.CharField(max_length=1, default="y")
class Answer(models.Model):
answer_idx = models.AutoField(primary_key=True)
survey_idx = models.IntegerField()
num = models.IntegerField()
django에서 지원하는 models의 Model이라는 클래스를 상속하는 자식 클래스 Survy와 Answer를 만들어준다.
TextField는 여러줄이 가능한 필드지만, CharField는 한줄만 가능하다.
survey/admin.py
from django.contrib import admin
from survey.models import Survey, Answer
class SurveyAdmin(admin.ModelAdmin):
list_display = ("question", "ans1", "ans2", "ans3", "ans4", "status")
admin.site.register(Survey, SurveyAdmin)
admin.site.register(Answer)
SurveyAdmin 클래스를 만들어서 Survey라는 클래스가 관리자페이지에서 어떻게 보일지 정의해준다.
admin.site.register() 함수를 통해 Survey와 SurveyAdmin, Answer 클래스를 관리자 페이지에 등록해준다. register() 함수는 2개까지만 한 번에 등록할 수 있기 때문에 3개 이상은 2개씩 나누어 써줘야 한다.
이제 이렇게 만든 모델 클래스들을 데이터베이스에 반영해준다.
python manage.py makemigrations
python manage.py migrate
5. 웹서버 구동과 관리자 페이지
python manage.py runserver localhost:80
이 코드를 anaconda prompt에 입력해주면 이제 http://localhost 나 http://localhost:80를 통해 접속할 수 있다.
하지만, 전과는 다르게 오류가 뜰 것이다. 그 이유는 디버그 툴바 때문인데, 디버깅 툴바를 다룬 글에서 3번째 항목, urls.py를 수정하지 않았다면 오류가 뜰 것이다.
projname/urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import url
from django.conf import settings
from survey import views
from django.urls import include
urlpatterns = [
path('admin/', admin.site.urls),
]
if settings.DEBUG:
import debug_toolbar
urlpatterns += [
url(r"^__debug__/", include(debug_toolbar.urls))
]
우선 urls.py를 이렇게 바꿔주자. 그 후, 다시 웹 페이지에 접속하면 우측에 디버깅툴바가 뜬 것을 볼 수 있다. Page not found가 뜨는 이유는 아직 admin 페이지와 debug 페이지말고는 만들지 않았기 때문이다.
주소 뒤에 /admin을 붙여서 관리자페이지에 접속해서 로그인해준다.
관리자 페이지에서 Survey에 설문조사를 하나 만들어서 저장해보자.
SQLite Expert를 통해 db.sqlite3 파일을 확인해보면, survey_survey 테이블에 내용이 추가된 것을 알 수 있다.
6. Url과 페이지 작성
projname/urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import url
from django.conf import settings
from survey import views
from django.urls import include
urlpatterns = [
path('admin/', admin.site.urls),
url(r"^$", views.main),
url(r"^save_survey$", views.save_survey),
url(r"^show_result$", views.show_result),
]
if settings.DEBUG:
import debug_toolbar
urlpatterns += [
url(r"^__debug__/", include(debug_toolbar.urls))
]
survey/views.py
from django.shortcuts import render
from survey.models import Survey, Answer
from django.shortcuts import render_to_response, redirect
from django.views.decorators.csrf import csrf_exempt
def main(request):
survey=Survey.objects.filter(status="y").order_by("-survey_idx")[0]
return render_to_response("main.html", {"survey":survey})
@csrf_exempt
def save_survey(request):
print(request.POST['survey_idx'])
print(request.POST['num'])
dto = Answer(survey_idx=request.POST['survey_idx'], num=request.POST['num'])
dto.save()
return render_to_response("success.html", {"dto":dto})
def show_result(request):
idx = request.GET['survey_idx']
ans = Survey.objects.get(survey_idx=idx)
answer = [ans.ans1, ans.ans2, ans.ans3, ans.ans4]
surveyList = Survey.objects.raw("""
select
survey_idx,num,count(num) sum_num,
round((select count(*) from survey_answer
where survey_idx=a.survey_idx
and num=a.num)*100.0 /
(select count(*) from survey_answer
where survey_idx=a.survey_idx), 1) rate
from survey_answer a
where survey_idx=%s
group by survey_idx,num
order by num
""", idx)
surveyList=zip(surveyList, answer)
return render_to_response("result.html",{"surveyList":surveyList})
main(request)함수는 survey들 중 status가 “y”인 것들만 내림차순으로 정렬한 후 제일 첫번째 것을 가지고 main.html에 자료를 보내서 렌더시켜준다.
save_survey(request)에서 print함수는 Anaconda Prompt에서 값을 확인할 수 있게 도와준다.
show_result(request)함수에서 Survey.objects.raw 는 SQL 코드를 사용하고 싶을 때 사용하는 함수로, raw 뒤에 나오는 “"”이 것들”"”을 SQL 코드로 입력할 수 있다.
zip(surveyList, answer)는 surveyList와 answer를 합쳐준다. (압축 파일 같은 역할)
survey/templates/main.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script>
function show_result(){
location.href="show_result?survey_idx=";
}
</script>
</head>
<body>
<h2>온라인 설문조사</h2>
<form method="post" action="save_survey">
{% csrf_token %}
<br>
<input type="radio" name="num" value="1"><br>
<input type="radio" name="num" value="2"><br>
<input type="radio" name="num" value="3"><br>
<input type="radio" name="num" value="4"><br><br>
<input type="hidden" name="survey_idx" value="">
<input type="submit" value="투표">
<input type="button" value="결과 확인" onclick="show_result()">
</form>
</body>
</html>
survey/templates/success.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>온라인 설문조사</h2>
완료되었습니다.
<a href="/">Home</a>
<a href="show_result?survey_idx=">설문결과</a>
</body>
</html>
survey/templates/result.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>설문조사 결과</h2>
<table border="1">
<tr align="center">
<th>문항</th>
<th>응답수</th>
<th>응답비율</th>
</tr>
{% for row,ans in surveyList %}
<tr align="center">
<td>{{ans}}</td>
<td>{{row.sum_num}}</td>
<td>{{row.rate}}</td>
</tr>
{% endfor %}
</table>
</body>
</html>