ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Part 4 폼과 기본 뷰
    Django 2022. 7. 2. 13:41

    간단한 폼 쓰기

    polls/detail.html템플릿에 HTML <form> 요소를 포함시켜 봅시다.

    polls/templates/polls/detail.html¶
    <form action="{% url 'polls:vote' question.id %}" method="post">
    {% csrf_token %}
    <fieldset>
        <legend><h1>{{ question.question_text }}</h1></legend>
        {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
        {% 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 %}
    </fieldset>
    <input type="submit" value="Vote">
    </form>

     

    기존에 확인했던 What's new?라는 질문을 확인할 수 있는 question_text가 있고

    에러 메시지를 전달받게 되면 에러메시지를 출력하는 if문이 보입니다. 

    label은 이름(choice 목록들)을 보여주고
    input은 사용자가 입력할 수 있는것을 보여줍니다.

     question에 choice 선택지들을 모두 가지고 와서 반복문(for)을 돌면서 보여지게 됩니다.
    (forloop.counter 는 for 태그가 반복을 한 횟수를 나타냅니다.)

     

     

     

    radio 타입의 choice 목록 버튼들이 나오며
    버튼 중 하나를 선택하여 폼을 제출하면 POST 데이터인 choice=#을 보냅니다.
    (여기서 #은 선택한 항목의 ID입니다.)

     

    POST 양식을 만들고 있기 때문에(데이터를 수정하는 효과가 있을 수 있음), 
    교차 사이트 요청 위조 때문에 {% csrf_oken %}코드를 넣습니다.(해킹 방지)

     

    사용자가 submit 타입의 input버튼(사이트 화면의 vote)을 누르게 되면

    해당 url('polls:vote')로 데이터가 전달되게 되고
    해당 url에 걸려있는 view(vote( ))에서 데이터를 처리합니다.

     

     

     

    polls/views.py에 vote( )부분을 다음과 같이 추가해 주세요.

    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,)))

     

    request.POST 는 키로 전송된 자료에 접근할 수 있도록 해주는 사전과 같은 객체입니다. 
    이 경우, request.POST['choice'] 는 선택된 설문의 ID를 문자열로 반환합니다.

     

    question에 대한 choice들을 가져오게 되는데 
    이때 (get) 조건이 선택지 중에서 pk값이 템플릿에서 넘겨받은 값을 조회하게 되는겁니다.

     


    만약 POST 자료에 choice 가 없으면,(except 부분)
    request.POST['choice'] 는 KeyError 가 일어납니다. 

    위의 코드는 KeyError 를 체크하고, 
    choice가 주어지지 않은 경우에는 에러 메시지와 함께 설문조사 폼을 다시보여줍니다.

     

     

    데이터가 있는경우에는,(else 부분)
    선택지에서 투표를 1올려주고 저장하게 되며
    results url('polls:results')로 돌려보내(Redirect)줍니다.
     reverse() 함수는 뷰 함수에서 URL을 하드코딩하지 않도록 도와줍니다.

     

     

     

     

     

     

    polls/views.py에 results( )를 다음과 같이 수정해 주세요.

    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})

     

     

    앞 내용에 이어서 (vote( )의 else 부분)

    results url('polls:results')에서 results view를 호출하게 되고

    question을 조회를 한 다음 results 템플릿('polls/results.html')이 결과 페이지로 보여집니다.

     

     

     

    polls/results.html 템플릿도 만들어 주세요.

    <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 'polls:detail' question.id %}">Vote again?</a>

     

     

    question에 대한 선택지 값들이 반복문을 돌면서 리스트로 반환됩니다.(선택지 이름, 선택지 투표수)

    pluralize는 votes가 단수인 경우에는 단수처리를 복수인 경우에는 복수처리를 해주겠다는
    장고에서 제공하는 템플릿 기능중 하나입니다.

     

     

     

     

    이제, 웹 브라우저에서 /polls/1/ 페이지로 가서, 투표를 해보세요.
    투표를 할 때마다 값이 반영된 결과 페이지를 볼 수 있을 것입니다. 
    만약 설문지를 선택하지 않고 폼을 전송했다면,
    오류 메시지를 보게 될 것입니다.

     

     

     

     

     

     

     

     

     

     

    제너릭 뷰 사용하기: 적은 코드가 더 좋습니다.

    클래스 기반 뷰는 제너릭 뷰라고도 합니다.
    제너릭 뷰는 일반적인 패턴을 추상화하여 앱을 작성하기 위해 Python 코드를 작성하지 않아도됩니다.

     

    polls/urls.py URLconf를 열어 다음과 같이 변경해 주세요.

     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'),
    ]

     

     

    제너릭 뷰는 함수 기반 뷰와 달리
    장고에서 미리 작성된 as_view( ) 함수를 이용하여 view를 호출하게 됩니다.
     <question_id> 에서 <pk> 로 변경해주면 됩니다.

     

     

     

    polls/views.py에 index, detail, results뷰를 다음과 같이 수정해 주세요.

    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.

     

     

    함수기반 뷰를 작성했던 소스코드 양이 줄어든 것을 확인할 수 있습니다.

    사용할 템플릿 이름, 해당 템플릿에서 사용할 데이터 모델을 적어주면 됩니다.

    context에 넘겨주는 이름이 모델 이름과 다르다면
    context_object_name을 정해주고
    필요한 데이터를 get_queryset( ) 함수를 통해서 작성해주면 됩니다.

     

     

     

     

     

     

     

     

    출처 : django 웹 프로그래밍 강좌 (#4 form, generic view)(django form 사용, 데이터 받아오는 법, generic view 사용)

    Django part4

    'Django' 카테고리의 다른 글

    Part 6 정적 파일  (0) 2022.07.03
    Part 5 테스팅  (0) 2022.07.02
    Part 3 뷰와 템플릿  (0) 2022.07.01
    Part 2-2 관리자 페이지  (0) 2022.06.29
    part 2-1 모델  (0) 2022.06.29
Designed by Tistory.