View ๋ฐ Template ์ฝ”๋”ฉ ๐Ÿง 

jurinยท2021๋…„ 7์›” 12์ผ
0

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœํ•˜๊ธฐ - View ๋ฐ Template ์ฝ”๋”ฉ

polls ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•  ๋•Œ 3๊ฐœ์˜ ํŽ˜์ด์ง€๊ฐ€ ํ•„์š”ํ–ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•œ ๋ทฐ์™€ ํ…œํ”Œ๋ฆฟ์„ ์ฝ”๋”ฉํ•œ๋‹ค.

URL๊ณผ ๋ทฐ๋Š” 1:1 ๊ด€๊ณ„๋กœ ๋งคํ•‘๋œ๋‹ค. ์ด๋Ÿฌํ•œ URL/๋ทฐ ๋งคํ•‘์„ URLconf๋ผ๊ณ  ํ•˜๋ฉฐ urls.py ํŒŒ์ผ์— ์ž‘์„ฑํ•œ๋‹ค.

์ด ์„ค๊ณ„ ๋‚ด์šฉ์„ ๊ฐœ๋ฐœํ•˜๊ธฐ ์œ„ํ•ด ์•„๋ž˜ ์ˆœ์„œ๋Œ€๋กœ ์ฝ”๋”ฉ์„ ์ง„ํ–‰ํ•œ๋‹ค. ๋กœ์ง์˜ ํ๋ฆ„์ƒ URLconf๋ฅผ ๋จผ์ € ์ฝ”๋”ฉํ•œ ํ›„์— ๋ทฐ, ํ…œํ”Œ๋ฆฟ ๋˜๋Š” ํ…œํ”Œ๋ฆฟ, ๋ทฐ ์ˆœ์„œ๋กœ ์ฝ”๋”ฉํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ด๋‹ค.

  1. urls.py ์ž‘์„ฑ - URLconf ๋‚ด์šฉ ์ฝ”๋”ฉ
  2. views.index() ํ•จ์ˆ˜ ์ž‘์„ฑ - index.html ํ…œํ”Œ๋ฆฟ๋„ ๊ฐ™์ด ์ž‘์„ฑ
  3. views.detail() ํ•จ์ˆ˜ ์ž‘์„ฑ - detail.html ํ…œํ”Œ๋ฆฟ๋„ ๊ฐ™์ด ์ž‘์„ฑ
  4. views.vote() ํ•จ์ˆ˜ ์ž‘์„ฑ - ๋ฆฌ๋‹ค์ด๋ ‰์…˜ ์ฒ˜๋ฆฌ ๋“ค์–ด์žˆ์Œ
  5. views.results() ํ•จ์ˆ˜ ์ž‘์„ฑ - results.html ํ…œํ”Œ๋ฆฟ๋„ ๊ฐ™์ด ์ž‘์„ฑ

URLconf ์ฝ”๋”ฉ

Admin ์‚ฌ์ดํŠธ ํฌํ•จ 5๊ฐœ์˜ URL๊ณผ ๋ทฐ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

urls.py

from django.contrib import admin
from django.urls import path
from polls import views

# URL ํŒจํ„ด ๋งค์นญ์€ ์œ„์—์„œ ์•Œ๋ž˜๋กœ ์ง„ํ–‰ํ•˜๋ฏ€๋กœ, ์ •์˜ํ•˜๋Š” ์ˆœ์„œ ์œ ์˜
urlpatterns = [ 
    path('admin/', admin.site.urls),
    path('polls/', views.index, name='index'),
    path('polls/<int:question_id>/', views.detail, name='detail'),
    path('polls/<int:question_id>/results/', views.results, name='results'),
    path('polls/<int:question_id>/vote/', views.vote, name='vote'),
]

