Django tutorial 04

.·2020년 5월 5일
0

Coding

목록 보기
9/33

장고 튜토리얼 파트 4를 시작하지

1. form 사용하기

폼을 이용해서 클라이언트인 사용자로부터 서버쪽으로 데이터를 불러오는 방법을 학습해보기.

파트 3에서는 함수 기반 view 를 사용했다면 파트 4 에서는 클래스 기반 뷰를 학습하도록 한다.

클래스 기반 뷰로 구현하면 함수 기반 뷰와 같지만 소스 코드가 줄어든다.

먼저 템플릿내 detail.html 을 수정해주고,

polls/templates/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>

polls/views.py 내 vote 정의한 함수도 코드 수정해 넣자.(복붙s)

polls/views.py

from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse

from .models import Choice, Question
# ...
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):
        # Redisplay the question voting form.
        return render(request, 'polls/detail.html', {
            'question': question,
            'error_message': "You didn't select a choice.",
        })
    else:
        selected_choice.votes += 1
        selected_choice.save()
        # Always return an HttpResponseRedirect after successfully dealing
        # with POST data. This prevents data from being posted twice if a
        # user hits the Back button.
        return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))

import 부분을 제대로 입력하지 않으면 런서버시 오류가 난다. 주의하자.
결과 화면은 아래와 같고 코드를 보자.

일단 detail.html 을 보면 제목은 변경된 내용이 없고 이번템플릿에서는 서버
쪽으로 데이터 보내기 위해 form 태그와 input 태그를 사용하였다.
에러메시지를 전달받으면 에러 메시지를 전달해준다.

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

뷰에서 context 를 통해서 question 과 같이 전달되는 것을 생각해 볼 수 있다.

사용자가 서버로 데이터를 어떻게 보내는지 살펴보자.

form 태그, input 태그가 있다. label 태그는 이름 보여주는 태그, input 은 사용자가 무엇을 입력할 수 있도록 화면에 보여주는 태그이다.
radio 타입이 적용되어 있어서 radio 버튼이 있다.
submit type 등 input 타입은 다양다양 하다.

퀘스천의 질문을 외래키로 갖는 선택지를 모두 가지고 와서 반복문을 돌면서 하나씩 하나씩 보여지게 된다고 보면 된다.

화면에는 저렇게 보여주고 데이터는 어떻게 전달되냐면 사용자가 submit 타입의 input 을 누르면 해당 url 로 데이터가 전달되게 되고 해당 url 에 걸려 있는 (mysite-urls.py) 뷰에서 (views.vote) 데이터를 처리하게된다.

< form action="{% url 'polls:vote' question.id %}" method="post" >
method 가 POST 다. 데이터 생성이나 변경은 메소드로 POST를 쓰겠다 이렇게 입력한다 라는 것만 기억을 해 주면 되겠다.

{% csrf_token %}

이 코드는 왜 넣어 놓았냥? 사이트 간 위조 요청 이라고 해서 해킹 방지를 위해서 이러한 코드를 삽입한거. 사이트간 위조 요청은 사용자와 서버 사이에 데이터를 해커가 임의로 변경하는 것을 말하는 건데 웹 프레임워크를 사용하는 이유는 개발이 편리한 이유도 있지만 혼자서 보안에 대한 대비를 다 할 수가 없기 때문이다.
그래서 웹 프레임 워크를 이용하면 전반적인 보안에 대한 대비책을 마련해 준다.
결론 - 위의 코드는 사이트가 위조 요청을 막기 위해서 폼 태그 안에는 이렇게 위와같이 모두 입력해주면 된다.

사용자가 submit 버튼에 Input 버튼을 누르게 되면,
< input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" >

넘어가는 값은 value 값이 넘어가게 된다.
밸류 값이 넘어갔을 때 어떻게 사용하는지 이제 뷰에서 한번 보도록 하자.

