{"title":"첫 번째 장고 앱 작성하기, part 4","version":"3.2","locale":"ko","docname":"intro/tutorial04","url":"/ko/3.2/intro/tutorial04/","canonical":"https://djangodocs.dev/ko/3.2/intro/tutorial04/","summary":"This tutorial begins where Tutorial 3 left off. We’re continuing the Web-poll application and will focus on form processing and cutting down our code. 도움을 받을 수 있는…","html":"<h1>첫 번째 장고 앱 작성하기, part 4<a class=\"heading-anchor\" href=\"#writing-your-first-django-app-part-4\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>This tutorial begins where <a class=\"reference internal\" href=\"/ko/3.2/intro/tutorial03/\"><span class=\"doc\">Tutorial 3</span></a> left off. We’re\ncontinuing the Web-poll application and will focus on form processing and\ncutting down our code.</p>\n<aside class=\"admonition-where-to-get-help admonition\">\n<p class=\"admonition-title\">도움을 받을 수 있는 방법</p>\n<p>If you’re having trouble going through this tutorial, please head over to\nthe <a class=\"reference internal\" href=\"/ko/3.2/faq/help/\"><span class=\"doc\">Getting Help</span></a> section of the FAQ.</p>\n</aside>\n<section id=\"write-a-minimal-form\">\n<h2>Write a minimal form<a class=\"heading-anchor\" href=\"#write-a-minimal-form\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>앞장의 투표 상세 템플릿(“polls/detail.html”)을 수정하여, 템플릿에 HTML <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;form&gt;</span></code> 요소를 포함시켜 봅시다.</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"html+django\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">polls/templates/polls/detail.html</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Django template code\"><code><span class=\"p\">&lt;</span><span class=\"nt\">form</span> <span class=\"na\">action</span><span class=\"o\">=</span><span class=\"s\">&quot;</span><span class=\"cp\">{%</span> <span class=\"k\">url</span> <span class=\"s1\">&#39;polls:vote&#39;</span> <span class=\"nv\">question.id</span> <span class=\"cp\">%}</span><span class=\"s\">&quot;</span> <span class=\"na\">method</span><span class=\"o\">=</span><span class=\"s\">&quot;post&quot;</span><span class=\"p\">&gt;</span>\n<span class=\"cp\">{%</span> <span class=\"k\">csrf_token</span> <span class=\"cp\">%}</span>\n<span class=\"p\">&lt;</span><span class=\"nt\">fieldset</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">legend</span><span class=\"p\">&gt;&lt;</span><span class=\"nt\">h1</span><span class=\"p\">&gt;</span><span class=\"cp\">{{</span> <span class=\"nv\">question.question_text</span> <span class=\"cp\">}}</span><span class=\"p\">&lt;/</span><span class=\"nt\">h1</span><span class=\"p\">&gt;&lt;/</span><span class=\"nt\">legend</span><span class=\"p\">&gt;</span>\n    <span class=\"cp\">{%</span> <span class=\"k\">if</span> <span class=\"nv\">error_message</span> <span class=\"cp\">%}</span><span class=\"p\">&lt;</span><span class=\"nt\">p</span><span class=\"p\">&gt;&lt;</span><span class=\"nt\">strong</span><span class=\"p\">&gt;</span><span class=\"cp\">{{</span> <span class=\"nv\">error_message</span> <span class=\"cp\">}}</span><span class=\"p\">&lt;/</span><span class=\"nt\">strong</span><span class=\"p\">&gt;&lt;/</span><span class=\"nt\">p</span><span class=\"p\">&gt;</span><span class=\"cp\">{%</span> <span class=\"k\">endif</span> <span class=\"cp\">%}</span>\n    <span class=\"cp\">{%</span> <span class=\"k\">for</span> <span class=\"nv\">choice</span> <span class=\"k\">in</span> <span class=\"nv\">question.choice_set.all</span> <span class=\"cp\">%}</span>\n        <span class=\"p\">&lt;</span><span class=\"nt\">input</span> <span class=\"na\">type</span><span class=\"o\">=</span><span class=\"s\">&quot;radio&quot;</span> <span class=\"na\">name</span><span class=\"o\">=</span><span class=\"s\">&quot;choice&quot;</span> <span class=\"na\">id</span><span class=\"o\">=</span><span class=\"s\">&quot;choice</span><span class=\"cp\">{{</span> <span class=\"nb\">forloop</span><span class=\"nv\">.counter</span> <span class=\"cp\">}}</span><span class=\"s\">&quot;</span> <span class=\"na\">value</span><span class=\"o\">=</span><span class=\"s\">&quot;</span><span class=\"cp\">{{</span> <span class=\"nv\">choice.id</span> <span class=\"cp\">}}</span><span class=\"s\">&quot;</span><span class=\"p\">&gt;</span>\n        <span class=\"p\">&lt;</span><span class=\"nt\">label</span> <span class=\"na\">for</span><span class=\"o\">=</span><span class=\"s\">&quot;choice</span><span class=\"cp\">{{</span> <span class=\"nb\">forloop</span><span class=\"nv\">.counter</span> <span class=\"cp\">}}</span><span class=\"s\">&quot;</span><span class=\"p\">&gt;</span><span class=\"cp\">{{</span> <span class=\"nv\">choice.choice_text</span> <span class=\"cp\">}}</span><span class=\"p\">&lt;/</span><span class=\"nt\">label</span><span class=\"p\">&gt;&lt;</span><span class=\"nt\">br</span><span class=\"p\">&gt;</span>\n    <span class=\"cp\">{%</span> <span class=\"k\">endfor</span> <span class=\"cp\">%}</span>\n<span class=\"p\">&lt;/</span><span class=\"nt\">fieldset</span><span class=\"p\">&gt;</span>\n<span class=\"p\">&lt;</span><span class=\"nt\">input</span> <span class=\"na\">type</span><span class=\"o\">=</span><span class=\"s\">&quot;submit&quot;</span> <span class=\"na\">value</span><span class=\"o\">=</span><span class=\"s\">&quot;Vote&quot;</span><span class=\"p\">&gt;</span>\n<span class=\"p\">&lt;/</span><span class=\"nt\">form</span><span class=\"p\">&gt;</span>\n</code></pre></figure>\n<p>간략하게 설명하면:</p>\n<ul class=\"simple\">\n<li><p>위의 템플릿은 각 질문 선택 항목에 대한 라디오 버튼을 표시합니다. 각 라디오 버튼의 <code class=\"docutils literal notranslate\"><span class=\"pre\">value</span></code>는 연관된 질문 선택 항목의 ID입니다. 각 라디오 버튼의 <code class=\"docutils literal notranslate\"><span class=\"pre\">name</span></code>은  <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;choice&quot;</span></code>입니다. 즉, 누군가가 라디오 버튼 중 하나를 선택하여 폼을 제출하면, POST 데이터 인 <code class=\"docutils literal notranslate\"><span class=\"pre\">choice=#</span></code>을 보낼 것입니다. 여기서 #은 선택한 항목의 ID입니다. 이것은 HTML 폼의 기본 개념입니다.</p></li>\n<li><p>We set the form’s <code class=\"docutils literal notranslate\"><span class=\"pre\">action</span></code> to <code class=\"docutils literal notranslate\"><span class=\"pre\">{%</span> <span class=\"pre\">url</span> <span class=\"pre\">'polls:vote'</span> <span class=\"pre\">question.id</span> <span class=\"pre\">%}</span></code>, and we\nset <code class=\"docutils literal notranslate\"><span class=\"pre\">method=&quot;post&quot;</span></code>. Using <code class=\"docutils literal notranslate\"><span class=\"pre\">method=&quot;post&quot;</span></code> (as opposed to\n<code class=\"docutils literal notranslate\"><span class=\"pre\">method=&quot;get&quot;</span></code>) is very important, because the act of submitting this\nform will alter data server-side. Whenever you create a form that alters\ndata server-side, use <code class=\"docutils literal notranslate\"><span class=\"pre\">method=&quot;post&quot;</span></code>. This tip isn’t specific to\nDjango; it’s good Web development practice in general.</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">forloop.counter</span></code> 는 <a class=\"reference internal\" href=\"/ko/3.2/ref/templates/builtins/#std-templatetag-for\"><code class=\"xref std std-ttag docutils literal notranslate\"><span class=\"pre\">for</span></code></a> 태그가 반복을 한 횟수를 나타냅니다.</p></li>\n<li><p>Since we’re creating a POST form (which can have the effect of modifying\ndata), we need to worry about Cross Site Request Forgeries.\nThankfully, you don’t have to worry too hard, because Django comes with a\nhelpful system for protecting against it. In short, all POST forms that are\ntargeted at internal URLs should use the <a class=\"reference internal\" href=\"/ko/3.2/ref/templates/builtins/#std-templatetag-csrf_token\"><code class=\"xref std std-ttag docutils literal notranslate\"><span class=\"pre\">{%</span> <span class=\"pre\">csrf_token</span> <span class=\"pre\">%}</span></code></a>\ntemplate tag.</p></li>\n</ul>\n<p>이제 제출된 데이터를 처리하고 그 데이터로 무언가를 수행하는 Django 뷰를 작성하겠습니다. <a class=\"reference internal\" href=\"/ko/3.2/intro/tutorial03/\"><span class=\"doc\">튜토리얼 3</span></a> 에서 설문조사 어플리케이션을 위해 아래에 나와있는 코드를 포함하는 URLconf 를 만들었습니다:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">polls/urls.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"n\">path</span><span class=\"p\">(</span><span class=\"s1\">&#39;&lt;int:question_id&gt;/vote/&#39;</span><span class=\"p\">,</span> <span class=\"n\">views</span><span class=\"o\">.</span><span class=\"n\">vote</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s1\">&#39;vote&#39;</span><span class=\"p\">),</span>\n</code></pre></figure>\n<p>또, 우리는 <code class=\"docutils literal notranslate\"><span class=\"pre\">vote()</span></code> 함수를 가상으로 만들었습니다. 실제로 구현을 해봅시다. <code class=\"docutils literal notranslate\"><span class=\"pre\">polls/views.py</span></code> 에 다음을 추가합시다:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">polls/views.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.http</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">HttpResponse</span><span class=\"p\">,</span> <span class=\"n\">HttpResponseRedirect</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.shortcuts</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">get_object_or_404</span><span class=\"p\">,</span> <span class=\"n\">render</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.urls</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">reverse</span>\n\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Choice</span><span class=\"p\">,</span> <span class=\"n\">Question</span>\n<span class=\"c1\"># ...</span>\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">vote</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">question_id</span><span class=\"p\">):</span>\n    <span class=\"n\">question</span> <span class=\"o\">=</span> <span class=\"n\">get_object_or_404</span><span class=\"p\">(</span><span class=\"n\">Question</span><span class=\"p\">,</span> <span class=\"n\">pk</span><span class=\"o\">=</span><span class=\"n\">question_id</span><span class=\"p\">)</span>\n    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">selected_choice</span> <span class=\"o\">=</span> <span class=\"n\">question</span><span class=\"o\">.</span><span class=\"n\">choice_set</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">pk</span><span class=\"o\">=</span><span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">POST</span><span class=\"p\">[</span><span class=\"s1\">&#39;choice&#39;</span><span class=\"p\">])</span>\n    <span class=\"k\">except</span> <span class=\"p\">(</span><span class=\"ne\">KeyError</span><span class=\"p\">,</span> <span class=\"n\">Choice</span><span class=\"o\">.</span><span class=\"n\">DoesNotExist</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Redisplay the question voting form.</span>\n        <span class=\"k\">return</span> <span class=\"n\">render</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"s1\">&#39;polls/detail.html&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;question&#39;</span><span class=\"p\">:</span> <span class=\"n\">question</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;error_message&#39;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;You didn&#39;t select a choice.&quot;</span><span class=\"p\">,</span>\n        <span class=\"p\">})</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">selected_choice</span><span class=\"o\">.</span><span class=\"n\">votes</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>\n        <span class=\"n\">selected_choice</span><span class=\"o\">.</span><span class=\"n\">save</span><span class=\"p\">()</span>\n        <span class=\"c1\"># Always return an HttpResponseRedirect after successfully dealing</span>\n        <span class=\"c1\"># with POST data. This prevents data from being posted twice if a</span>\n        <span class=\"c1\"># user hits the Back button.</span>\n        <span class=\"k\">return</span> <span class=\"n\">HttpResponseRedirect</span><span class=\"p\">(</span><span class=\"n\">reverse</span><span class=\"p\">(</span><span class=\"s1\">&#39;polls:results&#39;</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"n\">question</span><span class=\"o\">.</span><span class=\"n\">id</span><span class=\"p\">,)))</span>\n</code></pre></figure>\n<p>위 코드는 이 튜토리얼에서 아직 다루지 않은 몇 가지를 포함하고 있습니다:</p>\n<ul>\n<li><p><a class=\"reference internal\" href=\"/ko/3.2/ref/request-response/#django.http.HttpRequest.POST\" title=\"django.http.HttpRequest.POST\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">request.POST</span></code></a> 는 키로 전송된 자료에 접근할 수 있도록 해주는 사전과 같은 객체입니다. 이 경우, <code class=\"docutils literal notranslate\"><span class=\"pre\">request.POST['choice']</span></code> 는 선택된 설문의 ID를 문자열로 반환합니다. <a class=\"reference internal\" href=\"/ko/3.2/ref/request-response/#django.http.HttpRequest.POST\" title=\"django.http.HttpRequest.POST\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">request.POST</span></code></a> 의 값은 항상 문자열들입니다.</p>\n<p>Django는 같은 방법으로 GET 자료에 접근하기 위해 <a class=\"reference internal\" href=\"/ko/3.2/ref/request-response/#django.http.HttpRequest.GET\" title=\"django.http.HttpRequest.GET\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">request.GET</span></code></a> 를 제공합니다 – 그러나 POST 요청을 통해서만 자료가 수정되게하기 위해서, 명시적으로 코드에 <a class=\"reference internal\" href=\"/ko/3.2/ref/request-response/#django.http.HttpRequest.POST\" title=\"django.http.HttpRequest.POST\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">request.POST</span></code></a> 를 사용하고 있습니다.</p>\n</li>\n<li><p>만약 POST 자료에 <code class=\"docutils literal notranslate\"><span class=\"pre\">choice</span></code> 가 없으면, <code class=\"docutils literal notranslate\"><span class=\"pre\">request.POST['choice']</span></code> 는 <a class=\"reference external\" href=\"https://docs.python.org/3/library/exceptions.html#KeyError\" title=\"(Python v3.14에서)\"><code class=\"xref py py-exc docutils literal notranslate\"><span class=\"pre\">KeyError</span></code></a> 가 일어납니다. 위의 코드는 <a class=\"reference external\" href=\"https://docs.python.org/3/library/exceptions.html#KeyError\" title=\"(Python v3.14에서)\"><code class=\"xref py py-exc docutils literal notranslate\"><span class=\"pre\">KeyError</span></code></a> 를 체크하고, choice가 주어지지 않은 경우에는 에러 메시지와 함께 설문조사 폼을 다시보여줍니다.</p></li>\n<li><p>설문지의 수가 증가한 이후에, 코드는 일반 <a class=\"reference internal\" href=\"/ko/3.2/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponse</span></code></a> 가 아닌 <a class=\"reference internal\" href=\"/ko/3.2/ref/request-response/#django.http.HttpResponseRedirect\" title=\"django.http.HttpResponseRedirect\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponseRedirect</span></code></a> 를 반환하고, <a class=\"reference internal\" href=\"/ko/3.2/ref/request-response/#django.http.HttpResponseRedirect\" title=\"django.http.HttpResponseRedirect\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponseRedirect</span></code></a> 는 하나의 인수를 받습니다: 그 인수는 사용자가 재전송될 URL 입니다. (이 경우에 우리가 URL을 어떻게 구성하는지 다음 항목을 보세요).</p>\n<p>As the Python comment above points out, you should always return an\n<a class=\"reference internal\" href=\"/ko/3.2/ref/request-response/#django.http.HttpResponseRedirect\" title=\"django.http.HttpResponseRedirect\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponseRedirect</span></code></a> after successfully dealing with\nPOST data. This tip isn’t specific to Django; it’s good Web development\npractice in general.</p>\n</li>\n<li><p>우리는 이 예제에서 <a class=\"reference internal\" href=\"/ko/3.2/ref/request-response/#django.http.HttpResponseRedirect\" title=\"django.http.HttpResponseRedirect\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponseRedirect</span></code></a> 생성자 안에서 <a class=\"reference internal\" href=\"/ko/3.2/ref/urlresolvers/#django.urls.reverse\" title=\"django.urls.reverse\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">reverse()</span></code></a> 함수를 사용하고 있습니다. 이 함수는 뷰 함수에서 URL을 하드코딩하지 않도록 도와줍니다. 제어를 전달하기 원하는 뷰의 이름을, URL패턴의 변수부분을 조합해서 해당 뷰를 가리킵니다. 여기서 우리는 <a class=\"reference internal\" href=\"/ko/3.2/intro/tutorial03/\"><span class=\"doc\">튜토리얼 3장</span></a>에서 설정했던 URLconf를 사용하였으며, 이 <a class=\"reference internal\" href=\"/ko/3.2/ref/urlresolvers/#django.urls.reverse\" title=\"django.urls.reverse\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">reverse()</span></code></a> 호출은 아래와 같은 문자열을 반환할 것입니다.</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"s1\">&#39;/polls/3/results/&#39;</span>\n</code></pre></div>\n<p>여기서 <code class=\"docutils literal notranslate\"><span class=\"pre\">3</span></code> 은 <code class=\"docutils literal notranslate\"><span class=\"pre\">question.id</span></code> 값입니다. 이렇게 리디렉션된 URL은 최종 페이지를 표시하기 위해 <code class=\"docutils literal notranslate\"><span class=\"pre\">'results'</span></code> 뷰를 호출합니다.</p>\n</li>\n</ul>\n<p><a class=\"reference internal\" href=\"/ko/3.2/intro/tutorial03/\"><span class=\"doc\">튜토리얼 3장</span></a>에서 언급했듯이, <code class=\"docutils literal notranslate\"><span class=\"pre\">request</span></code> 는 <a class=\"reference internal\" href=\"/ko/3.2/ref/request-response/#django.http.HttpRequest\" title=\"django.http.HttpRequest\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpRequest</span></code></a> 개체입니다. <a class=\"reference internal\" href=\"/ko/3.2/ref/request-response/#django.http.HttpRequest\" title=\"django.http.HttpRequest\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpRequest</span></code></a> 개체에 대해 더 알고 싶다면  <a class=\"reference internal\" href=\"/ko/3.2/ref/request-response/\"><span class=\"doc\">request와 response 문서</span></a>를 참고하세요.</p>\n<p>어떤 이가 설문조사에 설문을 하고난 뒤에는, <code class=\"docutils literal notranslate\"><span class=\"pre\">vote()</span></code> 뷰는 설문조사 결과 페이지로 리다이렉트합니다. 그 뷰를 작성해봅시다:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">polls/views.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.shortcuts</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">get_object_or_404</span><span class=\"p\">,</span> <span class=\"n\">render</span>\n\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">results</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">question_id</span><span class=\"p\">):</span>\n    <span class=\"n\">question</span> <span class=\"o\">=</span> <span class=\"n\">get_object_or_404</span><span class=\"p\">(</span><span class=\"n\">Question</span><span class=\"p\">,</span> <span class=\"n\">pk</span><span class=\"o\">=</span><span class=\"n\">question_id</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">render</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"s1\">&#39;polls/results.html&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;question&#39;</span><span class=\"p\">:</span> <span class=\"n\">question</span><span class=\"p\">})</span>\n</code></pre></figure>\n<p><a class=\"reference internal\" href=\"/ko/3.2/intro/tutorial03/\"><span class=\"doc\">튜토리얼 3장</span></a>의 <code class=\"docutils literal notranslate\"><span class=\"pre\">detail()</span></code> 뷰와 거의 동일합니다. 템플릿 이름만 다릅니다. 나중에 이 중복을 수정할 겁니다.</p>\n<p>이제, <code class=\"docutils literal notranslate\"><span class=\"pre\">polls/results.html</span></code> 템플릿을 만듭니다.</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"html+django\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">polls/templates/polls/results.html</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Django template code\"><code><span class=\"p\">&lt;</span><span class=\"nt\">h1</span><span class=\"p\">&gt;</span><span class=\"cp\">{{</span> <span class=\"nv\">question.question_text</span> <span class=\"cp\">}}</span><span class=\"p\">&lt;/</span><span class=\"nt\">h1</span><span class=\"p\">&gt;</span>\n\n<span class=\"p\">&lt;</span><span class=\"nt\">ul</span><span class=\"p\">&gt;</span>\n<span class=\"cp\">{%</span> <span class=\"k\">for</span> <span class=\"nv\">choice</span> <span class=\"k\">in</span> <span class=\"nv\">question.choice_set.all</span> <span class=\"cp\">%}</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">li</span><span class=\"p\">&gt;</span><span class=\"cp\">{{</span> <span class=\"nv\">choice.choice_text</span> <span class=\"cp\">}}</span> -- <span class=\"cp\">{{</span> <span class=\"nv\">choice.votes</span> <span class=\"cp\">}}</span> vote<span class=\"cp\">{{</span> <span class=\"nv\">choice.votes</span><span class=\"o\">|</span><span class=\"nf\">pluralize</span> <span class=\"cp\">}}</span><span class=\"p\">&lt;/</span><span class=\"nt\">li</span><span class=\"p\">&gt;</span>\n<span class=\"cp\">{%</span> <span class=\"k\">endfor</span> <span class=\"cp\">%}</span>\n<span class=\"p\">&lt;/</span><span class=\"nt\">ul</span><span class=\"p\">&gt;</span>\n\n<span class=\"p\">&lt;</span><span class=\"nt\">a</span> <span class=\"na\">href</span><span class=\"o\">=</span><span class=\"s\">&quot;</span><span class=\"cp\">{%</span> <span class=\"k\">url</span> <span class=\"s1\">&#39;polls:detail&#39;</span> <span class=\"nv\">question.id</span> <span class=\"cp\">%}</span><span class=\"s\">&quot;</span><span class=\"p\">&gt;</span>Vote again?<span class=\"p\">&lt;/</span><span class=\"nt\">a</span><span class=\"p\">&gt;</span>\n</code></pre></figure>\n<p>이제, 웹 브라우저에서 <code class=\"docutils literal notranslate\"><span class=\"pre\">/polls/1/</span></code> 페이지로 가서, 투표를 해보세요. 당신이 투표를 할 때마다 값이 반영된 결과 페이지를 볼 수 있을 것입니다. 만약 당신이 설문지를 선택하지 않고 폼을 전송했다면, 오류 메시지를 보게 될 것입니다.</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">참고</p>\n<p>우리의 <code class=\"docutils literal notranslate\"><span class=\"pre\">vote()</span></code> 뷰에는 작은 문제가 있습니다. 먼저 데이터베이스에서 <code class=\"docutils literal notranslate\"><span class=\"pre\">selected_choice</span></code> 객체를 가져온 다음, <code class=\"docutils literal notranslate\"><span class=\"pre\">votes</span></code> 의 새 값을 계산하고 나서,  데이터베이스에 다시 저장합니다. 만약 여러분의 웹사이트에 두 명의 사용자가 <em>정확하게 같은 시간</em> 에 투표를 할려고 시도할 경우, 잘못될 수 있습니다.  <code class=\"docutils literal notranslate\"><span class=\"pre\">votes</span></code> 의 조회값이 42라고 할 경우, 두 명의 사용자에게 새로운 값인 43이 계산 되고, 저장됩니다. 그러나 44가 되야되겠죠.</p>\n<p>이를 <em>경쟁 상태</em> 라 합니다. 이 문제를 해결할 수 있는 방법을 알아보려면 <a class=\"reference internal\" href=\"/ko/3.2/ref/models/expressions/#avoiding-race-conditions-using-f\"><span class=\"std std-ref\">Avoiding race conditions using F()</span></a> 를 참고하세요.</p>\n</aside>\n</section>\n<section id=\"use-generic-views-less-code-is-better\">\n<h2>제너릭 뷰 사용하기: 적은 코드가 더 좋습니다.<a class=\"heading-anchor\" href=\"#use-generic-views-less-code-is-better\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>The <code class=\"docutils literal notranslate\"><span class=\"pre\">detail()</span></code> (from <a class=\"reference internal\" href=\"/ko/3.2/intro/tutorial03/\"><span class=\"doc\">Tutorial 3</span></a>) and <code class=\"docutils literal notranslate\"><span class=\"pre\">results()</span></code>\nviews are very short – and, as mentioned above, redundant. The <code class=\"docutils literal notranslate\"><span class=\"pre\">index()</span></code>\nview, which displays a list of polls, is similar.</p>\n<p>이러한 뷰는 URL에서 전달 된 매개 변수에 따라 데이터베이스에서 데이터를 가져 오는 것과 템플릿을 로드하고 렌더링 된 템플릿을 리턴하는 기본 웹 개발의 일반적인 경우를 나타냅니다. Django는 이런 매우 일반적인 경우를 위해 “제너릭 뷰”시스템이라는 지름길을 제공합니다.</p>\n<p>제너릭 뷰는 일반적인 패턴을 추상화하여 앱을 작성하기 위해 Python 코드를 작성하지 않아도됩니다.</p>\n<p>Let’s convert our poll app to use the generic views system, so we can delete a\nbunch of our own code. We’ll have to take a few steps to make the conversion.\nWe will:</p>\n<ol class=\"arabic simple\">\n<li><p>URLconf를 변환하십시오.</p></li>\n<li><p>불필요한 오래된보기 중 일부를 삭제하십시오.</p></li>\n<li><p>Django의 제너릭 뷰를 기반으로 새로운 뷰를 도입하십시오.</p></li>\n</ol>\n<p>자세한 내용은 계속 읽어 나가십시오.</p>\n<aside class=\"admonition-why-the-code-shuffle admonition\">\n<p class=\"admonition-title\">왜 코드 셔플인가?</p>\n<p>일반적으로 Django 앱을 작성할 때 일반 뷰가 문제에 적합한 지 여부를 평가할 것이며 코드를 중간에서 다시 리팩토링하지 않고 처음부터 사용하게됩니다. 그러나 이 튜토리얼은 의도적으로 현재까지 핵심 개념에 초점을 맞추기 위해 “어려운 방법”으로 뷰를 작성하는 데 중점을 두었습니다.</p>\n<p>계산기를 사용하기 전에 기본 수학을 알아야합니다.</p>\n</aside>\n<section id=\"amend-urlconf\">\n<h3>URLconf 수정<a class=\"heading-anchor\" href=\"#amend-urlconf\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>먼저, <code class=\"docutils literal notranslate\"><span class=\"pre\">polls/urls.py</span></code> URLconf를 열어 다음과 같이 변경하십시오:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">polls/urls.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.urls</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">path</span>\n\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">.</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">views</span>\n\n<span class=\"n\">app_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;polls&#39;</span>\n<span class=\"n\">urlpatterns</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"n\">path</span><span class=\"p\">(</span><span class=\"s1\">&#39;&#39;</span><span class=\"p\">,</span> <span class=\"n\">views</span><span class=\"o\">.</span><span class=\"n\">IndexView</span><span class=\"o\">.</span><span class=\"n\">as_view</span><span class=\"p\">(),</span> <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s1\">&#39;index&#39;</span><span class=\"p\">),</span>\n    <span class=\"n\">path</span><span class=\"p\">(</span><span class=\"s1\">&#39;&lt;int:pk&gt;/&#39;</span><span class=\"p\">,</span> <span class=\"n\">views</span><span class=\"o\">.</span><span class=\"n\">DetailView</span><span class=\"o\">.</span><span class=\"n\">as_view</span><span class=\"p\">(),</span> <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s1\">&#39;detail&#39;</span><span class=\"p\">),</span>\n    <span class=\"n\">path</span><span class=\"p\">(</span><span class=\"s1\">&#39;&lt;int:pk&gt;/results/&#39;</span><span class=\"p\">,</span> <span class=\"n\">views</span><span class=\"o\">.</span><span class=\"n\">ResultsView</span><span class=\"o\">.</span><span class=\"n\">as_view</span><span class=\"p\">(),</span> <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s1\">&#39;results&#39;</span><span class=\"p\">),</span>\n    <span class=\"n\">path</span><span class=\"p\">(</span><span class=\"s1\">&#39;&lt;int:question_id&gt;/vote/&#39;</span><span class=\"p\">,</span> <span class=\"n\">views</span><span class=\"o\">.</span><span class=\"n\">vote</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s1\">&#39;vote&#39;</span><span class=\"p\">),</span>\n<span class=\"p\">]</span>\n</code></pre></figure>\n<p>두 번째와 세 번째 패턴의 경로 문자열에서 일치하는 패턴들의 이름이 <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;question_id&gt;</span></code> 에서 <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;pk&gt;</span></code> 로 변경되었습니다.</p>\n</section>\n<section id=\"amend-views\">\n<h3>views 수정<a class=\"heading-anchor\" href=\"#amend-views\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>다음으로 이전의 <code class=\"docutils literal notranslate\"><span class=\"pre\">index</span></code>, <code class=\"docutils literal notranslate\"><span class=\"pre\">detail</span></code>, <code class=\"docutils literal notranslate\"><span class=\"pre\">results</span></code>뷰를 제거하고 장고의 일반적인 뷰를 대신 사용하겠습니다. 그렇게하려면 <code class=\"docutils literal notranslate\"><span class=\"pre\">polls/views.py</span></code> 파일을 열고 다음과 같이 변경하십시오:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">polls/views.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.http</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">HttpResponseRedirect</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.shortcuts</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">get_object_or_404</span><span class=\"p\">,</span> <span class=\"n\">render</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.urls</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">reverse</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.views</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">generic</span>\n\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Choice</span><span class=\"p\">,</span> <span class=\"n\">Question</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">IndexView</span><span class=\"p\">(</span><span class=\"n\">generic</span><span class=\"o\">.</span><span class=\"n\">ListView</span><span class=\"p\">):</span>\n    <span class=\"n\">template_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;polls/index.html&#39;</span>\n    <span class=\"n\">context_object_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;latest_question_list&#39;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">get_queryset</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;Return the last five published questions.&quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"n\">Question</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">order_by</span><span class=\"p\">(</span><span class=\"s1\">&#39;-pub_date&#39;</span><span class=\"p\">)[:</span><span class=\"mi\">5</span><span class=\"p\">]</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">DetailView</span><span class=\"p\">(</span><span class=\"n\">generic</span><span class=\"o\">.</span><span class=\"n\">DetailView</span><span class=\"p\">):</span>\n    <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">Question</span>\n    <span class=\"n\">template_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;polls/detail.html&#39;</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">ResultsView</span><span class=\"p\">(</span><span class=\"n\">generic</span><span class=\"o\">.</span><span class=\"n\">DetailView</span><span class=\"p\">):</span>\n    <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">Question</span>\n    <span class=\"n\">template_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;polls/results.html&#39;</span>\n\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">vote</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">question_id</span><span class=\"p\">):</span>\n    <span class=\"o\">...</span> <span class=\"c1\"># same as above, no changes needed.</span>\n</code></pre></figure>\n<p><a class=\"reference internal\" href=\"/ko/3.2/ref/class-based-views/generic-display/#django.views.generic.list.ListView\" title=\"django.views.generic.list.ListView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ListView</span></code></a>와 <a class=\"reference internal\" href=\"/ko/3.2/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView\" title=\"django.views.generic.detail.DetailView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">DetailView</span></code></a>의 두 가지 제너릭 뷰를 사용하고 있습니다. 이 두보기는 각각 “개체 목록 표시” 및 “특정 개체 유형에 대한 세부 정보 페이지 표시” 개념을 추상화합니다.</p>\n<ul class=\"simple\">\n<li><p>각 제너릭 뷰는 어떤 모델이 적용될 것인지를 알아야합니다. 이것은 <code class=\"docutils literal notranslate\"><span class=\"pre\">model</span></code> 속성을 사용하여 제공됩니다.</p></li>\n<li><p><a class=\"reference internal\" href=\"/ko/3.2/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView\" title=\"django.views.generic.detail.DetailView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">DetailView</span></code></a> 제너릭 뷰는 URL에서 캡처된 기본 키 값이 <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;pk&quot;</span></code>라고 기대하기 때문에 <code class=\"docutils literal notranslate\"><span class=\"pre\">question_id</span></code>를 제너릭 뷰를 위해 <code class=\"docutils literal notranslate\"><span class=\"pre\">pk</span></code>로 변경합니다.</p></li>\n</ul>\n<p>기본적으로 <a class=\"reference internal\" href=\"/ko/3.2/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView\" title=\"django.views.generic.detail.DetailView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">DetailView</span></code></a> 제너릭 뷰는 <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;app</span> <span class=\"pre\">name&gt;/&lt;model</span> <span class=\"pre\">name&gt;_detail.html</span></code> 템플릿을 사용합니다. 우리의 경우에는 <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;polls/question_detail.html&quot;</span></code>템플릿을 사용할 것입니다. <code class=\"docutils literal notranslate\"><span class=\"pre\">template_name</span></code> 속성은 Django에게 자동 생성 된 기본 템플릿 이름 대신에 특정 템플릿 이름을 사용하도록 알려주기 위해 사용됩니다. <code class=\"docutils literal notranslate\"><span class=\"pre\">results</span></code>리스트 뷰에 대해서 <code class=\"docutils literal notranslate\"><span class=\"pre\">template_name</span></code>을 지정합니다 - 결과 뷰와 상세 뷰가 렌더링 될 때 서로 다른 모습을 갖도록합니다. 이들이 둘다 동일한 <a class=\"reference internal\" href=\"/ko/3.2/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView\" title=\"django.views.generic.detail.DetailView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">DetailView</span></code></a>를 사용하고 있더라도 말이지요.</p>\n<p>마찬가지로, <a class=\"reference internal\" href=\"/ko/3.2/ref/class-based-views/generic-display/#django.views.generic.list.ListView\" title=\"django.views.generic.list.ListView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ListView</span></code></a> 제네릭 뷰는 <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;app</span> <span class=\"pre\">name&gt;/&lt;model</span> <span class=\"pre\">name&gt;_list.html</span></code> 템플릿을 기본으로 사용합니다; 이미 있는 <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;polls/index.html&quot;</span></code> 템플릿을 사용하기 위해 <a class=\"reference internal\" href=\"/ko/3.2/ref/class-based-views/generic-display/#django.views.generic.list.ListView\" title=\"django.views.generic.list.ListView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ListView</span></code></a> 에 <code class=\"docutils literal notranslate\"><span class=\"pre\">template_name</span></code> 를 전달했습니다.</p>\n<p>In previous parts of the tutorial, the templates have been provided\nwith a context that contains the <code class=\"docutils literal notranslate\"><span class=\"pre\">question</span></code> and <code class=\"docutils literal notranslate\"><span class=\"pre\">latest_question_list</span></code>\ncontext variables. For <code class=\"docutils literal notranslate\"><span class=\"pre\">DetailView</span></code> the <code class=\"docutils literal notranslate\"><span class=\"pre\">question</span></code> variable is provided\nautomatically – since we’re using a Django model (<code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code>), Django\nis able to determine an appropriate name for the context variable.\nHowever, for ListView, the automatically generated context variable is\n<code class=\"docutils literal notranslate\"><span class=\"pre\">question_list</span></code>. To override this we provide the <code class=\"docutils literal notranslate\"><span class=\"pre\">context_object_name</span></code>\nattribute, specifying that we want to use <code class=\"docutils literal notranslate\"><span class=\"pre\">latest_question_list</span></code> instead.\nAs an alternative approach, you could change your templates to match\nthe new default context variables – but it’s a lot easier to tell Django to\nuse the variable you want.</p>\n<p>서버를 실행하고 제너릭 뷰를 기반으로한 새 설문조사 앱을 사용하십시오.</p>\n<p>제너릭 뷰에 대한 자세한 내용은 <a class=\"reference internal\" href=\"/ko/3.2/topics/class-based-views/\"><span class=\"doc\">제너릭 뷰 문서</span></a>를 참조하십시오.</p>\n<p>폼 및 제너릭 뷰가 마음에 들면, 이 설문조사 앱의 테스트에 대해 <a class=\"reference internal\" href=\"/ko/3.2/intro/tutorial05/\"><span class=\"doc\">튜토리얼의 5장</span></a>을 읽어 배워 보기 바랍니다.</p>\n</section>\n</section>","rootId":"writing-your-first-django-app-part-4","toc":[{"title":"Write a minimal form","anchor":"write-a-minimal-form","children":[]},{"title":"제너릭 뷰 사용하기: 적은 코드가 더 좋습니다.","anchor":"use-generic-views-less-code-is-better","children":[{"title":"URLconf 수정","anchor":"amend-urlconf","children":[]},{"title":"views 수정","anchor":"amend-views","children":[]}]}],"breadcrumbs":[{"docname":"intro/index","title":"시작하기","url":"/ko/3.2/intro/"}],"prev":{"docname":"intro/tutorial03","title":"첫 번째 장고 앱 작성하기, part 3","url":"/ko/3.2/intro/tutorial03/"},"next":{"docname":"intro/tutorial05","title":"첫 번째 장고 앱 작성하기, part 5","url":"/ko/3.2/intro/tutorial05/"},"formats":{"html":"/ko/3.2/intro/tutorial04/","markdown":"/ko/3.2/intro/tutorial04.md","json":"/ko/3.2/intro/tutorial04.json"},"source":"https://github.com/django/django/blob/stable/3.2.x/docs/intro/tutorial04.txt","official":"https://docs.djangoproject.com/ko/3.2/intro/tutorial04/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0","1.11"],"inLocales":["en","zh-hans","fr","ja","id","it","pt-br","ko","es","el","pl"]}