path() ํ•จ์ˆ˜๋Š” route, view 2๊ฐœ์˜ ํ•„์ˆ˜ ์ธ์ž์™€ kwargs, name 2๊ฐœ์˜ ์„ ํƒ ์ธ์ž๋ฅผ ๋ฐ›๋Š”๋‹ค.

  • route : URL ํŒจํ„ด์„ ํ‘œํ˜„ํ•˜๋Š” ๋ฌธ์ž์—ด (=URL ์ŠคํŠธ๋ง)
  • view : URL ์ŠคํŠธ๋ง์ด ๋งค์นญ๋˜๋ฉด ํ˜ธ์ถœ๋˜๋Š” ๋ทฐ ํ•จ์ˆ˜. HttpRequest ๊ฐ์ฒด์™€ URL ์ŠคํŠธ๋ง์—์„œ ์ถ”์ถœ๋œ ํ•ญ๋ชฉ์ด ๋ทฐ ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ์ „๋‹ฌ.
  • kwargs : URL ์ŠคํŠธ๋ง์—์„œ ์ถ”์ถœ๋œ ํ•ญ๋ชฉ ์™ธ์— ์ถ”๊ฐ€์ ์ธ ์ธ์ž๋ฅผ ๋ทฐ ํ•จ์ˆ˜์— ์ „๋‹ฌํ•  ๋•Œ, ํŒŒ์ด์ฌ ์‚ฌ์ „ ํƒ€์ž…์œผ๋กœ ์ธ์ž๋ฅผ ์ •์˜
  • name : ๊ฐ URL ํŒจํ„ด๋ณ„๋กœ ์ด๋ฆ„์„ ๋ถ™์—ฌ์ค€๋‹ค. ์—ฌ๊ธฐ์„œ ์ •ํ•ด์ค€ ์ด๋ฆ„์€ ์ฃผ๋กœ ํ…œํ”Œ๋ฆฟ ํŒŒ์ผ์—์„œ ์‚ฌ์šฉํ•œ๋‹ค.

๋งŒ์ผ URL์ด /polls/3/ ์ด๋ผ๋ฉด URL ์ŠคํŠธ๋ง์—์„œ 3์ด ์ถ”์ถœ๋˜๋ฏ€๋กœ ๋ทฐ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ ์‹œ views.detail(request, question_id=3)์ฒ˜๋Ÿผ ์ธ์ž๊ฐ€ ๋Œ€์ž…๋œ๋‹ค.

mystie/settings.py ํŒŒ์ผ์— ROOT_URLCONF ํ•ญ๋ชฉ์ด ์ •์˜๋œ๋‹ค. ์žฅ๊ณ ๋Š” URL ๋ถ„์„ ์‹œ, ์ด ํ•ญ๋ชฉ์— ์ •์˜๋œ urls.y ํŒŒ์ผ์„ ๊ฐ€์žฅ ๋จผ์ € ๋ถ„์„ํ•˜๊ธฐ ์‹œ์ž‘ํ•œ๋‹ค.

URLconf๋ฅผ ์ฝ”๋”ฉํ•  ๋•Œ ์•ž์—์„œ์ฒ˜๋Ÿผ ํ•˜๋‚˜์˜ urls.py ํŒŒ์ผ์— ์ž‘์„ฑํ•  ์ˆ˜๋„ ์žˆ๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์ด mysite/urls.py์™€ polls/urls.py 2๊ฐœ์˜ ํŒŒ์ผ์— ์ž‘์„ฑํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

mysite/urls.py

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

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

polls/urls.py

from django.urls import path
from polls import views

# URL ํŒจํ„ด์˜ ์ด๋ฆ„์ด ์ถฉ๋Œ๋‚˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•œ ์ด๋ฆ„ ๊ณต๊ฐ„
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'),

]

์ด๋ ‡๊ฒŒ URLconf ๋ชจ๋“ˆ์„ ๊ณ„์ธต์ ์œผ๋กœ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ์ด ๋ณ€๊ฒฝ๋„ ์‰ฌ์›Œ์ง€๊ณ  ํ™•์žฅ๋„ ์šฉ์ดํ•ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ๋” ์ข‹๋‹ค.

๋ทฐ ํ•จ์ˆ˜ index() ๋ฐ ํ…œํ”Œ๋ฆฟ ์ž‘์„ฑ

UI ํ™”๋ฉด์„ ์ƒ๊ฐํ•˜๋ฉด์„œ ๋กœ์ง์„ ํ’€์–ด๋‚˜๊ฐ€๋Š” ๊ฒƒ์ด ์‰ฝ๊ธฐ ๋•Œ๋ฌธ์— ๋ทฐ๋ณด๋‹ค ํ…œํ”Œ๋ฆฟ์„ ๋จผ์ € ์ฝ”๋”ฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

index.html

{% if latest_question_list %}
<!--latest_question_list ๊ฐ์ฒด๋Š” index() ๋ทฐ ํ•จ์ˆ˜์—์„œ ๋„˜๊ฒจ์ฃผ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ์ด๋‹ค.-->
    <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 %}