다시 한번 보자면 저 라디오 버튼을 눌렀을 때, 해당 url 을 호출하게 되고 (mysite-urls.py) 해당 url 에서는 polls/views.py 뷰의 코드를 호출하게 된다.

뷰를 가서 소스를 한번 보자.

def vote 쪽을 보면 뷰를 호출 할 때 question_id 를 넘겨 받았다. 그러면 question 데이터를 넘겨받은 다음에 조회를 하게 된다.
question = get_object_or_404(Question, pk=question_id)

그리고 다음으로 이 question 에 대해서 외래 키를 갖는 선택들을 가져오게 된다.
selected_choice = question.choice_set.get(pk=request.POST['choice'])
이때의 조건이 선택지 중에서 pk 값이 템플릿에서 넘겨받은 값을 조회하게 되는 것이다. 앞전에서 request 는 많은 정보를 담고 있다고 했었다.

request는 템플릿에서 포스트 방식 으로 호출했기 때문에 위에 보듯이,
pk=request.POST['choice’] - request.POST 인풋의 네임 choice 이 있다.

< input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" >

이 네임 == choice 의 데이터를 가지고 와라 이다. 그러면 데이터를 가지고 와서 선택된 context를 가지고 오게 된다.
이때 선택된 데이터가 없는 다시 말해 데이터를 조회했을 때 데이터가 없다 그러면 예외가 발생을 하게 되고 예외발생했을 때 다시 상세 페이지로 리스폰스를 하게 된다.

except (KeyError, Choice.DoesNotExist):
        # Redisplay the question voting form.
        return render(request, 'polls/detail.html', {
            'question': question,
            'error_message': "You didn't select a choice.",

그러면 context 데이터 로는 question과 error 메시지를 보내 주게 된다.
에러 메시지는 디테일 템플릿에서 확인할 수 있고, 이렇게 데이터가 없는 경우 다시 상세 페이지를 보여주게 되고 이렇게 question과 error 메시지 데이터를 보내주게 된다.

컨텍스트 변수를 별도로 선언하지 않고 이렇게 데이터를 보낼 수 도 있겠다.

데이터가 있는 경우에는 선택지에 대해서 표를 1올려주고 저장을 해주게 된다.

else:
        selected_choice.votes += 1
        selected_choice.save()

result url 로 Redirect를 해주면 된다. ResponseRedirect는 위에 나온 POST 와 한 세트라고 생각하면 된다 포스트로 뷰가 호출된 경우에는 ResponseRedirect 를 해준다 라고 명심해 주면 된다.

HttpResponseRedirect(reverse('polls:results', args=(question.id,)))

reverse 는 처음 사용되었는데 url 을 하드코딩 하지 않기 위해서 reverse 를 사용해서 appname:urlname 을 사용하였다.

위의 def results(request, question_id) 이 쪽은 작성된 내용이 없으므로 문서를 보며 확인하자 진행하자.

설명한 내용을 곱씹은 뒤 튜토리얼을 찬찬히 읽어보면 좋을 것이다 왈왈왈

이제 result view 관련된 코드와 result.html 템플릿을 작성하고 오장.

polls/views.py

from django.shortcuts import get_object_or_404, render


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

views.py 를 보게 되면 아래 vote 쪽을 다시 말해보면 선택에 대한 vote 를 1 추가 해주고 그 다음 결과 페이지를 ( polls:results ) 보여주게 되어 해당 url 이 호출이 되고 이 results url 에서 다시 view 를 호출하게 된다. 그리고 난 다음에 question 을 조회한 다음에 result 템플릿이 결과 페이지로 보여지겠다.

return render(request, 'polls/results.html', {'question': question})

이때 question 데이터와 같이 넘어가게 되고 넘어간 데이터는 question 이 보여줄 것이고 question 에 대한 선택지 값들이 반복문을 돌면서 리스트로 뿌려지게 될 것이다.

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

위의 코드를 또 눈여겨보면, 선택.선택키텍스트, 선택키.투표수 , pluralize 처음보는 키워드 들이 있는데 이 키워드는 vote가 단수인 경우에는 단수처리를 하고 복수인 경우에는 복수 처리를 해주겠다 라는 django에서 제공하는 템플릿 기능중 하나이다.

pluralize 필터는 말 그대로 복수형으로 만들어주는 기능을 한다. 만약 choice_votes가 2 이상이라면, 앞의 vote 문자열에 s를 붙여 주어 복수로 되게 한다.

이제 투표를 웹상에서 해보고 결과 페이지를 보도록 하자.

import 를 제대로 했다면 에로메세지가 없었을 테지만 난 있었다.

여기까지가 사용자들로부터 데이터를 받아오는 방법을 학습하였고 클래스 기반 뷰 관련하여 살펴보자.

2. Generic View

클래스 기반 뷰는 Generic view 라고도 칭하는데 여기 장고 도큐먼트 보니까
제너릭 뷰 사용하기: 적은 코드가 더 좋습니다 이렇게 나오네.
일반적인 패턴들에 대해서는 장고에서 무언가 많이 만들어놓았기 때문에
우리는 파이썬 코드를 함수형기반 뷰에 비해서 (Generic view를 사용한다는 가정하에) 많이 작성을 하지 않아도 된다.

제너릭 뷰를 사용하기 위해서 polls/urls.py 와 views.py 를 수정하고 오자.

polls/urls.py

from django.urls import path

from . import views

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

polls/views.py

from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
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 ResultsView(generic.DetailView):
    model = Question
    template_name = 'polls/results.html'


def vote(request, question_id):
    ... # same as above, no changes needed.

제너릭 뷰는 함수기반 표와 달리 장고에서 미리 작성된 s 뷰 함수를 호출하여 view 를 호출하게 된다.

detail 이나 result url에도 파라미터의 이름을 지우고 pk 만 명시해주면 되겠다.

어차피 pk 값을 호출하겠거니 라고 생각하여 내부의 구현이 다 되어 있는 거다.
pk 란 db 내의 하나의 열 그러니까 하나의 데이터를 구분할 수 있는 값이다.
pk 값은 중복되지 않는다. view 가 호출이 되고 나면 함수 기반 뷰로 작성했던 소스 양이 확 줄어들어버린 것을 볼 수 있다.
사용할 템플릿 이름, 해당 템플릿에서 사용할 데이터 모델을 명시해주기만 하면 된다.

컨텍스트에 넘겨준 이름이 모델이름과 다르다면 컨텍스트 오브젝트 이름을 다시 정해주고
context_object_name = 'latest_question_list'

필요한 데이터를 get_queryset 함수를 통해서,

def get_queryset(self):
        """Return the last five published questions."""
        return Question.objects.order_by('-pub_date')[:5]

다시 작성해 주면 되겠다.

정상적으로 동작하는지 확인해 보도록 하자.
ok 정상적으로 작동하는구나.

정형화된 작업이 만들어져 있기에 기능들을 익혀 간편하게 사용하는 것이다.

장고에 익숙해질 때까지 함수 기반 view 를 작성하는 것을 권장한다고 함.
클래스 기반 view 는 처음 딱 보면 그냥 몇 줄에 무언가 나오는 모습이 너무 마법 같이 보여서 이해가 잘 안될 수도 있기 때문이다.
그래서 문법이 중요함을 느끼고 좀 이따 강의 쇼핑을 좀 해볼라고 한다. 나룸의돌파구쓰.

한 가지만 더 데이터 전송을 위해서 post 방식으로 요청하기 위해서,
POST 가 명시 되었다. (detail.html 을 봐)

인덱스 템플릿인 경우에 데이터 조회를 위해서 이러한 방식으로 조회용으로 요청하는 것은 GET 방식이라고 한다.
index.html 에서 보이듯 post 값이 명시된 내용이 없다.
여기서 알 수 있듯 GET 은 데이터 조회를 위한 요청 방식이다.

튜토리얼 4 마무리

profile
.

0개의 댓글