본문 바로가기
source-code/Django

Polls App

by mattew4483 2020. 12. 28.
728x90
반응형

UI 설계 / 각각 index, detail, vote.html

전체 흐름

1. mysite project생성 -> polls app 생성

2. model 생성

3. urls 작성

4. 각 views & templates 작성


2. model 생성

models.py

 

직업, 선호, 지역을 물어볼 Question모델을 만든다.

DateTimeField에 정의한 'date published'는? 이후 admin에서 보게 될 문구!

 

각 Question(ex 직업이 무엇인가요?)마다 해당되는 Choice(ex 독서, 축구, 등산)가 필요하다.

즉 Question모델과 Choice모델을 Foreignkey로 상호참조.

여기서 ForeignKey는 항상 다른 모델의 PK와 연결되므로, Question의 id변수까지 지정할 필요가 없다.

(그냥 Question 클래스만 지정하면 됨)

이렇게 FK로 지정된 컬럼은 _id 접미사가 붙는다!!

다르게 말하자면, _id가 붙은 녀석들은 FK로 지정된 Choice모델의 question칼럼이란 말씀.

 

투표를 할 때마다 해당 Choice들의 숫자가 올라가므로 이를 나타내줄 IntergerField도 생성한다.

 

3. urls 작성

urls.py

path()는 기본적으로

첫번째 인자 -> 요청 받을 url

두번째 인자 -> 해당 url 요청시 작동될 함수

세번째 인자 -> 코드 내에서 지칭해줄 이름 으로 이해하면 쉽다.

 

path('polls/<int:question_id>/', detail, name='detail') 의 경우

요청 url이 polls/3/ 이면 views함수 호출 시 detail(request, questions_id=3)이 작동되고, 그 이름을 detail로 지어준 것!

여기서 int:question_id는 index.html에서 보내줄, 각 질문의 pk값이 되겠다.

 

4. Views & Templates 작성

1) index함수 & index.html 작성

views.py

Questions모델의 모든 dbjects들을 index.html에 뿌려준다!

이를 위해 Questions.objects.all() 사용.

뒤에 order_by('-pub_date') 는 칼럼이 만들어진 날짜인 pub_date의 역순(-)으로 정렬order하겠다는 뜻이다.

 

index.html

{% if latest_question_list %} -> 넘겨준 Questions.objects.all()일 경우 아래의 for문을 작동!

그 외의 경우(else) -> No Polls are available 이란 문구를 보여준다.

 

for문을 통해서는 Questions모델에 있는 quetions_text들을 하나하나 띄워줘야 한다.

즉 {% for question in latest_quetion_list %}를 통해 for문을 돌려주고,

{{question.question_text}} 를 통해 latest_question_list의 요소들 중 question_text를 하나씩 띄워준다!

 

각 question_text를 클릭하면 해당 질문에 맞는 detail 페이지로 이동해야한다.

따라서 a herf를 통해 링크를 걸어주고,

링크를 클릭하면 .../polls/해당 질문 id 라는 주소로 이동하도록 한다.

그리고 이는 아까 url 에서

요 녀석에 해당된다. 즉 이를 통해 detail 함수를 작동시키는 것!

그럼 이제 detail 함수와 페이지를 만들어보자.

 

2) detail함수 & detail.html 작성

views.py

detail 함수를 통해 각 Question 모델에 대응하는 choice들을 띄워줘야 한다.

이를 위해서는 Question 모델 각각의 고유 값들을 찾은 후, 고유 값에 해당되는 choice들을 가져와야한다.

'question_text의 고유 값' -> 이 녀석이 urls을 통해 보내준 question_id가 되는 것!

 

즉 get_object_or_404를 통해 Question모델에서 pk=question_id인 녀석들을 찾는다.

조건에 해당되는 객체가 없을 경우에는 404에러 반환!

 

detail.html

{{question.question_text}} -> 우선 해당 질문(question_text)을 띄워준다.

error_message -> 이 부분은 이후 vote에서 다룰 예정!

 

detail 페이지에서는 각 질문들에 대한 응답을 제출하는 기능이 필요하다. 이를 위해 우선 form태그 사용.

제출 시 (아직 만들지 않은) vote 함수가 작동해 해당 응답들을 count하게 해줄 예정이다.

{% url 'vote' question.id %} -> 요 녀석을 통해 vote url에 question의 id를 보내서 전달!

POST요청을 사용하기 때문에 밑에 {% csrf_token %} 도 야무지게 적어준다.

 