index.html์„ ์ž‘์„ฑํ•˜๋ฉด์„œ ํ•„์š”ํ•œ ๋ณ€์ˆ˜๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์ฐพ์•„๋‚ด์•ผ ํ•œ๋‹ค. ์ด ๋ณ€์ˆ˜๋Š” ๋ทฐ ํ•จ์ˆ˜์—์„œ context ๋ณ€์ˆ˜๋กœ ์ •์˜ํ•ด์„œ ํ…œํ”Œ๋ฆฟ์œผ๋กœ ๋„˜๊ฒจ์ค˜์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์˜ˆ์ œ์˜ ํ…œํ”Œ๋ฆฟ์—์„œ๋Š” ์งˆ๋ฌธ์œผ๋กœ ์‚ฌ์šฉ๋  ์—ฌ๋Ÿฌ ๊ฐœ์˜ question_text๋ฅผ ํ™”๋ฉด์— ๋ณด์—ฌ์ค˜์•ผ ํ•˜๊ณ  URL ๋งํฌ๋ฅผ ์—ฐ๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด question.id๋„ ํ•„์š”ํ•˜๋‹ค. ์ด ๋‘ ๊ฐ€์ง€ ์ •๋ณด๊ฐ€ ํ•จ๊ป˜ ๋“ค์–ด์žˆ๋Š” Question ๊ฐ์ฒด๋ฅผ ๋ทฐ ํ•จ์ˆ˜๋กœ๋ถ€ํ„ฐ ๋„˜๊ฒจ๋ฐ›์œผ๋ฉด ๋œ๋‹ค. Question ๊ฐ์ฒด๋“ค์˜ ๋ฆฌ์ŠคํŠธ๊ฐ€ ๋“ค์–ด์žˆ๋Š” latest_question_list ๋ณ€์ˆ˜๋ฅผ ๋ทฐ ํ•จ์ˆ˜๋กœ๋ถ€ํ„ฐ ํ…œํ”Œ๋ฆฟ ํŒŒ์ผ๋กœ ์ „๋‹ฌํ•ด์•ผ ํ•œ๋‹ค.

from django.shortcuts import render # ๋‹จ์ถ•ํ•จ์ˆ˜ render import
from polls.models import Question

def index(request):
    # Question ํ…Œ์ด๋ธ” ๊ฐ์ฒด์—์„œ pub_date ์ปฌ๋Ÿผ์˜ ์—ญ์ˆœ์œผ๋กœ ์ •๋ ฌํ•˜์—ฌ
    # 5๊ฐœ์˜ ์ตœ๊ทผ Question ๊ฐ์ฒด๋ฅผ ๊ฐ€์ ธ์™€์„œ ๋งŒ๋“ ๋‹ค.
    latest_question_list = Question.objects.all().order_by('-pub_date')[:5]
    
    # ํ…œํ”Œ๋ฆฟ์— ์‚ฌ์šฉ๋  ๋ณ€์ˆ˜๋ช…๊ณผ ๊ทธ ๋ณ€์ˆ˜๋ช…์— ํ•ด๋‹น๋˜๋Š” ๊ฐ์ฒด๋ฅผ ๋งคํ•‘ํ•˜๋Š” ์‚ฌ์ „ ํƒ€์ž…์œผ๋กœ
    # context ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด ์ด๋ฅผ render() ํ•จ์ˆ˜์— ๋ณด๋‚ด์ค€๋‹ค.
    context = {'latest_question_list': latest_question_list}
    
    # render() ํ•จ์ˆ˜๋Š” ํ…œํ”Œ๋ฆฟ ํŒŒ์ผ์ธ polls/index.html์— context ๋ณ€์ˆ˜๋ฅผ ์ ์šฉํ•˜์—ฌ
    # ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์—ฌ์ค„ ์ตœ์ข… HTML์„ ๋งŒ๋“ค๊ณ  ์ด๋ฅผ ๋‹ด์•„ HttpResponse ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
    return render(request, 'polls/index.html', context)

๋‹จ์ถ•ํ•จ์ˆ˜๋ž€?
์›น ํ”„๋กœ๊ทธ๋žจ ๊ฐœ๋ฐœ ์‹œ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ๊ธฐ๋Šฅ๋“ค, ์˜ˆ๋ฅผ ๋“ค์–ด render() ํ•จ์ˆ˜์ฒ˜๋Ÿผ ํ…œํ”Œ๋ฆฟ ์ฝ”๋“œ๋ฅผ ๋กœ๋”ฉํ•œ ํ›„์— ์ปจํ…์ŠคํŠธ ๋ณ€์ˆ˜๋ฅผ ์ ์šฉํ•˜๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋ฅผ HTTPResponse ๊ฐ์ฒด์— ๋‹ด์•„ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ž‘์—… ๋“ฑ์˜ ๊ณตํ†ต์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๊ธฐ๋Šฅ๋“ค์„ ์žฅ๊ณ ์—์„œ๋Š” ์ด๋ฏธ ๊ฐœ๋ฐœํ•˜์—ฌ ๋‚ด์žฅ ํ•จ์ˆ˜๋กœ ์ œ๊ณตํ•˜๊ณ  ์žˆ๋Š”๋ฐ ์ด๋ฅผ ๋‹จ์ถ•ํ•จ์ˆ˜๋ผ๊ณ  ํ•œ๋‹ค.

