Archive

[Django] View / Template Coding Overview (실습2) 본문

------ Web ------/Backend

[Django] View / Template Coding Overview (실습2)

enent 2022. 6. 26. 17:34
반응형

0. Overview

- View/ Template 코딩전에 Request / Response에 대한 로직을 설계하고 시작해야 한다.

- URL ~ View 는 N:1 매핑이 가능하다.

 

 

 

 

코딩순서

urls.py

views.index()

views.detail()

views.vote()

views.results()

 

 

1. URLconf 

위의 로직에 따라 URLconf와 View를 설계해 보면 아래와 같다

URL 패턴 뷰 이름 뷰가 처리하는 내용
/polls/ index() index.html template 보여줌
/polls/5/ detail() detail.html template 보여줌
/polls/5/vote/ vote() detail.html에 있는 form을
POST방식으로 처리
/polls/5/results/ results() results.html template 보여줌

 

urls.py에는 Urlpatterns 내 path()함수를 통해 URL~ View 매핑을 정의한다.

1) poll/urls.py 

from django.urls import path
from . import views

app_name='polls'
urlpatterns = [
    path('', views.index, name = 'index'),
    path('<int:question_id>/', views.detail, name = 'detail'),
    path('<int:question_id>/results/', views.results, name = 'results'),
    path('<int:question_id>/vote/', views.vote, name = 'vote'),
]

2) project/urls.py 

from django.contrib import admin
from django.urls import path, include


urlpatterns = [
    path('admin/', admin.site.urls),
    path('polls/', include('polls.urls')),
]

 

*path() 함수는 route, view(이상 필수), kwargs, name (이상 선택) parameter를 받는다

*path내 name인자가 애플리케이션에 따라 중복될 수 있으므로 app name을 :을 통해 명시해주는 것이 일반적이다.

 

 

2. view.index()

사람에 따라 templaate , view 구현 순서는 다르나, 일반적으로는 만들려는 화면을 먼저 그려놓고 로직을 구현을 하는 것 같다.

 

① 간단한 화면 UI 설계 (index.html)

② index.html 구현 (Template)

  • index.html을 작성하면서 어떤 context 변수를 template에 넘겨줘야 할 지 파악한다.
    : 아래의 예시 코드에선 question_text, question.id가 필요하므로, 이 두 가지 정보가 같이 들어있는 Question 객체를 view함수로 부터 받으면 된다.
  • index.html 이 저장되는 위치는 나중에 애플리케이션이 많아졌을 시의 관리의 편의성을 위해 Root Dir/Application Dir/Template Dir/Application Name/index.html 이다. (ex.mysite/polls/template/polls/index.html)
{%  if latest_question_list %}
<ul>
    {% for question in latest_question_list %}
        <li>
            <a href="/polls/{{ question.id }}/'">{{ question.question_text }}</a>
        </li>
    {% endfor %}
</ul>
{% else %}
    <p>No polls are available</p>
{%  endif %}

 

③ views.py 내 index() 구현

from django.shortcuts import render
from polls.models import Question

def index(request):
    latest_question_list = Question.objects.all().order_by('-pub_date')[:5]
    context = {'latest_question_list' : latest_question_list}
    return render(request, 'polls/index.html', context)

*render() : Template 변수는 Dict()형태로 전달하는데, 이를 Render함수에 보내면, 이를 기반으로 HTML text를 만들고, Http Response 객체를 반환한다.

 

3. view.detail()

① 간단한 화면 UI 설계 (detail.html)

 

② detail.html 구현 (Template)

  • detail.html을 작성하면서 어떤 context 변수를 template에 넘겨줘야 할 지 파악한다.
    : 아래의 예시 코드에선 question_text, question.id,. question.choice_set 변수가 필요하므로, 같이 들어있는 Question 객체를 view함수로 부터 받으면 된다.
  • detail.html 이 저장되는 위치는 나중에 애플리케이션이 많아졌을 시의 관리의 편의성을 위해 Root Dir/Application Dir/Template Dir/Application Name/detail.html 이다. (ex.mysite/polls/template/polls/detail.html)
<h1>{{ question.question_text }}</h1>

{% if error_message %}<p><strong>{{ error_message }}</strong></p>{ % endif%}

