{"title":"첫 번째 장고 앱 작성하기, part 4","version":"2.0","locale":"ko","docname":"intro/tutorial04","url":"/ko/2.0/intro/tutorial04/","canonical":"https://djangodocs.dev/ko/2.0/intro/tutorial04/","summary":"이 튜토리얼은 Tutorial 3 에서 이어집니다. 웹-설문조사 어플리케이션을 다루고 있고, 간단한 폼 처리와 소스코드를 줄여가는데 중점을 둘것입니다. 간단한 폼 만들기 Link to this heading # Let’s update our poll detail template…","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>이 튜토리얼은 <a class=\"reference internal\" href=\"/ko/2.0/intro/tutorial03/\"><span class=\"doc\">Tutorial 3</span></a> 에서 이어집니다. 웹-설문조사 어플리케이션을 다루고 있고, 간단한 폼 처리와 소스코드를 줄여가는데 중점을 둘것입니다.</p>\n<section id=\"write-a-simple-form\">\n<h2>간단한 폼 만들기<a class=\"heading-anchor\" href=\"#write-a-simple-form\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Let’s update our poll detail template (“polls/detail.html”) from the last\ntutorial, so that the template contains an HTML <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;form&gt;</span></code> element:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"html+django\"><figcaption class=\"code-block-caption\"><code>polls/templates/polls/detail.html</code></figcaption><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=\"polls/templates/polls/detail.html\"><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=\"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\n<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=\"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\">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>폼의 <code class=\"docutils literal notranslate\"><span class=\"pre\">action</span></code>을 <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>로 설정하고, <code class=\"docutils literal notranslate\"><span class=\"pre\">method=&quot;post&quot;</span></code> 로 설정하였습니다. 이 폼을 전송하는 행위는 서버측 자료를 변경할 것이므로, <code class=\"docutils literal notranslate\"><span class=\"pre\">method=&quot;post&quot;</span></code> (<code class=\"docutils literal notranslate\"><span class=\"pre\">method=&quot;get&quot;</span></code> 와 반대로) 를 사용하는 것은 매우 중요합니다. 서버 측 자료를 변경하는 폼을 작성할 때마다, <code class=\"docutils literal notranslate\"><span class=\"pre\">method=&quot;post&quot;</span></code> 를 사용하세요. 이 팁은 Django에만 국한되지 않습니다. 이것은 웹개발시의 권장사항 입니다.</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">forloop.counter</span></code> 는 <a class=\"reference internal\" href=\"/ko/2.0/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>우리는 POST 폼(자료를 수정하는 효과를 가진)을 만들고 있으므로, 사이트 간 요청 위조 (Cross Site Request Forgeries)에 대해 고민해야합니다. 고맙게도, Django는 사이트 간 요청 위조(CSRF)에 대항하기위한 사용하기 쉬운 시스템을 가지고 있기 때문에, 너무 심각하게 고민할 필요가 없습니다. 간단히 말하면, 내부 URL들을 향하는 모든 POST 폼에 템플릿 태그 <a class=\"reference internal\" href=\"/ko/2.0/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>를 사용하면됩니다.</p></li>\n</ul>\n<p>이제 제출된 데이터를 처리하고 그 데이터로 무언가를 수행하는 Django 뷰를 작성하겠습니다. <a class=\"reference internal\" href=\"/ko/2.0/intro/tutorial03/\"><span class=\"doc\">튜토리얼 3</span></a> 에서 설문조사 어플리케이션을 위해 아래에 나와있는 코드를 포함하는 URLconf 를 만들었습니다:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"default\"><figcaption class=\"code-block-caption\"><code>polls/urls.py</code></figcaption><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=\"polls/urls.py\"><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=\"default\"><figcaption class=\"code-block-caption\"><code>polls/views.py</code></figcaption><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=\"polls/views.py\"><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/2.0/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/2.0/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/2.0/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/2.0/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/2.0/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/2.0/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/2.0/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>위의 파이썬 주석이 지적했듯이, POST 데이터를 성공적으로 처리 한 후에는 항상 <a class=\"reference internal\" href=\"/ko/2.0/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> 를 반환해야합니다. 이 팁은 Django에만 국한되는것이 아닌 웹개발의 권장사항입니다.</p>\n</li>\n<li><p>우리는 이 예제에서 <a class=\"reference internal\" href=\"/ko/2.0/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/2.0/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/2.0/intro/tutorial03/\"><span class=\"doc\">튜토리얼 3</span></a> 에서 설정했던 URLconf를 사용하였으며, 이 <a class=\"reference internal\" href=\"/ko/2.0/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/2.0/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/2.0/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/2.0/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/2.0/ref/request-response/\"><span class=\"doc\">request and response documentation</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=\"default\"><figcaption class=\"code-block-caption\"><code>polls/views.py</code></figcaption><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=\"polls/views.py\"><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/2.0/intro/tutorial03/\"><span class=\"doc\">Tutorial 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>polls/templates/polls/results.html</code></figcaption><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=\"polls/templates/polls/results.html\"><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/2.0/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><code class=\"docutils literal notranslate\"><span class=\"pre\">detail()</span></code> (<a class=\"reference internal\" href=\"/ko/2.0/intro/tutorial03/\"><span class=\"doc\">Tutorial 3</span></a>에서 만든)과 <code class=\"docutils literal notranslate\"><span class=\"pre\">results()</span></code> 뷰는 매우 간단합니다. – 그리고 위에서 말한것처럼 중복됩니다. polls 리스트를 보여주는 <code class=\"docutils literal notranslate\"><span class=\"pre\">index()</span></code> 뷰와도 비슷합니다.</p>\n<p>이러한 뷰는 URL에서 전달 된 매개 변수에 따라 데이터베이스에서 데이터를 가져 오는 것과 템플릿을 로드하고 렌더링 된 템플릿을 리턴하는 기본 웹 개발의 일반적인 경우를 나타냅니다. Django는 이런 매우 일반적인 경우를 위해 “제너릭 뷰”시스템이라는 지름길을 제공합니다.</p>\n<p>제너릭 뷰는 일반적인 패턴을 추상화하여 앱을 작성하기 위해 Python 코드를 작성하지 않아도됩니다.</p>\n<p>우리의 설문조사 애플리케이션을 제너릭 뷰 시스템을 사용하도록 변환하여 우리의 코드를 삭제할 수 있도록 합시다. 이러한 전환을 하려면 그저 다음과 같은 몇 단계 만 거치면 됩니다:</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=\"default\"><figcaption class=\"code-block-caption\"><code>polls/urls.py</code></figcaption><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=\"polls/urls.py\"><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>조회수 수정<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=\"default\"><figcaption class=\"code-block-caption\"><code>polls/views.py</code></figcaption><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=\"polls/views.py\"><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/2.0/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/2.0/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/2.0/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에서 캡쳐 된 기본 키 값이``”pk”<code class=\"docutils literal notranslate\"><span class=\"pre\">\\</span> <span class=\"pre\">라고</span> <span class=\"pre\">기대하기</span> <span class=\"pre\">때문에</span> <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/2.0/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/2.0/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/2.0/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/2.0/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>이 튜토리얼의 이전 부분에서 템플릿에는 <code class=\"docutils literal notranslate\"><span class=\"pre\">question</span></code> 및 <code class=\"docutils literal notranslate\"><span class=\"pre\">latest_question_list</span></code> 컨텍스트 변수가 포함 된 컨텍스트가 제공되었습니다. <code class=\"docutils literal notranslate\"><span class=\"pre\">DetailView</span></code>의 경우, <code class=\"docutils literal notranslate\"><span class=\"pre\">question</span></code> 변수가 자동으로 제공됩니다 - Django 모델 (<code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code>)을 사용하기 때문에 Django는 컨텍스트 변수의 적절한 이름을 결정할 수 있습니다. 그러나 ListView의 경우 자동 생성 된 컨텍스트 변수는 <code class=\"docutils literal notranslate\"><span class=\"pre\">question_list</span></code> 입니다. 이것을 덮어 쓰려면 <code class=\"docutils literal notranslate\"><span class=\"pre\">context_object_name</span></code> 속성을 제공하고, 대신에 <code class=\"docutils literal notranslate\"><span class=\"pre\">latest_question_list</span></code>를 사용하도록 지정하십시오. 다른 접근 방법으로, 템플릿을 새로운 기본 컨텍스트 변수와 일치하도록 변경할 수 있습니다. 그러나 원하는 변수를 사용하도록 Django에 지시하는 것이 훨씬 쉽습니다.</p>\n<p>서버를 실행하고 제너릭 뷰를 기반으로한 새 설문조사 앱을 사용하십시오.</p>\n<p>제너릭 뷰에 대한 자세한 내용은 <a class=\"reference internal\" href=\"/ko/2.0/topics/class-based-views/\"><span class=\"doc\">제너릭 뷰 문서</span></a>를 참조하십시오.</p>\n<p>폼 및 제너릭 뷰가 마음에 들면, 이 설문조사 앱의 테스트에 대해 <a class=\"reference internal\" href=\"/ko/2.0/intro/tutorial05/\"><span class=\"doc\">튜토리얼의 5장</span></a>을 읽어 배워 보기 바랍니다.</p>\n</section>\n</section>","rootId":"writing-your-first-django-app-part-4","toc":[{"title":"간단한 폼 만들기","anchor":"write-a-simple-form","children":[]},{"title":"제너릭 뷰 사용하기: 적은 코드가 더 좋습니다.","anchor":"use-generic-views-less-code-is-better","children":[{"title":"URLconf 수정","anchor":"amend-urlconf","children":[]},{"title":"조회수 수정","anchor":"amend-views","children":[]}]}],"breadcrumbs":[{"docname":"intro/index","title":"시작하기","url":"/ko/2.0/intro/"}],"prev":{"docname":"intro/tutorial03","title":"첫 번째 장고 앱 작성하기, part 3","url":"/ko/2.0/intro/tutorial03/"},"next":{"docname":"intro/tutorial05","title":"첫 번째 장고 앱 작성하기, part 5","url":"/ko/2.0/intro/tutorial05/"},"formats":{"html":"/ko/2.0/intro/tutorial04/","markdown":"/ko/2.0/intro/tutorial04.md","json":"/ko/2.0/intro/tutorial04.json"},"source":"https://github.com/django/django/blob/stable/2.0.x/docs/intro/tutorial04.txt","official":"https://docs.djangoproject.com/ko/2.0/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","pt-br","ko","es","el","pl"]}