๋ทฐ์—์„œ ์ง€์ •ํ•˜๋Š” ํ…œํ”Œ๋ฆฟ์˜ ์œ„์น˜

์žฅ๊ณ ์—์„œ ํ…œํ”Œ๋ฆฟ ํŒŒ์ผ์„ ์ฐพ์„ ๋•Œ TEMPLATES, INSTALLED_APP์—์„œ ์ง€์ •๋œ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋Š”๋ฐ ์ด ์ค‘ INSTALLED_APPS ํ•ญ๋ชฉ์˜ ๊ฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋Œ€ํ•œ ํ…œํ”Œ๋ฆฟ ํŒŒ์ผ์˜ ์œ„์น˜๋Š” ์ฃผ์˜ํ•  ๊ฒƒ์ด ์žˆ๋‹ค.

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ์ˆ˜๊ฐ€ ๋Š˜์–ด๋‚˜๊ณ  ํ…œํ”Œ๋ฆฟ ํŒŒ์ผ์ด ๋งŽ์•„์ง€๋ฉด ์ด๋ฆ„์ด ๊ฐ™์€ ๊ฒฝ์šฐ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— templates ๋””๋ ‰ํ† ๋ฆฌ ํ•˜์œ„์— ๋‹ค์‹œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ช…์œผ๋กœ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๋งŒ๋“ค์–ด ํ…œํ”Œ๋ฆฟ ํŒŒ์ผ์„ ์œ„์น˜์‹œํ‚ค๋Š” ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•œ๋‹ค.

ch3/polls/templates/polls/index.html

๋ทฐ ํ•จ์ˆ˜ detail() ๋ฐ ํผ ํ…œํ”Œ๋ฆฟ ์ž‘์„ฑ

ch3/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>
    {% endfor %}
    <input type="submit" value="Vote" />
</form>


์ฝ”๋“œ ์„ค๋ช…

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

์—๋Ÿฌ๋ฅผ ์ฒดํฌํ•˜๋Š” ๋กœ์ง์€ ๋‹ค์Œ ์ ˆ์˜ vote() ๋ทฐ ํ•จ์ˆ˜์— ์žˆ๋‹ค.
vote() ๋ทฐ ํ•จ์ˆ˜์—์„œ ์ต์…‰์…˜์ด ๋ฐœ์ƒํ•˜๋ฉด error_message๋ฅผ ๋‹ด์•„
detail.html ํ…œํ”Œ๋ฆฟ์„ ๋ Œ๋”๋งํ•˜๊ณ , ๊ทธ์— ๋”ฐ๋ผ ์ง€๊ธˆ์˜ detail.html ํ…œํ”Œ๋ฆฟ์—์„œ
์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด์—ฌ์ค€๋‹ค.

<form action="{% url 'polls:vote' question.id %}" method="post">

์„œ๋ฒ„ ์ธก์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒฝ์šฐ ์ผ๋ฐ˜์ ์œผ๋กœ POST ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•œ๋‹ค.

< form action> ์†์„ฑ์— {% url %} ํ…œํ”Œ๋ฆฟ ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ›์„ ๊ณณ์˜ URL์„ polls:vote๋กœ ์ง€์ •ํ–ˆ๋‹ค. polls:vote๋Š” URLconf์—์„œ ์ •์˜ํ•œ URL ํŒจํ„ด ์ด๋ฆ„์ด๋‹ค. ๋™์ผํ•œ ์ผ๋ฏ€์œผ๋กœ ์ธํ•œ ์ถฉ๋Œ์„ ๋ง‰๊ธฐ ์œ„ํ•ด ์ด๋ฆ„ ๊ณต๊ฐ„์„ ์ถ”๊ฐ€ํ•ด์„œ polls:vote๊ฐ€ ๋œ ๊ฒƒ์ด๋‹ค.

{% for choice in question.choice_set.all %}

for ํƒœ๊ทธ๋กœ ๋ทฐ ํ•จ์ˆ˜์—์„œ ๋„˜์–ด์˜จ ๊ฐ์ฒด๋ฅผ ์ˆœํšŒํ•œ๋‹ค. question.choice_set.all์˜ ์˜๋ฏธ๋Š” Question ๊ฐ์ฒด์˜ choice_set ์†์„ฑ์— ๋“ค์–ด์žˆ๋Š” ํ•ญ๋ชฉ ๋ชจ๋‘๋ฅผ ๋œปํ•œ๋‹ค.

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