<form action ="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
        <input type="radio" name="choice" id="choice{{ forloop.counter }}" value ="{{ choice.id }}" />
        <label for="choice{{ forloop.counter }}"> {{ choice.choice_text }}</label><br />
{% endfor %}
<input type="submit" value="Vote" />
</form>

* 서버측의 데이터를 변경하는 경우 POST 방식 사용

* 보안 측면에서 CSRF(Cross Site Request Forgery) 공격을 막기 위해 {% csrf_token%} template 태그 사용

* radio button : 옵션 선택할 때 사용하는 ○ 모양 버튼. 해당 버튼을 선택하면 POST 데이터가 choice=3 을 choice.id 형태로 구성하게끔 되어있다.

*forloop.counter : for loop 실행 횟수를 담고있는 template 변수

*vote버튼을 클릭하면 사용자가 선택한 form 데이터가 POST방식으로 polls:vote URL로 전송된다. <input>태그의 name, value 속성 값들이 request.POST 사전에 key, value로 사용된다

 

 

③ views.py 내 detail() 구현

index.html에서 질문 하나를 클릭하면, /polls/1/과 같은 URL이 넘어오고, detail() view 함수가 호출된다.

from django.shortcuts import render, get_object_or_404
from polls.models import Question

def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'polls/detail.html', {'question': question})

*get_object_or_404 : Question 클래스로부터 pk=-question_id 검색 조건에 맞는 객체 조회, 조건에 맞는 객체가 없으면 Http404 Exception 발생

 

 

4. view.vote() 및 redirection

detail.html에서 template에 있는 form 을 제출하면, /polls/5/vole/와 같은 URL 이 POST 방식으로 넘어온다.

 

from django.shortcuts import render, get_object_or_404
from django.http import HttpResponseRedirect, HttpResponse
from django.urls import reverse
from polls.models import Choice, Question
# Create your views here.


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' : "You didn't select a choice.",
        })
    else:
        selected_choice.vote+=1
        selected_choice.save()
        return HttpResponseRedirect(reverse('polls:results',args=(question.id,)))

* Form 의 POST 데이터에서 'choice'라는 key가 없으면 KeyError Exception 발생 / 검색 조건에 맞지 않으면 DoesNotExist Exception 발생

  - Exception이 발생하면 render() 함수에 의해, question과 error_message Context 변수를 detail.html로 전 / 사용자에게는 Error message와 함께 Form을 다시 보여줘서 데이터를 재입력 할 수 있도록 함

*vote() 가 반환하는 객체는 HttpResponseRedirect로, 객체의 생성자가 Redirect할 Target URL을 인자로 받는다. (Target URL은 reverse()로 생성)

*reverse() : URL 패턴 이름, URL String에 사용될 Parameter를 받아, URL 패턴 이름으로 부터 URL String을 만듦

 

5. view.results()

① views.py 내 results() 구현

results() view 함수의 호출과 연계된 URL은 votes() view 함수의 Redirect 결과로 받는다 

: 즉, Form 을 처리한 후 결과를 보여주는 페이지로 redirect시켜주기 위해 votes()에서 redirect 객체를 return 한다. 웹에서는 이를 받아서 redirect URL로 다시 요청을 보내게 된다

 

from django.shortcuts import render, get_object_or_404
from django.http import HttpResponseRedirect, HttpResponse
from django.urls import reverse
from polls.models import Choice, Question
# Create your views here.
 return HttpResponseRedirect(reverse('polls:results',args=(question.id,)))
    
def results(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'polls/results.html', {'question':question})

 

② 간단한 화면 UI 설계 (results.html)

③ results.html 구현 (Template)

<h1>{{ question.question_text }}</h1>

<ul>
    {% for choice in question.choice_set.all %}
    <li>{{ choice.choice_text }} - {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
    {% endfor %}
</ul>

<a href = "{% url 'pools:detail' question.id %}">Vote again?</a>

*pluralize : | 앞의 choice.votes 값에 따라 복수 접미사(s)를 붙여주는 함수

*{ % url % } : View 내의 reverse()와 같이, URL 스트링을 추출할 수 있게 해주는 태그 

 

 

 

6. run server

① admin page 에서 데이터 등록

 

Question 등록

 

Choice 등록

 

② /polls 확인

 

*후기

너무 허접해서 웃기고 조금은 황당하다. 원래 처음은 다 이렇게 시작하는 것이라며,, 

 

 

 

파이썬 웹 프로그래밍  - 3. Django 웹프레임워크
반응형
Comments