[Django] tutorial #4-form

์ •๋ณด๊ตฌ๋‹ˆยท2021๋…„ 11์›” 28์ผ
0

Django

๋ชฉ๋ก ๋ณด๊ธฐ
6/15
post-thumbnail

form์„ ์ด์šฉํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ์ธ ์‚ฌ์šฉ์ž๋กœ๋ถ€ํ„ฐ ์„œ๋ฒ„์ชฝ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด๋ ค๊ณ  ํ•œ๋‹ค.

์ €๋ฒˆ part3์—์„œ ๋งŒ๋“  ๋ทฐ๋Š” ํ•จ์ˆ˜๊ธฐ๋ฐ˜์ด์—ˆ๋‹ค.
์ด๋ฒˆ์—๋Š” class๊ธฐ๋ฐ˜์œผ๋กœ ๋ทฐ๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค.
class๊ธฐ๋ฐ˜ ๋ทฐ๋กœ ๊ตฌํ˜„ํ•˜๋ฉด ์†Œ์Šค์ฝ”๋“œ๊ฐ€ ์ค„์–ด๋“ ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.



๊ฐ„๋‹จํ•œ form ๋งŒ๋“ค๊ธฐ


polls/detail.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>

์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด์ž๋ฉด,
๋ฐ์ดํ„ฐ๋ฅผ ์ „์†ก์„ ์œ„ํ•œ ์š”์ฒญ๋ฐฉ์‹์„ post๋ฐฉ์‹์œผ๋กœ ํ•˜๊ธฐ ์œ„ํ•ด post๋ฅผ ๋ช…์‹œํ•ด์ฃผ์—ˆ๋‹ค.

์‚ฌ์šฉ์ž๊ฐ€ ์„œ๋ฒ„๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด์ฃผ๊ธฐ ์œ„ํ•˜์—ฌ form ํƒœ๊ทธ์™€ input ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜์˜€๋‹ค.

์‚ฌ์šฉ์ž๊ฐ€ submit type์˜ input tag์„ ๋ˆ„๋ฅด๋ฉด ํ•ด๋‹น url์ธ polls:vote๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ์ „๋‹ฌ๋˜๊ณ , ํ•ด๋‹น url์— ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋Š” ๋ทฐ์ธ views.vote๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ฒŒ ๋œ๋‹ค.

์ด๋•Œ ๋ทฐ๋กœ ์ „๋‹ฌ๋˜๋Š” ๋ฐ์ดํ„ฐ๋Š” value๊ฐ’์ด๋‹ค.


์—ฌ๊ธฐ์„œ ํ•ด๋‹น์ฝ”๋“œ๊ฐ€ ์‚ฌ์šฉ๋˜๋Š” ์ด์œ ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค

  • {% csrf_token %} : ์‚ฌ์ดํŠธ ์œ„์กฐ์š”์ฒญ์œผ๋กœ, ํ•ดํ‚น๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.



์šฐ๋ฆฌ๋Š” ์ด๋ฏธ polls ์•ฑ์„ ์œ„ํ•ด ์•„๋ž˜์— ๋‚˜์™€์žˆ๋Š” ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•˜๋Š” URLconf๋ฅผ ๋งŒ๋“ค์–ด ๋‘์—ˆ๋‹ค.

- polls/urls.py

path('<int:question_id>/vote/', views.vote, name='vote'),

๋˜ํ•œ ๊ฐ€์ƒ์œผ๋กœ ๋งŒ๋“ค์–ด ๋‘์—ˆ๋˜ vote() ํ•จ์ˆ˜๋ฅผ
์‹ค์ œ๋กœ ๊ตฌํ˜„ ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •ํ•ด์ค€๋‹ค.

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

๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ํ•ด์„ํ•ด๋ณด์ž๋ฉด,

  • def vote(request, question_id) : vote ๋ทฐ๋ฅผ ํ˜ธ์ถœํ• ๋•Œ question_id๋ฅผ ๋„˜๊ฒจ ๋ฐ›์Œ
  • question = get_object_or_404(Question, pk=question_id) : question_id๋ฅผ ๋„˜๊ฒจ ๋ฐ›์œผ๋ฉด question๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒ
  • except (KeyError, Choice.DoesNotExist):: ์กฐํšŒํ–ˆ์„ ๋•Œ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์œผ๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒ
  • return render(request, 'polls/detail.html', { 'question': question, 'error_message': "You didn't select a choice.", }) : ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ๋‹ค์‹œ detail.html(์ƒ์„ธํŽ˜์ด์ง€)๋กœ respose๋ฅผ ํ•ด์ฃผ๋ฉฐ, context ๋ฐ์ดํ„ฐ๋กœ question๊ณผ error_message๋ฅผ ๋ณด๋‚ด์คŒ
  • else: selected_choice.votes += 1 selected_choice.save() : ์กฐํšŒํ–ˆ์„ ๋•Œ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์œผ๋ฉด choice๋ฅผ 1 ์˜ฌ๋ ค์ฃผ๊ณ  ์ €์žฅ
  • return HttpResponseRedirect(reverse('polls:results', args=(question.id,))) : reverseํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด results ๋ทฐ๋ฅผ ํ˜ธ์ถœ.
    ์ด๋•Œ reverse๋Š” ๋ทฐ ํ•จ์ˆ˜์—์„œ url์„ ํ•˜๋“œ์ฝ”๋”ฉํ•˜์ง€ ์•Š๋„๋ก ๋„์™€์คŒ

์ˆ˜์ • ํ›„ ์„œ๋ฒ„๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด ๋งŒ๋“ค์–ด์ค€ form์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค.



results ๋ทฐ ๋งŒ๋“ค๊ธฐ


์‚ฌ์šฉ์ž๊ฐ€ ์„ค๋ฌธ์กฐ์‚ฌ์— ์„ค๋ฌธ์„ ํ•˜๊ณ ๋‚˜๋ฉด, vote ๋ทฐ๋Š” ์„ค๋ฌธ์กฐ์‚ฌ ๊ฒฐ๊ณผ ํŽ˜์ด์ง€result๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

๋”ฐ๋ผ์„œ result ๋ทฐ๋ฅผ ์ž‘์„ฑํ•ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค.

- polls/view.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})

results ๋ทฐ๋Š” question์„ ์กฐํšŒํ•œ ๋‹ค์Œ, results.html์„ ๊ฒฐ๊ณผํŽ˜์ด์ง€๋กœ ๋ณด์—ฌ์ค€๋‹ค.
์ด๋•Œ question ๋ฐ์ดํ„ฐ๊ฐ€ ํ…œํ”Œ๋ฆฟ์œผ๋กœ ์ „๋‹ฌ๋œ๋‹ค.


๋”ฐ๋ผ์„œ ๊ฒฐ๊ณผํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ํ…œํ”Œ๋ฆฟ์„ ์ž‘์„ฑํ•ด์ค€๋‹ค.

- polls/templates/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 ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์™€,
question_text๊ฐ€ ์ œ๋ชฉ์ด ๋˜๊ณ 
question์— ๋Œ€ํ•œ ์„ ํƒ์ง€(choice)๊ฐ’๋“ค์ด ๋ฐ˜๋ณต๋ฌธ์„ ๋Œ๋ฉฐ ๋ฆฌ์ŠคํŠธ๋กœ ๋“ค์–ด๊ฐ„๋‹ค.


์—ฌ๊ธฐ์„œ ์ฒ˜์Œ๋ณด๋Š” ํ‚ค์›Œ๋“œ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž๋ฉด,

  • vote{{ choice.votes|pluralize }} : pluralize๋Š” votes๊ฐ€ ๋‹จ์ˆ˜์ธ ๊ฒฝ์šฐ๋Š” ๋‹จ์ˆ˜์ฒ˜๋ฆฌ๋ฅผ, ๋ณต์ˆ˜์ธ ๊ฒฝ์šฐ๋Š” ๋ณต์ˆ˜์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋Š” ์žฅ๊ณ ์—์„œ ์ œ๊ณตํ•˜๋Š” ํ…œํ”Œ๋ฆฟ ๊ธฐ๋Šฅ์ด๋‹ค.

์œ„์™€ ๊ฐ™์ด ์ฒ˜์Œ๋ณด๋Š” ํ‚ค์›Œ๋“œ๊ฐ€ ์žˆ๋‹ค๋ฉด ์™ธ์šฐ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ํ‚ค์›Œ๋“œ์— ๋Œ€ํ•ด ๊ตฌ๊ธ€๋ง ํ•ด์„œ ์ฐพ์•„๋ณด๋ฉด ๋œ๋‹ค