๋ผ๋””์˜ค ๋ฒ„ํŠผ์œผ๋กœ ๋‹ต๋ณ€ ํ•ญ๋ชฉ์„ ๋ณด์—ฌ์ค€๋‹ค. ํ•ด๋‹น ๋ผ๋””์˜ค ๋ฒ„ํŠผ์„ ์„ ํƒํ•˜๋ฉด POST ๋ฐ์ดํ„ฐ๊ฐ€ 'choice'='3' ํ˜•ํƒœ๋กœ ๊ตฌ์„ฑ๋˜๋„๋ก name๊ณผ value ์†์„ฑ์„ ์ •์˜ํ•œ๋‹ค.

<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label>

forloop.counter ๋ณ€์ˆ˜๋Š” for ๋ฃจํ”„๋ฅผ ์‹คํ–‰ํ•œ ํšŸ์ˆ˜๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š” ๋ณ€์ˆ˜์ด๋‹ค. label for ์†์„ฑ๊ณผ input id ์†์„ฑ์€ ๊ฐ’์ด ๊ฐ™์•„์•ผ ์„œ๋กœ ๋ฐ”์ธ๋”ฉ๋œ๋‹ค.

<input type="submit" value="Vote" />

Vote ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์„ ํƒํ•œ ํผ ๋ฐ์ดํ„ฐ๊ฐ€ POST ๋ฐฉ์‹์œผ๋กœ polls:vote URL๋กœ ์ „์†ก๋œ๋‹ค. ์ „์†ก๋œ ๋ฐ์ดํ„ฐ๋Š” vote() ๋ทฐ ํ•จ์ˆ˜์—์„œ request.POST['choice'] ๊ตฌ๋ฌธ์œผ๋กœ ์—‘์„ธ์Šคํ•œ๋‹ค. input ํƒœ๊ทธ์˜ name๊ณผ value ์†์„ฑ๊ฐ’๋“ค์ด request.POST ์‚ฌ์ „์— key, value๋กœ ์‚ฌ์šฉ๋œ๋‹ค๋Š” ์ ์„ ์œ ์˜ํ•ด์•ผ ํ•œ๋‹ค.

Question ๊ฐ์ฒด์˜ choice_set ์†์„ฑ

Question๊ณผ Choice ํ…Œ์ด๋ธ”์˜ ๊ด€๊ณ„๋Š” 1:N ๊ด€๊ณ„์ด๊ณ , ์™ธ๋ž˜ํ‚ค๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋‹ค. ์ฆ‰, question.choice_set.all() ์ด๋ผ๊ณ  ํ•˜๋ฉด Question ํ…Œ์ด๋ธ”์˜ question ๋ ˆ์ฝ”๋“œ์— ์—ฐ๊ฒฐ๋œ Choice ํ…Œ์ด๋ธ”์˜ ๋ ˆ์ฝ”๋“œ ๋ชจ๋‘๋ฅผ ๋œปํ•œ๋‹ค.

detail.html ํŒŒ์ผ์—์„œ ํ•„์š”ํ•œ ๋ณ€์ˆ˜, ์ฆ‰ detail() ๋ทฐ ํ•จ์ˆ˜์—์„œ ์ •์˜ํ•ด์•ผ ํ•  context ๋ณ€์ˆ˜๊ฐ€ ์–ด๋–ค ๊ฒŒ ์žˆ๋Š”์ง€ ์ฐพ์•„๋ณด์ž
question.text, error_message, question.id, question.choice_set, forloop.counter, choice.id, choice.choice_text ๋“ฑ์˜ ๋ณ€์ˆ˜๋“ค์ด ์‚ฌ์šฉ๋˜๊ณ  ์žˆ๋‹ค.

forloop.counter : ์žฅ๊ณ ์—์„œ ์ œ๊ณตํ•˜๋ฏ€๋กœ ์ •์˜ํ•  ํ•„์š” ์—†๋‹ค.
error_message : vote() ํ•จ์ˆ˜์—์„œ ์ •์˜ํ•  ์˜ˆ์ •

question.text, question.id, question.choice_set : ๊ฐ๊ฐ context ๋ณ€์ˆ˜๋กœ ์ •์˜ํ•ด๋„ ๋˜์ง€๋งŒ question ๋ณ€์ˆ˜๋งŒ ์ •์˜ํ•˜๋ฉด ๊ทธ ๋ณ€์ˆ˜์˜ ์†์„ฑ์œผ๋กœ ์—‘์„ธ์Šคํ•  ์ˆ˜ ์žˆ๋‹ค.

