Django #6 | Django_tutorial(part#4)

신승호·2021년 4월 27일
0

Django

목록 보기
7/7

Write a minimal form

  • 투표 상세 template인 polls/detail.htmlform을 넣어보자 ! !
<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 }}">		# 질문 선택 항목에 대한 `라디오 버튼 표시` / 각 라디오 버튼의 value는 "연관된 질문 선택 항목"의 ID 임/ 라디오 버튼의 name은 `choice`임
    <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>			# forloop.counter 는 for 태그가 반복을 한 횟수를 나타냅니다.

{% endfor %}
<input type="submit" value="Vote">
</form>

** 위 코드는 form의 액션과, post 메소드를 세팅해놓은것
  - post 메소드(get 메소드와 반대)
     - 폼을 서밋하는 행동은 서버사이드 데이터를 바꿀꺼임 
     - 그래서 폼을 생성할때 마다 데이터를 바꾼다는 말임, 그때마다 post 메소드를 쓴다는 말이고
     - post from은 "{% csrf_token %}" template태그를 써야함, 
        - 왜냐면 post form을 생성할때마다 데이터에 영향을 주기때문에 사이트간 요청 위조를 조심해야되지만, 저거 쓰면 괜찮음 ^ _^ 저게바로 장고 헬프시스템이라 걱정 ㄴㄴ
  • 즉, 누군가가 라디오 버튼 중 하나를 선택하여 form을 제출하면, POST 데이터 인 choice=#을 보낼 것입니다. 여기서 #은 선택한 항목의 ID임.
  • **이게바로 HTML 폼의 기본 개념

Django 뷰를 수정하여 데이터 처리하기

제출된 데이터를 처리하고 그 데이터로 무언가를 수행하는 Django 뷰를 작성

  • 현재 polls/urls.pyvote는 아래와 같음
path('<int:question_id>/vote/', views.vote, name='vote'),
  • urls.pyviews.py랑 연결이자나 ? 음 그럼 views.py에 뭐좀 추가해볼까
from django.shortcuts import render
from django.http import HttpResponse, Http404   # 이거 추가됬어
from django.template import loader

from .models import Choice,  Question

# Create your views here.
def index(request):
    #return HttpResponse("Hello, world")
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    template = loader.get_template('polls/index.html')
    context = {
        'latest_question_list': latest_question_list,
    }
    return HttpResponse(template.render(context,request))

def detail(request, question_id):
    try:
        question = Question.object.get(pk=question_id)
    except Question.DoesNotExist:
        raise Http404("Question doex not exist")
    return render(request, 'polls/detail.html', {'question':question})

def results(request, question_id):
    response = "You're looking at the results of question %s."
    return HttpResponse(response % question_id)

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'])		# request.POST 는 키로 전송된 자료에 접근할 수 있도록 해주는 사전과 같은 객체 / request.POST['choice'] 는 선택된 설문의 ID를 문자열로 반환합니다. request.POST 의 값은 항상 문자열들		
    except (KeyError, Choice.DoesNotExist):						# POST 자료에 choice 가 없으면, request.POST['choice'] 는 KeyError 가 일어나기 때문에 에러 체크하고
        return render(request, 'polls/detail.html', {					# choice가 주어지지 않은 경우에는 에러 메시지와 함께 설문조사 폼을 다시보여줌
            'question': question,
            'error_message' : "You didn't select a choice.",
        })
    else:
        selected_choice.votes += 1
        selected_choice.save()
        return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))	# 문지의 수가 증가한 이후에, 코드는 일반 HttpResponse 가 아닌 HttpResponseRedirect 를 반환

설문조사 이후 나오는 결과 페이지 만들어 보자

  • 설문조사에 설문을 하고난 뒤에는, vote() 뷰는 설문조사 result 페이지로 리다이렉트 함
    • detail() 클래스와 거의 동일
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})
  • polls/result.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>

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

URLconf 수정

  • 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'),		#  <question_id> 에서 <pk> 로 변경
    path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),	#  <question_id> 에서 <pk> 로 변경
    path('<int:question_id>/vote/', views.vote, name='vote'),
]

views 수정

-이전의 index, detail, results 뷰를 제거하고 장고의 일반적인 뷰를 대신 사용

  • 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.
  • ListViewDetailView의 두 가지 제너릭 뷰를 사용

    • 개체 목록 표시특정 개체 유형에 대한 세부 정보 페이지 표시 개념을 추상화
  • 각 제너릭 뷰에서는 어떤 model이 실행되는지 알아야하며, 이건 model 속성을 사용하면서 알려준다.

  • DetailView generice view

    • question_id 를 pk로 바꾼다.
    • DetailView generic view는 기본적으로 app이름/model이름_detail.html template를 사용함
      • 이번엔 template "polls/question_detail.html"을 사용
    • 템플릿 네임은 자세한걸로 써라 ㅡ ㅡ
    • results list view에서도 템플릿 네임 지정해 / 이게 detail뷰랑 result뷰가 렌더링 될때 다른 모습을 가질꺼임 같은 DetailView generic view라고 해도
  • ListView generice view

    • DetailView generic view는 기본적으로 app이름/model이름_list.html template를 사용함
      • 이번엔 그냥 지금있는 polls/index.html이라는 템플릿 네임 사용
  • the templates have been provided with a context that contains the question and latest_question_list context variables.

    • For DetailView
      • the question variable is provided automatically
      • Django is able to determine an appropriate name for the context variable.
    • for ListView
      • the automatically generated context variable is question_list.

    To override this we provide the context_object_name attribute, specifying that we want to use latest_question_list instead. As an alternative approach, you could change your templates to match the new default context variables – but it’s a lot easier to tell Django to use the variable you want.

profile
신승홉니다

0개의 댓글