인프런 Django 강좌를 따라 실습하면서 간단하게 투표 기능을 할 수 있는 웹 어플리케이션을 만들어 보았다. 우선 투표 어플리케이션에 사용될 4개의 view를 설계해 보았다.
- Question Index Page : 최근 등록된 5개의 질문들을 보여주는 페이지
- Question Detail Page : 각 질문과 투표를 할 수 있는 User 폼을 보여주는 페이지
- Question Result Page : 각 질문에 대한 결과를 보여주는 페이지
- 투표 액션 : 특정 질문에 대해 투표를 핸들링
현재 Django 프로젝트 디렉터리 구조는 다음과 같다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
mysite
├── db.sqlite3
├── manage.py
├── mysite
│ ├── __init__.py
│ ├── __pycache__
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── polls
├── admin.py
├── apps.py
├── __init__.py
├── migrations
│ └── __pycache__
├── models.py
├── __pycache__
├── tests.py
├── urls.py
└── views.py
|
cs |
polls/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
|
import datetime
from django.db import models
from django.utils import timezone
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
def __str__(self):
return self.question_text
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
def __str__(self):
return self.choice_text
|
cs |
polls의 Django 모델을 정의해 놓은 polls/models.py는 위와 같이 구성해 놓았다.
- Question은 투표 항목의 제목(질문)이다. question_text는 해당 투표의 제목, pub_date는 등록된 시간을 말한다.
- Choice는 각 Question의 투표 항목을 말한다. 18행에서 볼 수 있듯이 Choice 모델은 Question 모델에 외래키로 포함되어 있다. choice_text는 투표 항목의 이름이고, votes는 각 항목별로 투표 수가 몇 개나 되는 지 알려주는 정수 값으로 기본 값은 0이다.
mysite는 프로젝트의 이름, polls는 투표 어플리케이션의 이름이다. 우선 CSS 파일이 있는 static 디렉터리와 HTML 파일이 있는 templates 디렉터리는 잠시 제외해 두기로 하고 나중에 이야기하려 한다.
앞에서 말한 4가지의 view를 제네릭으로 구현해 보았다.
polls/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
|
from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.views import generic
from .models import Choice, Question
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
'''Return the last five published questions'''
return Question.objects.order_by('-pub_date')[:5]
class DetailView(generic.DetailView):
model = Question
template_name = 'polls/detail.html'
class ResultView(generic.DetailView):
model = Question
template_name = 'polls/results.html'
def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
try:
selected_choice = question.choice_set.get(pk=request.POST['choice'])
except(KeyError, Choice.DoesNotExist):
return render(request, 'polls/detail.html', {
'question': question,
'error_message': "선택은 하셔야죵",
})
else:
selected_choice.votes += 1
selected_choice.save()
return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
|
cs |
IndexView()
polls 앱의 index 페이지(polls/index.html)를 보여준다. index 페이지에서 latest_questions_list라는 이름으로 최근 5개의 질문(Question 모델)을 보여준다.
DetailView()
각 Question 모델의 세부 페이지를 보여준다. 실제 테스트에서 적용되는 URL 형식은 polls/<pk>/이다. 질문의 내용을 보여주고, 그 아래 각 선택지를 선택하여 투표할 수 있게 한다. 실제 투표 액션은 vote()함수를 통해 실행한다. 1
ResultView()
각 Question 모델의 세부 페이지를 보여준다. 실제 테스트에서 적용되는 URL 형식은 polls/<pk>/results이다. 각 선택지에 현재 몇 개의 표가 들어와 있는지 보여준다. 2
vote()
실제 투표 액션을 수행하는 함수이다. detail 페이지에서 선택지를 고른 후 submit하면 해당 choice의 투표 수(votes)를 1개씩 증가시키고, 증가시킨 결과를 저장한다.(34행, selected_choice.save()) 선택하지 않고 submit을 하는 예외가 발생한다면(Choice.DoesNotExist) 에러 메시지로 '선택은 하셔야죵' 이라고 추가로 출력한다 (...)
'Back End' 카테고리의 다른 글
[Django] Django 모델 ForeignKeyField on_delete 종류 (0) | 2019.05.17 |
---|---|
[Django] Django MTV 개발 방식 (0) | 2019.05.16 |