choice.id, choice.choice_text : question.choice_set ๋ณ€์ˆ˜๊ฐ€ ์ •์˜๋˜๋ฉด ์—‘์„ธ์Šค ๊ฐ€๋Šฅํ•˜๋‹ค.

๊ฒฐ๋ก ์ ์œผ๋กœ detail() ๋ทฐ ํ•จ์ˆ˜์—์„œ ์ •์˜ํ•ด์•ผ ํ•  ๋ณ€์ˆ˜๋Š” question ๋ณ€์ˆ˜ ํ•˜๋‚˜ ๋ฟ์ด๋‹ค.

์ด๋ ‡๊ฒŒ html ํŒŒ์ผ์„ ๋จผ์ € ์ฝ”๋”ฉํ•˜๋ฉด์„œ context ๋ณ€์ˆ˜๋ฅผ ์ฐพ๋Š” ์‹์œผ๋กœ ์ˆ™์ง€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

detail() ๋ทฐ ํ•จ์ˆ˜ ์ž‘์„ฑ

index.html ํ™”๋ฉด์—์„œ ์งˆ๋ฌธ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•˜๋ฉด /polls/1/๊ณผ ๊ฐ™์€ URL์ด ๋„˜์–ด์˜ค๊ฒŒ ๋˜์–ด ์žˆ๋‹ค.

index.html์˜ ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ๋œปํ•œ๋‹ค.

        <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>

๋˜ํ•œ urls.py์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •์˜ํ–ˆ๋‹ค.

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

์œ„ ๋‘ ๋ผ์ธ์— ์˜ํ•ด ์งˆ๋ฌธ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•˜๋ฉด detail() ๋ทฐ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

์ด์ œ views.py์— deatil()์„ ์ž‘์„ฑํ•œ๋‹ค.

# ๋ทฐ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•œ๋‹ค. request ๊ฐ์ฒด๋Š” ํ•„์ˆ˜ ์ธ์ž์ด๊ณ , ์ถ”๊ฐ€์ ์œผ๋กœ question_id ์ธ์ž๋ฅผ
# ๋” ๋ฐ›๋Š”๋‹ค. URL ํŒจํ„ด์œผ๋กœ๋ถ€ํ„ฐ ์ถ”์ถœ๋œ question_id๊ฐ€ ๋ทฐ ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ๋„˜์–ด์˜จ๋‹ค.
def detail(request, question_id):
    # get_object_or_404() ๋‹จ์ถ•ํ•จ์ˆ˜
    question = get_object_or_404(Question, pk=question_id)
    
    # ํ…œํ”Œ๋ฆฟ์—๊ฒŒ ๋„˜๊ฒจ์ฃผ๋Š” ์ปจํ…์ŠคํŠธ ์‚ฌ์ „์„ render() ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ์ง์ ‘ ์จ์ฃผ๊ณ  ์žˆ๋‹ค.
    # ํ…œํ”Œ๋ฆฟ ํŒŒ์ผ์—์„œ๋Š” question์ด๋ž€ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๊ฒƒ์ด๋‹ค.
    return render(request, 'polls/detail.html', {'question':question})

get_object_or_404() : ์ด ํ•จ์ˆ˜์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋Š” ๋ชจ๋ธ ํด๋ž˜์Šค์ด๊ณ , ๋‘ ๋ฒˆ์งธ ์ธ์ž๋ถ€ํ„ฐ ๊ฒ€์ƒ‰ ์กฐ๊ฑด์„ ์—ฌ๋Ÿฌ ๊ฐœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ์˜ˆ์ œ์—์„œ๋Š” Question ๋ชจ๋ธ ํด๋ž˜์Šค๋กœ๋ถ€ํ„ฐ pk=question_id ๊ฒ€์ƒ‰ ์กฐ๊ฑด์— ๋งž๋Š” ๊ฐ์ฒด๋ฅผ ์กฐํšŒํ•œ๋‹ค. ์กฐ๊ฑด์— ๋งž๋Š” ๊ฐ์ฒด๊ฐ€ ์—†์œผ๋ฉด Http404 ์ต์…‰์…˜์„ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.

๋ทฐ ํ•จ์ˆ˜ vote() ๋ฐ ๋ฆฌ๋‹ค์ด๋ ‰์…˜ ์ž‘์„ฑ

vote() ๋ทฐ ํ•จ์ˆ˜์˜ ํ˜ธ์ถœ๊ณผ ์—ฐ๊ณ„๋œ URL์€ detail.html ํ…œํ”Œ๋ฆฟ ํŒŒ์ผ์—์„œ ๋ฐ›๋Š”๋‹ค. ์ฆ‰, detail.html ํ…œํ”Œ๋ฆฟ์— ์žˆ๋Š” ํผ์„ ์ œ์ถœํ•˜๋ฉด ํผ์˜ ๊ธฐ๋Šฅ์— ์˜ํ•ด /polls/5/vote/์™€ ๊ฐ™์€ URL์ด POST ๋ฐฉ์‹์œผ๋กœ ๋„˜์–ด์˜จ๋‹ค.

