이번 포스트에서는 Django로 설문조사 앱을 만들어 볼 것이다.

(이 포스트는 YOUTUBE : LIFE SOFT 님이 게시하시는 글을 통해 공부하고 작성한 것이다.)

1. 새로운 프로젝트 만들기

File -> New -> Other (Ctrl + N)을 누르면 다양한 옵션들이 뜰 것이다.
Django를 검색하면 나오는 PyDevDjango를 선택하고, 이름을 정해서 만들어주자.

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에서 지원하는 modelsModel이라는 클래스를 상속하는 자식 클래스 SurvyAnswer를 만들어준다.

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() 함수를 통해 SurveySurveyAdmin, 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.rawSQL 코드를 사용하고 싶을 때 사용하는 함수로, raw 뒤에 나오는 “"”이 것들”"”을 SQL 코드로 입력할 수 있다.

zip(surveyList, answer)surveyListanswer를 합쳐준다. (압축 파일 같은 역할)

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>