다음으로 모델에 담겨있는 항목들을 불러와 투표할 수 있도록 해야한다.

{% for choice in question.choice_set.all %}을 통해

Question모델(detail함수를 통해 question이란이름으로 html에 뿌려줬다)의 choice_set 속성에 든 항목 모두를 가져온다.

 

여기서 choice_set의 정체는?

현재 Choice모델은 Question과 ForeignKey로 연결된 상태.

우리는 question으로 연결된 Choice모델을 칼럼들을 가져오고 싶다!

이 때 사용하는 django의 기본값이 바로 _set.all이라고 생각하면 된다.

 

input type="radio"를 통해 해당 radio 버튼을 클릭하면,

POST 데이터가 'choice' = '3' (choice.id)과 같은 형태가 되도록 name과 value를 정의해준다.

 

{{choice.choice_text}}를 통해 for문을 돌며 받아온 choice내의 choice_text속성들을 하나하나 띄워준다.

 

마지막으로 이를 제출할 input type="submit"과 value를 입력.

 

이제 vote버튼을 누르면 작동될, 각 항목별 투표수를 세어주는 함수를 만들어 보자.

 

3) vote함수 작성

vote.py

길기도 하다!!

 

마찬가지로 question = get_object_or_404(Question, pk=question_id)를 통해 choice_set 속성에 든 항목들을 가져온다.

Choice모델을 검색하는데(question.choice_set.get) 그 조건을 pk=request.POST['choice']로 삼은 것!

 

만약 choice라는 key가 없으면 Keterror를 발생시킨다. 또한 조건에 맞는 객체가 없으면 Choice.DoesNotExist를 발생.

그리고 이러한 에러가 발생하면 다시 detail.html을 render한다.

이때 You didn't select a choice라는 에러메시지도 함께 html상에 뿌려준다. 

그리고 이것이 아까전에 지나간 error_message!

 

에러가 발생하지 않았을 때, 즉 정상적으로 처리됬을 때는 해당 함수를 작동시킨다.

selected_choice의 votes에 하나를 더해주고, .save로 저장!

 

마지막으로 HttpResponseRedirect를 통해 결과를 반환한다. 왜?

POST 방식의 form 데이터를 처리하는 경우,

그 결과를 보여줄 페이지로 이동시키기 위해서는 HttpResponseRedirect객체를 return하는 것이 일반적...이라고 한다.

그리고 이러한 HttpResponseRedirect 객체는 redirect할 타겟 URL을 인자로 받는데, 이는 reverse()함수로 만든다.

 

reverse()함수는 또 뭔디?

일반적으로 URL 스트링과 뷰를 매핑한 각 라인을 URL 패턴이라 하고 이름을 하나씩 부여한다.

그런데 이 반대 방향, 즉 URL 패턴명으로부터 URL 스트링을 구할 수 있는데 이것이 바로 reverse()함수.

함수의 인자로 reverse(URL 패턴명, URL 스트링에 사용될 파라미터) 를 받는다.

 

즉 간단히 말하자면 일반적으로 우리는

/polls/<question_id>/results/라는 url을 통해 views.result()를 작동시킨다.

하지만 reverse함수를 통해서는

reverse('polls.results', args=(question.id))로 /polls/<question_id>/results를 추출하는 것!

이렇게 적으니 뭔가 간단하다

 

4) results 함수 & results.html

마지막으로 투표 결과를 보여주는 results 함수와 html을 작성.

views.py

마찬가지로 question를 받아 results.html에 뿌려주자!

 

results.html

{% for choice in question.choice_set.all %} -> 아까랑 똑같다!

 

'설문항목' - '득표 수' vote(s) 형태로 띄워줘야 한다!

즉 {{choice.choice_text}}와 {{choice.votes}}를 통해 각 choice별 choice_text와 votes를 받아온다.

{{choice.votes|pluralize}}는 choice.votes 값에 따라 복수 접미사 s를 붙여주는 역할.


여기까지 잘 따라왔다면, 해당 페이지는 다음과 같다.

물론 디자인은 전혀 신경쓰지 않았다.

이상 Polls 애플리케이션 완성!

728x90
반응형

'source-code > Django' 카테고리의 다른 글

Books App _ log 만들기  (0) 2020.12.30
Books App _ home 만들기  (0) 2020.12.30
Books App _ Template 상속하기  (0) 2020.12.30
Books App  (0) 2020.12.29
자잘자잘 문제들  (0) 2020.11.03