detail.html์˜ form ๋ถ€๋ถ„

<form action="{% url 'polls:vote' question.id %}" method="post">

urls.py์˜ vote ๋ถ€๋ถ„

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

์œ„ ๋‘ ๋ผ์ธ์— ์˜ํ•ด ์‚ฌ์šฉ์ž๊ฐ€ Vote ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด vote() ๋ทฐ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.

form์œผ๋กœ๋ถ€ํ„ฐ ์ˆ˜์‹ ํ•œ POST ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” vote() ๋ทฐ ํ•จ์ˆ˜๋ฅผ views.py ํŒŒ์ผ์— ์ž‘์„ฑํ•œ๋‹ค.

def vote(request, question_id):
    # Choice ํ…Œ์ด๋ธ”์„ ๊ฒ€์ƒ‰ํ•œ๋‹ค. request.POST๋Š” ์ œ์ถœ๋œ ํผ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š”
    # ๊ฐ์ฒด๋กœ์„œ key๋กœ ๊ทธ ๊ฐ’์„ ๊ตฌํ•  ์ˆ˜ ์žˆ๋‹ค.
    # request.POST['choice']๋Š” ํผ ๋ฐ์ดํ„ฐ์—์„œ ํ‚ค๊ฐ€ 'choice'์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ’์ธ
    # choice.id๋ฅผ ์ŠคํŠธ๋ง์œผ๋กœ ๋ฆฌํ„ดํ•œ๋‹ค.
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected_choice = question.choice_set.get(pk=request.POST['choice'])
    
    # 'choice'๋ผ๋Š” ํ‚ค๊ฐ€ ์—†์œผ๋ฉด KeyError ์ต์…‰์…˜ ๋ฐœ์ƒ
    # ๊ฒ€์ƒ‰ ์กฐ๊ฑด์— ๋งž๋Š” ๊ฐ์ฒด๊ฐ€ ์—†์œผ๋ฉด Choice.DoesNotExist ์ต์…‰์…˜ ๋ฐœ์ƒ
    except (KeyError, Choice.DoseNotExist):
        # ์ต์…‰์…˜์ด ๋ฐœ์ƒํ•˜๋ฉด render() ํ•จ์ˆ˜์— ์˜ํ•ด question๊ณผ error_message
        # ์ปจํ…์ŠคํŠธ ๋ณ€์ˆ˜๋ฅผ detail.html ํ…œํ”Œ๋ฆฟ์œผ๋กœ ์ „๋‹ฌ
        # ์—๋Ÿฌ ๋ฉ”์„ธ์ง€์™€ ํ•จ๊ป˜ ์งˆ๋ฌธ ํ•ญ๋ชฉ ํผ์„ ๋‹ค์‹œ ๋ณด์—ฌ์ค˜์„œ ์žฌ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•จ
        return render(request, 'polls/detail.html', {
            'question': question,
            'error_message': "You didn't select a choice",
        })
    else:
        selected_choice.votes += 1
        
        # ๋ณ€๊ฒฝ ์‚ฌํ•ญ Choice ํ…Œ์ด๋ธ” ์ €์žฅ
        selected_choice.save()
        
        # POST ๋ฐ์ดํ„ฐ๋ฅผ ์ •์ƒ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ–ˆ์œผ๋ฉด
        # ํ•ญ์ƒ HttpResponseRedirect๋ฅผ ๋ฐ˜ํ™˜ํ•˜์—ฌ ๋ฆฌ๋‹ค์ด๋ ‰์…˜ ์ฒ˜๋ฆฌ
        # ์ตœ์ข…์ ์œผ๋กœ vote() ๋ทฐ ํ•จ์ˆ˜๋Š” ๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•  ํƒ€๊ฒŸ URL์„ ๋‹ด์€
        # HttpResponseRedirect ๊ฐ์ฒด ๋ฐ˜ํ™˜
        return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))

vote() ๋ทฐ ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ์ฒด๋Š” HttpResponseRedirect ๊ฐ์ฒด์ด๋‹ค. HttpResponseRedirect ํด๋ž˜์Šค์˜ ์ƒ์„ฑ์ž๋Š” ๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•  ํƒ€๊ฒŸ URL์„ ์ธ์ž๋กœ ๋ฐ›๊ณ  ํƒ€๊ฒŸ URL์€ reverse() ํ•จ์ˆ˜๋กœ ๋งŒ๋“ ๋‹ค.