์ด์ œ ์„œ๋ฒ„์—์„œ ์„ค๋ฌธ์— ๋Œ€ํ•œ ํˆฌํ‘œ๋ฅผ ํ•˜๊ณ ๋‚˜๋ฉด, ๊ฒฐ๊ณผํŽ˜์ด์ง€(results)๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.



generic ๋ทฐ ์‚ฌ์šฉํ•˜๊ธฐ


class ๊ธฐ๋ฐ˜์˜ ๋ทฐ๋ฅผ generic๋ทฐ๋ผ๊ณ ๋„ ํ•œ๋‹ค.

generic ๋ทฐ๋Š” ์ผ๋ฐ˜์ ์ธ ํŒจํ„ด๋“ค์— ๋Œ€ํ•ด ์žฅ๊ณ ์—์„œ ๋งŒ๋“ค์–ด๋†“์•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•จ์ˆ˜ํ˜• ๊ธฐ๋ฐ˜ ๋ทฐ์— ๋น„ํ•ด ์ฝ”๋“œ๋Ÿ‰์ด ์ ๋‹ค.

generic ๋ทฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด url๊ณผ views ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•ด์ค€๋‹ค.

- polls/url.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'),
]

generic๋ทฐ๋Š” ์žฅ๊ณ ์—์„œ ๋ฏธ๋ฆฌ ์ž‘์„ฑ ๋œ as_viewํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ทฐ๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ ๋œ๋‹ค.

์ด๋•Œ detail์ด๋‚˜ results url์—์„œ๋„ int:question_id๋ผ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์„ ์ง€์šฐ๊ณ  pk๋งŒ ๋ช…์‹œํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

์—ฌ๊ธฐ์„œ pk๋ž€ db๋‚ด์˜ ํ•˜๋‚˜์˜ ์—ด, ์ฆ‰ ํ•˜๋‚˜์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ’์ด๋‹ค. pk๊ฐ’์€ ์ค‘๋ณต๋˜์ง€ ์•Š๋Š”๋‹ค


- 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.

์ด๋ ‡๊ฒŒ generic ๋ทฐ์—์„œ๋Š”
์‚ฌ์šฉํ•  ํ…œํ”Œ๋ฆฟ ์ด๋ฆ„, ํ•ด๋‹น ํ…œํ”Œ๋ฆฟ์—์„œ ์‚ฌ์šฉํ•  ๋ฐ์ดํ„ฐ ๋ชจ๋ธ์„ ๋ช…์‹œํ•ด์ฃผ๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.

์ด๋•Œ context์— ๋„˜๊ฒจ์ฃผ๋Š” ๋ฐ์ดํ„ฐ์˜ ์ด๋ฆ„์ด ๋ชจ๋ธ์ด๋ฆ„๊ณผ ๋‹ค๋ฅด๋‹ค๋ฉด context_object_name์„ ๋‹ค์‹œ ์ •ํ•ด์ฃผ๊ณ ,
ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ get_queryset ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด์„œ ๋‹ค์‹œ ์ž‘์„ฑํ•ด์ฃผ๋ฉด ๋œ๋‹ค.


generic ๋ทฐ๋Š” ์ •ํ˜•ํ™”๋œ ์ž‘์—…๋“ค์ด ์ด๋ฏธ ๋งŒ๋“ค์–ด์ ธ ์žˆ์–ด ๊ธฐ๋Šฅ๋“ค์„ ์ตํ˜€ ๊ฐ„ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

ํ•˜์ง€๋งŒ ์žฅ๊ณ ์— ์ต์ˆ™ํ•ด์งˆ๋•Œ ๊นŒ์ง€๋Š” ํ•จ์ˆ˜ ๊ธฐ๋ฐ˜ ๋ทฐ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค!



๐Ÿ”Ž ์ฐธ๊ณ 
๋””์žฅ๊ณ  ๊ณต์‹๋ฌธ์„œ
๋””์žฅ๊ณ  ๊ณต์‹๋ฌธ์„œ ๊ฐ•์˜์ž๋ฃŒ

0๊ฐœ์˜ ๋Œ“๊ธ€