์ด์ฒ˜๋Ÿผ POST ๋ฐฉ์‹์˜ ํผ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒฝ์šฐ, ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๋Š” ํŽ˜์ด์ง€๋กœ ์ด๋™์‹œํ‚ค๊ธฐ ์œ„ํ•ด HttpResponseRedirect ๊ฐ์ฒด๋ฅผ ๋ฆฌํ„ดํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ด๋‹ค.

reverse() ํ•จ์ˆ˜

URLconf๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ URL ์ŠคํŠธ๋ง๊ณผ ๋ทฐ๋ฅผ ๋งคํ•‘ํ•œ ๊ฐ ๋ผ์ธ์„ URL ํŒจํ„ด์ด๋ผ ํ•˜๊ณ  ์ด๋ฆ„์„ ํ•˜๋‚˜์”ฉ ๋ถ€์—ฌํ•œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ทธ ๋ฐ˜๋Œ€๋กœ reverse() ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ URL ํŒจํ„ด๋ช…์œผ๋กœ๋ถ€ํ„ฐ URL ์ŠคํŠธ๋ง์„ ๊ตฌํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

reverse() ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ URL ํŒจํ„ด์˜ ์ด๋ฆ„๊ณผ URL ์ŠคํŠธ๋ง์— ์‚ฌ์šฉ๋  ํŒŒ๋ผ๋ฏธํ„ฐ, 2๊ฐœ์˜ ์ธ์ž๋ฅผ ๋ฐ›๋Š”๋‹ค.

reverse() ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ URL์„ ๊ตฌํ•˜๋Š” ๊ฒƒ์€ URLconf์— ์ด๋ฏธ ์ •์˜๋œ URL ํŒจํ„ด์„ ํ™œ์šฉํ•ด์„œ URL ์ŠคํŠธ๋ง์„ ์ถ”์ถœํ•˜๋Š” ๋ฐฉ์‹์ด๋ฏ€๋กœ, ์†Œ์Šค์— URL ์ŠคํŠธ๋ง์„ ํ•˜๋“œ์ฝ”๋”ฉํ•˜์ง€ ์•Š๋„๋ก ํ•ด์ค€๋‹ค.

๋ทฐ ํ•จ์ˆ˜ results() ๋ฐ ํ…œํ”Œ๋ฆฟ ์ž‘์„ฑ

๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•˜๋ผ๋Š” ์‘๋‹ต์„ ๋ฐ›์€ ์›น ๋ธŒ๋ผ์šฐ์ €๋Š” ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ URL๋กœ ๋‹ค์‹œ ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค.

urls.py์˜ results ๋ถ€๋ถ„

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

๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ์š”์ฒญ๊ณผ ์œ„ ๋ผ์ธ์— ์˜ํ•ด results() ๋ทฐ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.

results() ๋ทฐ ํ•จ์ˆ˜์— ํผ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๋กœ์ง์„ ์ž‘์„ฑํ•œ๋‹ค. ์ด๋ฒˆ์—” ๋ทฐ -> ํ…œํ”Œ๋ฆฟ ์ˆœ์œผ๋กœ ์ฝ”๋”ฉํ•ด๋ณธ๋‹ค.

views.py ํŒŒ์ผ์— results() ๋ทฐ ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.

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

results.html UI

results.html

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

<ul>
<!--    ๋ทฐ ํ•จ์ˆ˜์—์„œ ๋„˜์–ด์˜จ question ๋ณ€์ˆ˜๋ฅผ ์ด์šฉํ•ด Choice ๊ฐ์ฒด๋ฅผ ์ˆœํšŒ-->
    {% 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>

ํฅ๋ฏธ๋กœ์šด ์ ์€ ๋ทฐ ํ•จ์ˆ˜์™€ ํ…œํ”Œ๋ฆฟ ํƒœ๊ทธ ์–‘์ชฝ์—์„œ ๋ชจ๋‘ URL ์ŠคํŠธ๋ง์„ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋ทฐ ํ•จ์ˆ˜์—์„œ๋Š” reverse() ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ํ…œํ”Œ๋ฆฟ์—์„œ๋Š” {% url %} ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.





์ถœ์ฒ˜: Django๋กœ ๋ฐฐ์šฐ๋Š” ํŒŒ์ด์ฌ ์›น ํ”„๋กœ๊ทธ๋ž˜๋ฐ(๊ธฐ์ดˆ) - ๊น€์„ํ›ˆ๋‹˜

profile
anaooauc1236@naver.com

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