{"title":"첫 번째 장고 앱 작성하기, part 3","version":"3.1","locale":"ko","docname":"intro/tutorial03","url":"/ko/3.1/intro/tutorial03/","canonical":"https://djangodocs.dev/ko/3.1/intro/tutorial03/","summary":"이 튜토리얼은 튜토리얼 2장 에서 이어집니다. 이제 투표 어플리케이션에 공개 인터페이스인 “뷰(view)”를 추가해 보겠습니다.","html":"<h1>첫 번째 장고 앱 작성하기, part 3<a class=\"heading-anchor\" href=\"#writing-your-first-django-app-part-3\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>이 튜토리얼은 <a class=\"reference internal\" href=\"/ko/3.1/intro/tutorial02/\"><span class=\"doc\">튜토리얼 2장</span></a> 에서 이어집니다. 이제 투표 어플리케이션에 공개 인터페이스인 “뷰(view)”를 추가해 보겠습니다.</p>\n<aside class=\"admonition-where-to-get-help admonition\" role=\"note\">\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.1/faq/help/\"><span class=\"doc\">Getting Help</span></a> section of the FAQ.</p>\n</aside>\n<section id=\"overview\">\n<h2>개요<a class=\"heading-anchor\" href=\"#overview\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>뷰는 Django 어플리케이션이 일반적으로 특정 기능과 템플릿을 제공하는 웹페이지의 한 종류입니다. 예를 들어, 블로그 어플리케이션의 경우 다음과 같은 뷰를 가질 수 있습니다.</p>\n<ul class=\"simple\">\n<li><p>Blog 홈페이지 – 가장 최근의 항목들을 보여줍니다</p></li>\n<li><p>항목 “세부”(detail) 페이지 – 하나의 항목에 연결하는 영구적인 링크(permalink)를 제공합니다.</p></li>\n<li><p>년도별 축적 페이지 – 주어진 연도의 모든 월별 항목들을 표시합니다.</p></li>\n<li><p>월별 축적 페이지 – 주어진 월의 날짜별 항목들을 표시합니다.</p></li>\n<li><p>날짜별 축적 페이지 – 주어진 날짜의 모든 항목들을 표시합니다.</p></li>\n<li><p>댓글 기능 – 특정 항목의 댓글을 다룰 수 있는 기능</p></li>\n</ul>\n<p>우리가 만드는 poll 어플리케이션에서 다음과 같은 네개의 view 를 만들어 보겠습니다.</p>\n<ul class=\"simple\">\n<li><p>질문 “색인” 페이지 – 최근의 질문들을 표시합니다.</p></li>\n<li><p>질문 “세부” 페이지 – 질문 내용과, 투표할 수 있는 서식을 표시합니다.</p></li>\n<li><p>질문 “결과” 페이지 – 특정 질문에 대한 결과를 표시합니다</p></li>\n<li><p>투표 기능 – 특정 질문에 대해 특정 선택을 할 수 있는 투표 기능을 제공합니다.</p></li>\n</ul>\n<p>In Django, web pages and other content are delivered by views. Each view is\nrepresented by a Python function (or method, in the case of class-based views).\nDjango will choose a view by examining the URL that’s requested (to be precise,\nthe part of the URL after the domain name).</p>\n<p>Now in your time on the web you may have come across such beauties as\n<code class=\"docutils literal notranslate\">ME2/Sites/dirmod.htm?sid=&amp;type=gen&amp;mod=Core+Pages&amp;gid=A6CD4967199A42D9B65B1B</code>.\nYou will be pleased to know that Django allows us much more elegant\n<em>URL patterns</em> than that.</p>\n<p>A URL pattern is the general form of a URL - for example:\n<code class=\"docutils literal notranslate\">/newsarchive/&lt;year&gt;/&lt;month&gt;/</code>.</p>\n<p>URL로부터 뷰를 얻기 위해, Django는 ‘URLconfs’라는 것을 사용합니다. URLconf는 URL 패턴을 뷰에 연결합니다.</p>\n<p>이 튜토리얼은 URLconfs를 사용하는 기초 지식을 제공하며, 좀 더 자세한 정보는 <a class=\"reference internal\" href=\"/ko/3.1/topics/http/urls/\"><span class=\"doc\">URL dispatcher</span></a>를 참조하세요.</p>\n</section>\n<section id=\"writing-more-views\">\n<h2>뷰 추가하기<a class=\"heading-anchor\" href=\"#writing-more-views\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>이제, <code class=\"docutils literal notranslate\">polls/views.py</code> 에 뷰를 추가해 봅시다. 이 뷰들은 인수를 받기 때문에 조금 모양이 다릅니다.</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/views.py</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=\"k\">def</span> <span class=\"nf\">detail</span><span class=\"p\">(</span>request<span class=\"p\">,</span> question_id<span class=\"p\">):</span>\n    <span class=\"k\">return</span> HttpResponse<span class=\"p\">(</span><span class=\"s2\">&quot;You&#39;re looking at question </span><span class=\"si\">%s</span><span class=\"s2\">.&quot;</span> <span class=\"o\">%</span> question_id<span class=\"p\">)</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">results</span><span class=\"p\">(</span>request<span class=\"p\">,</span> question_id<span class=\"p\">):</span>\n    response <span class=\"o\">=</span> <span class=\"s2\">&quot;You&#39;re looking at the results of question </span><span class=\"si\">%s</span><span class=\"s2\">.&quot;</span>\n    <span class=\"k\">return</span> HttpResponse<span class=\"p\">(</span>response <span class=\"o\">%</span> question_id<span class=\"p\">)</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">vote</span><span class=\"p\">(</span>request<span class=\"p\">,</span> question_id<span class=\"p\">):</span>\n    <span class=\"k\">return</span> HttpResponse<span class=\"p\">(</span><span class=\"s2\">&quot;You&#39;re voting on question </span><span class=\"si\">%s</span><span class=\"s2\">.&quot;</span> <span class=\"o\">%</span> question_id<span class=\"p\">)</span>\n</code></pre></figure>\n<p>다음의 <a class=\"reference internal\" href=\"/ko/3.1/ref/urls/#django.urls.path\" title=\"django.urls.path\"><code class=\"xref py py-func docutils literal notranslate\">path()</code></a> 호출을 추가하여 이러한 새로운 뷰를 <code class=\"docutils literal notranslate\">polls.urls</code> 모듈로 연결하세요.</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/urls.py</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=\"nn\">django.urls</span> <span class=\"kn\">import</span> path\n\n<span class=\"kn\">from</span> <span class=\"nn\">.</span> <span class=\"kn\">import</span> views\n\nurlpatterns <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"c1\"># ex: /polls/</span>\n    path<span class=\"p\">(</span><span class=\"s1\">&#39;&#39;</span><span class=\"p\">,</span> views<span class=\"o\">.</span>index<span class=\"p\">,</span> name<span class=\"o\">=</span><span class=\"s1\">&#39;index&#39;</span><span class=\"p\">),</span>\n    <span class=\"c1\"># ex: /polls/5/</span>\n    path<span class=\"p\">(</span><span class=\"s1\">&#39;&lt;int:question_id&gt;/&#39;</span><span class=\"p\">,</span> views<span class=\"o\">.</span>detail<span class=\"p\">,</span> name<span class=\"o\">=</span><span class=\"s1\">&#39;detail&#39;</span><span class=\"p\">),</span>\n    <span class=\"c1\"># ex: /polls/5/results/</span>\n    path<span class=\"p\">(</span><span class=\"s1\">&#39;&lt;int:question_id&gt;/results/&#39;</span><span class=\"p\">,</span> views<span class=\"o\">.</span>results<span class=\"p\">,</span> name<span class=\"o\">=</span><span class=\"s1\">&#39;results&#39;</span><span class=\"p\">),</span>\n    <span class=\"c1\"># ex: /polls/5/vote/</span>\n    path<span class=\"p\">(</span><span class=\"s1\">&#39;&lt;int:question_id&gt;/vote/&#39;</span><span class=\"p\">,</span> views<span class=\"o\">.</span>vote<span class=\"p\">,</span> name<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>브라우저에 “/polls/34/” 를 입력해 보세요. 이 주소에 접속하면 <code class=\"docutils literal notranslate\">detail()</code> 함수를 호출하여 URL 에 입력한 ID 를 출력할 것입니다. “/polls/34/results/” 와 “/polls/34/vote/” 도 실행해 보세요. 투표 결과와 투표 페이지의 뼈대가 되는 페이지가 출력될 것입니다.</p>\n<p>사용자가 웹사이트의 페이지를 요청할 때, 예로 “/polls/34/”를 요청했다고 하면, Django는 <code class=\"docutils literal notranslate\">mysite.urls</code> 파이썬 모듈을 불러오게 됩니다. <a class=\"reference internal\" href=\"/ko/3.1/ref/settings/#std-setting-ROOT_URLCONF\"><code class=\"xref std std-setting docutils literal notranslate\">ROOT_URLCONF</code></a> 설정에 의해 해당 모듈을 바라보도록 지정되어 있기 때문입니다. <code class=\"docutils literal notranslate\">mysite.urls</code>에서 <code class=\"docutils literal notranslate\">urlpatterns</code>라는 변수를 찾고, 순서대로 패턴을 따라갑니다. <code class=\"docutils literal notranslate\">'polls/'</code>를 찾은 후엔, 일치하는 텍스트(<code class=\"docutils literal notranslate\">&quot;polls/&quot;</code>)를 버리고, 남은 텍스트인 <code class=\"docutils literal notranslate\">&quot;34/&quot;</code>를 ‘polls.urls’ URLconf로 전달하여 남은 처리를 진행합니다. 거기에 <code class=\"docutils literal notranslate\">'&lt;int:question_id&gt;/'</code>와 일치하여, 결과적으로 <code class=\"docutils literal notranslate\">detail()</code> 뷰 함수가 호출됩니다.</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>detail<span class=\"p\">(</span>request<span class=\"o\">=&lt;</span>HttpRequest <span class=\"nb\">object</span><span class=\"o\">&gt;</span><span class=\"p\">,</span> question_id<span class=\"o\">=</span><span class=\"mi\">34</span><span class=\"p\">)</span>\n</code></pre></div>\n<p><code class=\"docutils literal notranslate\">question_id=34</code> 부분은 <code class=\"docutils literal notranslate\">&lt;int:question_id&gt;</code> 에서 왔습니다. 괄호를 사용하여 URL 의 일부를 “캡처”하고, 해당 내용을 keyword 인수로서 뷰 함수로 전달합니다. 문자열의 <code class=\"docutils literal notranslate\">:question_id&gt;</code> 부분은 일치되는 패턴을 구별하기 위해 정의한 이름이며, <code class=\"docutils literal notranslate\">&lt;int:</code> 부분은 어느 패턴이 해당 URL 경로에 일치되어야 하는 지를 결정하는 컨버터입니다.</p>\n</section>\n<section id=\"write-views-that-actually-do-something\">\n<h2>뷰가 실제로 뭔가를 하도록 만들기<a class=\"heading-anchor\" href=\"#write-views-that-actually-do-something\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>각 뷰는 두 가지 중 하나를 하도록 되어 있습니다. 요청된 페이지의 내용이 담긴 <a class=\"reference internal\" href=\"/ko/3.1/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\">HttpResponse</code></a> 객체를 반환하거나, 혹은 <a class=\"reference internal\" href=\"/ko/3.1/topics/http/views/#django.http.Http404\" title=\"django.http.Http404\"><code class=\"xref py py-exc docutils literal notranslate\">Http404</code></a> 같은 예외를 발생하게 해야합니다. 나머지는 당신에게 달렸습니다.</p>\n<p>당신이 작성한 뷰는 데이터베이스의 레코드를 읽을 수도 있습니다. 또한 뷰는 Django나 Python에서 서드파티로 제공되는 템플릿 시스템을 사용할 수도 있습니다. 뷰는 PDF를 생성하거나, XML을 출력하거나, 실시간으로 ZIP 파일을 만들 수 있습니다. 뷰는 당신이 원하는 무엇이든, Python의 어떤 라이브러리라도 사용할 수 있습니다.</p>\n<p>Django에 필요한 것은 <a class=\"reference internal\" href=\"/ko/3.1/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\">HttpResponse</code></a> 객체 혹은 예외입니다.</p>\n<p>왜냐면, 그렇게 다루는게 편리하기 때문입니다. <a class=\"reference internal\" href=\"/ko/3.1/intro/tutorial02/\"><span class=\"doc\">튜토리얼 2장</span></a>의 예제에서 다룬 Django 자체 데이터베이스 API를 사용해봅시다. 새로운 <code class=\"docutils literal notranslate\">index()</code> 뷰 하나를 호출했을 때, 시스템에 저장된 최소한 5 개의 투표 질문이 콤마로 분리되어, 발행일에 따라 출력됩니다.</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/views.py</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=\"nn\">django.http</span> <span class=\"kn\">import</span> HttpResponse\n\n<span class=\"kn\">from</span> <span class=\"nn\">.models</span> <span class=\"kn\">import</span> Question\n\n\n<span class=\"k\">def</span> <span class=\"nf\">index</span><span class=\"p\">(</span>request<span class=\"p\">):</span>\n    latest_question_list <span class=\"o\">=</span> Question<span class=\"o\">.</span>objects<span class=\"o\">.</span>order_by<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    output <span class=\"o\">=</span> <span class=\"s1\">&#39;, &#39;</span><span class=\"o\">.</span>join<span class=\"p\">([</span>q<span class=\"o\">.</span>question_text <span class=\"k\">for</span> q <span class=\"ow\">in</span> latest_question_list<span class=\"p\">])</span>\n    <span class=\"k\">return</span> HttpResponse<span class=\"p\">(</span>output<span class=\"p\">)</span>\n\n<span class=\"c1\"># Leave the rest of the views (detail, results, vote) unchanged</span>\n</code></pre></figure>\n<p>여기 몇가지 문제가 있습니다. 뷰에서 페이지의 디자인이 하드코딩 되어 있다고 합시다. 만약 페이지가 보여지는 방식을 바꾸고 싶다면, 이 Python 코드를 편집해야만 할 겁니다. 그럼, 뷰에서 사용할 수 있는 템플릿을 작성하여, Python 코드로부터 디자인을 분리하도록 Django의 템플릿 시스템을 사용해 봅시다.</p>\n<p>우선, <code class=\"docutils literal notranslate\">polls</code> 디렉토리에 <code class=\"docutils literal notranslate\">templates</code>라는 디렉토리를 만듭니다. Django는 여기서 템플릿을 찾게 될 것입니다.</p>\n<p>프로젝트의 <a class=\"reference internal\" href=\"/ko/3.1/ref/settings/#std-setting-TEMPLATES\"><code class=\"xref std std-setting docutils literal notranslate\">TEMPLATES</code></a> 설정은 Django가 어떻게 템플릿을 불러오고 렌더링 할 것인지 기술합니다. 기본 설정 파일은 <a class=\"reference internal\" href=\"/ko/3.1/ref/settings/#std-setting-TEMPLATES-APP_DIRS\"><code class=\"xref std std-setting docutils literal notranslate\">APP_DIRS</code></a> 옵션이 <code class=\"docutils literal notranslate\">True</code>로 설정된 <code class=\"docutils literal notranslate\">DjangoTemplates</code> 백엔드를 구성합니다. 관례에 따라, <code class=\"docutils literal notranslate\">DjangoTemplates</code>은 각 <a class=\"reference internal\" href=\"/ko/3.1/ref/settings/#std-setting-INSTALLED_APPS\"><code class=\"xref std std-setting docutils literal notranslate\">INSTALLED_APPS</code></a> 디렉토리의 “templates” 하위 디렉토리를 탐색합니다.</p>\n<p>Within the <code class=\"docutils literal notranslate\">templates</code> directory you have just created, create another\ndirectory called <code class=\"docutils literal notranslate\">polls</code>, and within that create a file called\n<code class=\"docutils literal notranslate\">index.html</code>. In other words, your template should be at\n<code class=\"docutils literal notranslate\">polls/templates/polls/index.html</code>. Because of how the <code class=\"docutils literal notranslate\">app_directories</code>\ntemplate loader works as described above, you can refer to this template within\nDjango as <code class=\"docutils literal notranslate\">polls/index.html</code>.</p>\n<aside class=\"admonition-template-namespacing admonition\" role=\"note\">\n<p class=\"admonition-title\">템플릿 네임스페이싱</p>\n<p>Now we <em>might</em> be able to get away with putting our templates directly in\n<code class=\"docutils literal notranslate\">polls/templates</code> (rather than creating another <code class=\"docutils literal notranslate\">polls</code> subdirectory),\nbut it would actually be a bad idea. Django will choose the first template\nit finds whose name matches, and if you had a template with the same name\nin a <em>different</em> application, Django would be unable to distinguish between\nthem. We need to be able to point Django at the right one, and the best\nway to ensure this is by <em>namespacing</em> them. That is, by putting those\ntemplates inside <em>another</em> directory named for the application itself.</p>\n</aside>\n<p>템플릿에 다음과 같은 코드를 입력합니다.</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"html+django\"><figcaption class=\"code-block-caption\">polls/templates/polls/index.html</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=\"cp\">{%</span> <span class=\"k\">if</span> <span class=\"nv\">latest_question_list</span> <span class=\"cp\">%}</span>\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\">question</span> <span class=\"k\">in</span> <span class=\"nv\">latest_question_list</span> <span class=\"cp\">%}</span>\n        <span class=\"p\">&lt;</span><span class=\"nt\">li</span><span class=\"p\">&gt;&lt;</span><span class=\"nt\">a</span> <span class=\"na\">href</span><span class=\"o\">=</span><span class=\"s\">&quot;/polls/</span><span class=\"cp\">{{</span> <span class=\"nv\">question.id</span> <span class=\"cp\">}}</span><span class=\"s\">/&quot;</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\">a</span><span class=\"p\">&gt;&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<span class=\"cp\">{%</span> <span class=\"k\">else</span> <span class=\"cp\">%}</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">p</span><span class=\"p\">&gt;</span>No polls are available.<span class=\"p\">&lt;/</span><span class=\"nt\">p</span><span class=\"p\">&gt;</span>\n<span class=\"cp\">{%</span> <span class=\"k\">endif</span> <span class=\"cp\">%}</span>\n</code></pre></figure>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">참고</p>\n<p>To make the tutorial shorter, all template examples use incomplete HTML. In\nyour own projects you should use <a class=\"reference external\" href=\"https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started#Anatomy_of_an_HTML_document\">complete HTML documents</a>.</p>\n</aside>\n<p>이제, 템플릿을 이용하여 <code class=\"docutils literal notranslate\">polls/views.py</code>에 <code class=\"docutils literal notranslate\">index</code> 뷰를 업데이트 해보도록 하겠습니다.</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/views.py</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=\"nn\">django.http</span> <span class=\"kn\">import</span> HttpResponse\n<span class=\"kn\">from</span> <span class=\"nn\">django.template</span> <span class=\"kn\">import</span> loader\n\n<span class=\"kn\">from</span> <span class=\"nn\">.models</span> <span class=\"kn\">import</span> Question\n\n\n<span class=\"k\">def</span> <span class=\"nf\">index</span><span class=\"p\">(</span>request<span class=\"p\">):</span>\n    latest_question_list <span class=\"o\">=</span> Question<span class=\"o\">.</span>objects<span class=\"o\">.</span>order_by<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    template <span class=\"o\">=</span> loader<span class=\"o\">.</span>get_template<span class=\"p\">(</span><span class=\"s1\">&#39;polls/index.html&#39;</span><span class=\"p\">)</span>\n    context <span class=\"o\">=</span> <span class=\"p\">{</span>\n        <span class=\"s1\">&#39;latest_question_list&#39;</span><span class=\"p\">:</span> latest_question_list<span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n    <span class=\"k\">return</span> HttpResponse<span class=\"p\">(</span>template<span class=\"o\">.</span>render<span class=\"p\">(</span>context<span class=\"p\">,</span> request<span class=\"p\">))</span>\n</code></pre></figure>\n<p>이 코드는 <code class=\"docutils literal notranslate\">polls/index.html</code> 템플릿을 불러온 후, context를 전달합니다. context는 템플릿에서 쓰이는 변수명과 Python 객체를 연결하는 사전형 값입니다.</p>\n<p>브라우저에서 “/polls/” 페이지를 불러오면, <a class=\"reference internal\" href=\"/ko/3.1/intro/tutorial02/\"><span class=\"doc\">튜토리얼 2장</span></a>에서 작성한 “What’s up” 질문이 포함된 리스트가 표시됩니다. 표시된 질문의 링크는 해당 질문에 대한 세부 페이지를 가리킵니다.</p>\n<section id=\"a-shortcut-render\">\n<h3>지름길: <a class=\"reference internal\" href=\"/ko/3.1/topics/http/shortcuts/#django.shortcuts.render\" title=\"django.shortcuts.render\"><code class=\"xref py py-func docutils literal notranslate\">render()</code></a><a class=\"heading-anchor\" href=\"#a-shortcut-render\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>템플릿에 context 를 채워넣어 표현한 결과를 <a class=\"reference internal\" href=\"/ko/3.1/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\">HttpResponse</code></a> 객체와 함께 돌려주는 구문은 자주 쓰는 용법입니다. 따라서 Django는 이런 표현을 쉽게 표현할 수 있도록 단축 기능(shortcuts)을 제공합니다. <code class=\"docutils literal notranslate\">index()</code> 뷰를 단축 기능으로 작성하면 다음과 같습니다.</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/views.py</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=\"nn\">django.shortcuts</span> <span class=\"kn\">import</span> render\n\n<span class=\"kn\">from</span> <span class=\"nn\">.models</span> <span class=\"kn\">import</span> Question\n\n\n<span class=\"k\">def</span> <span class=\"nf\">index</span><span class=\"p\">(</span>request<span class=\"p\">):</span>\n    latest_question_list <span class=\"o\">=</span> Question<span class=\"o\">.</span>objects<span class=\"o\">.</span>order_by<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    context <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s1\">&#39;latest_question_list&#39;</span><span class=\"p\">:</span> latest_question_list<span class=\"p\">}</span>\n    <span class=\"k\">return</span> render<span class=\"p\">(</span>request<span class=\"p\">,</span> <span class=\"s1\">&#39;polls/index.html&#39;</span><span class=\"p\">,</span> context<span class=\"p\">)</span>\n</code></pre></figure>\n<p>모든 뷰에 적용한다면, 더 이상 <a class=\"reference internal\" href=\"/ko/3.1/topics/templates/#module-django.template.loader\" title=\"django.template.loader\"><code class=\"xref py py-mod docutils literal notranslate\">loader</code></a>와 <a class=\"reference internal\" href=\"/ko/3.1/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\">HttpResponse</code></a>를 임포트하지 않아도 됩니다. (만약 <code class=\"docutils literal notranslate\">detail</code>, <code class=\"docutils literal notranslate\">results</code>, <code class=\"docutils literal notranslate\">vote</code>에서 stub 메소드를 가지고 있다면, <code class=\"docutils literal notranslate\">HttpResponse</code>를 유지해야 할 것입니다.)</p>\n<p><a class=\"reference internal\" href=\"/ko/3.1/topics/http/shortcuts/#django.shortcuts.render\" title=\"django.shortcuts.render\"><code class=\"xref py py-func docutils literal notranslate\">render()</code></a> 함수는 request 객체를 첫번째 인수로 받고, 템플릿 이름을 두번째 인수로 받으며, context 사전형 객체를 세전째 선택적(optional) 인수로 받습니다. 인수로 지정된 context로 표현된 템플릿의 <a class=\"reference internal\" href=\"/ko/3.1/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\">HttpResponse</code></a> 객체가 반환됩니다.</p>\n</section>\n</section>\n<section id=\"raising-a-404-error\">\n<h2>404 에러 일으키기<a class=\"heading-anchor\" href=\"#raising-a-404-error\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>이제, 질문의 상세 뷰에 태클을 걸어보겠습니다. 상세 뷰는 지정된 설문조사의 질문 내용을 보여줍니다. 다음과 같습니다.</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/views.py</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=\"nn\">django.http</span> <span class=\"kn\">import</span> Http404\n<span class=\"kn\">from</span> <span class=\"nn\">django.shortcuts</span> <span class=\"kn\">import</span> render\n\n<span class=\"kn\">from</span> <span class=\"nn\">.models</span> <span class=\"kn\">import</span> Question\n<span class=\"c1\"># ...</span>\n<span class=\"k\">def</span> <span class=\"nf\">detail</span><span class=\"p\">(</span>request<span class=\"p\">,</span> question_id<span class=\"p\">):</span>\n    <span class=\"k\">try</span><span class=\"p\">:</span>\n        question <span class=\"o\">=</span> Question<span class=\"o\">.</span>objects<span class=\"o\">.</span>get<span class=\"p\">(</span>pk<span class=\"o\">=</span>question_id<span class=\"p\">)</span>\n    <span class=\"k\">except</span> Question<span class=\"o\">.</span>DoesNotExist<span class=\"p\">:</span>\n        <span class=\"k\">raise</span> Http404<span class=\"p\">(</span><span class=\"s2\">&quot;Question does not exist&quot;</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> render<span class=\"p\">(</span>request<span class=\"p\">,</span> <span class=\"s1\">&#39;polls/detail.html&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;question&#39;</span><span class=\"p\">:</span> question<span class=\"p\">})</span>\n</code></pre></figure>\n<p>여기 새로운 내용이 추가되었습니다. 뷰는 요청된 질문의 ID 가 없을 경우 <a class=\"reference internal\" href=\"/ko/3.1/topics/http/views/#django.http.Http404\" title=\"django.http.Http404\"><code class=\"xref py py-exc docutils literal notranslate\">Http404</code></a> 예외를 발생시킵니다.</p>\n<p>조금 후에 <code class=\"docutils literal notranslate\">polls/detail.html</code> 템플릿에 무엇을 넣을 수 있는지 논의하겠지만, 일단 위의 예제를 동작시키기 위해 아래의 내용이 들어있는 파일을 작성하세요.</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"html+django\"><figcaption class=\"code-block-caption\">polls/templates/polls/detail.html</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=\"cp\">{{</span> <span class=\"nv\">question</span> <span class=\"cp\">}}</span>\n</code></pre></figure>\n<p>이제 시작해도 됩니다.</p>\n<section id=\"a-shortcut-get-object-or-404\">\n<h3>지름길: <a class=\"reference internal\" href=\"/ko/3.1/topics/http/shortcuts/#django.shortcuts.get_object_or_404\" title=\"django.shortcuts.get_object_or_404\"><code class=\"xref py py-func docutils literal notranslate\">get_object_or_404()</code></a><a class=\"heading-anchor\" href=\"#a-shortcut-get-object-or-404\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>만약 객체가 존재하지 않을 때 <a class=\"reference internal\" href=\"/ko/3.1/ref/models/querysets/#django.db.models.query.QuerySet.get\" title=\"django.db.models.query.QuerySet.get\"><code class=\"xref py py-meth docutils literal notranslate\">get()</code></a> 을 사용하여 <a class=\"reference internal\" href=\"/ko/3.1/topics/http/views/#django.http.Http404\" title=\"django.http.Http404\"><code class=\"xref py py-exc docutils literal notranslate\">Http404</code></a> 예외를 발생시키는것은 자주 쓰이는 용법입니다. Django에서 이 기능에 대한 단축 기능을 제공합니다. <code class=\"docutils literal notranslate\">detail()</code> 뷰를 단축 기능으로 작성하면 다음과 같습니다.</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/views.py</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=\"nn\">django.shortcuts</span> <span class=\"kn\">import</span> get_object_or_404<span class=\"p\">,</span> render\n\n<span class=\"kn\">from</span> <span class=\"nn\">.models</span> <span class=\"kn\">import</span> Question\n<span class=\"c1\"># ...</span>\n<span class=\"k\">def</span> <span class=\"nf\">detail</span><span class=\"p\">(</span>request<span class=\"p\">,</span> question_id<span class=\"p\">):</span>\n    question <span class=\"o\">=</span> get_object_or_404<span class=\"p\">(</span>Question<span class=\"p\">,</span> pk<span class=\"o\">=</span>question_id<span class=\"p\">)</span>\n    <span class=\"k\">return</span> render<span class=\"p\">(</span>request<span class=\"p\">,</span> <span class=\"s1\">&#39;polls/detail.html&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;question&#39;</span><span class=\"p\">:</span> question<span class=\"p\">})</span>\n</code></pre></figure>\n<p><a class=\"reference internal\" href=\"/ko/3.1/topics/http/shortcuts/#django.shortcuts.get_object_or_404\" title=\"django.shortcuts.get_object_or_404\"><code class=\"xref py py-func docutils literal notranslate\">get_object_or_404()</code></a> 함수는 Django 모델을 첫번째 인자로 받고, 몇개의 키워드 인수를 모델 관리자의 <a class=\"reference internal\" href=\"/ko/3.1/ref/models/querysets/#django.db.models.query.QuerySet.get\" title=\"django.db.models.query.QuerySet.get\"><code class=\"xref py py-meth docutils literal notranslate\">get()</code></a> 함수에 넘깁니다. 만약 객체가 존재하지 않을 경우, <a class=\"reference internal\" href=\"/ko/3.1/topics/http/views/#django.http.Http404\" title=\"django.http.Http404\"><code class=\"xref py py-exc docutils literal notranslate\">Http404</code></a> 예외가 발생합니다.</p>\n<aside class=\"admonition-philosophy admonition\" role=\"note\">\n<p class=\"admonition-title\">철학</p>\n<p>상위 계층에서 <a class=\"reference internal\" href=\"/ko/3.1/ref/exceptions/#django.core.exceptions.ObjectDoesNotExist\" title=\"django.core.exceptions.ObjectDoesNotExist\"><code class=\"xref py py-exc docutils literal notranslate\">ObjectDoesNotExist</code></a> 예외를 자동으로 잡아 내는 대신 <a class=\"reference internal\" href=\"/ko/3.1/topics/http/shortcuts/#django.shortcuts.get_object_or_404\" title=\"django.shortcuts.get_object_or_404\"><code class=\"xref py py-func docutils literal notranslate\">get_object_or_404()</code></a> 도움 함수(helper functoin)를 사용하거나, <a class=\"reference internal\" href=\"/ko/3.1/ref/exceptions/#django.core.exceptions.ObjectDoesNotExist\" title=\"django.core.exceptions.ObjectDoesNotExist\"><code class=\"xref py py-exc docutils literal notranslate\">ObjectDoesNotExist</code></a> 예외를 사용하는 대신 <a class=\"reference internal\" href=\"/ko/3.1/topics/http/views/#django.http.Http404\" title=\"django.http.Http404\"><code class=\"xref py py-exc docutils literal notranslate\">Http404</code></a> 를 사용하는 이유는 무엇일까요?</p>\n<p>왜냐하면, 모델 계층을 뷰 계층에 연결하는 방법이기 때문입니다. Django의 중요한 설계 목표는, 약결합(loose coupling)을 관리하는 데에 있습니다. 일부 제어된 결합이 <a class=\"reference internal\" href=\"/ko/3.1/topics/http/shortcuts/#module-django.shortcuts\" title=\"django.shortcuts: Convenience shortcuts that span multiple levels of Django's MVC stack.\"><code class=\"xref py py-mod docutils literal notranslate\">django.shortcuts</code></a> 모듈에서 도입되었습니다.</p>\n</aside>\n<p>또한, <a class=\"reference internal\" href=\"/ko/3.1/topics/http/shortcuts/#django.shortcuts.get_object_or_404\" title=\"django.shortcuts.get_object_or_404\"><code class=\"xref py py-func docutils literal notranslate\">get_object_or_404()</code></a> 함수처럼 동작하는 <a class=\"reference internal\" href=\"/ko/3.1/topics/http/shortcuts/#django.shortcuts.get_list_or_404\" title=\"django.shortcuts.get_list_or_404\"><code class=\"xref py py-func docutils literal notranslate\">get_list_or_404()</code></a> 함수가 있습니다. <a class=\"reference internal\" href=\"/ko/3.1/ref/models/querysets/#django.db.models.query.QuerySet.get\" title=\"django.db.models.query.QuerySet.get\"><code class=\"xref py py-meth docutils literal notranslate\">get()</code></a> 대신 <a class=\"reference internal\" href=\"/ko/3.1/ref/models/querysets/#django.db.models.query.QuerySet.filter\" title=\"django.db.models.query.QuerySet.filter\"><code class=\"xref py py-meth docutils literal notranslate\">filter()</code></a> 를 쓴다는 것이 다릅니다. 리스트가 비어있을 경우, <a class=\"reference internal\" href=\"/ko/3.1/topics/http/views/#django.http.Http404\" title=\"django.http.Http404\"><code class=\"xref py py-exc docutils literal notranslate\">Http404</code></a> 예외를 발생시킵니다.</p>\n</section>\n</section>\n<section id=\"use-the-template-system\">\n<h2>템플릿 시스템 사용하기<a class=\"heading-anchor\" href=\"#use-the-template-system\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>투표 어플리케이션의 <code class=\"docutils literal notranslate\">detail()</code> 뷰로 되돌아가 봅시다. context 변수 <code class=\"docutils literal notranslate\">question</code>이 주어졌을때, <code class=\"docutils literal notranslate\">polls/detail.html</code>이라는 템플릿이 어떻게 보이는지 봅시다.</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"html+django\"><figcaption class=\"code-block-caption\">polls/templates/polls/detail.html</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<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=\"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</code></pre></figure>\n<p>템플릿 시스템은 변수의 속성에 접근하기 위해 점-탐색(dot-lookup) 문법을 사용합니다. 예제의 <code class=\"docutils literal notranslate\">{{ question.question_text }}</code> 구문을 보면, Django는 먼저 <code class=\"docutils literal notranslate\">question</code> 객체에 대해 사전형으로 탐색합니다. 탐색에 실패하게 되면 속성값으로 탐색합니다. (이 예에서는 속성값에서 탐색이 완료됩니다만) 만약 속성 탐색에도 실패한다면 리스트의 인덱스 탐색을 시도하게 됩니다.</p>\n<p><a class=\"reference internal\" href=\"/ko/3.1/ref/templates/builtins/#std-templatetag-for\"><code class=\"xref std std-ttag docutils literal notranslate\">{% for %}</code></a> 반복 구문에서 메소드 호출이 일어납니다. <code class=\"docutils literal notranslate\">question.choice_set.all</code>은 Python에서 <code class=\"docutils literal notranslate\">question.choice_set.all()</code> 코드로 해석되는데, 이때 반환된 <code class=\"docutils literal notranslate\">Choice</code> 객체의 반복자는 <a class=\"reference internal\" href=\"/ko/3.1/ref/templates/builtins/#std-templatetag-for\"><code class=\"xref std std-ttag docutils literal notranslate\">{% for %}</code></a>에서 사용하기 적당합니다.</p>\n<p>템플릿에 대한 더 많은 정보는 <a class=\"reference internal\" href=\"/ko/3.1/topics/templates/\"><span class=\"doc\">템플릿 지침서</span></a>를 참고하세요.</p>\n</section>\n<section id=\"removing-hardcoded-urls-in-templates\">\n<h2>템플릿에서 하드코딩된 URL 제거하기<a class=\"heading-anchor\" href=\"#removing-hardcoded-urls-in-templates\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p><code class=\"docutils literal notranslate\">polls/index.html</code> 템플릿에 링크를 적으면, 이 링크는 다음과 같이 부분적으로 하드코딩된다는 것을 기억하세요.</p>\n<div class=\"code-block\" data-language=\"html+django\"><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\">li</span><span class=\"p\">&gt;&lt;</span><span class=\"nt\">a</span> <span class=\"na\">href</span><span class=\"o\">=</span><span class=\"s\">&quot;/polls/</span><span class=\"cp\">{{</span> <span class=\"nv\">question.id</span> <span class=\"cp\">}}</span><span class=\"s\">/&quot;</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\">a</span><span class=\"p\">&gt;&lt;/</span><span class=\"nt\">li</span><span class=\"p\">&gt;</span>\n</code></pre></div>\n<p>이러한 강력하게 결합되고 하드코딩된 접근방식의 문제는 수 많은 템플릿을 가진 프로젝트들의 URL을 바꾸는 게 어려운 일이 된다는 점입니다. 그러나, <code class=\"docutils literal notranslate\">polls.urls</code> 모듈의 <a class=\"reference internal\" href=\"/ko/3.1/ref/urls/#django.urls.path\" title=\"django.urls.path\"><code class=\"xref py py-func docutils literal notranslate\">path()</code></a> 함수에서 인수의 이름을 정의했으므로, <code class=\"docutils literal notranslate\">{% url %}</code> template 태그를 사용하여 url 설정에 정의된 특정한 URL 경로들의 의존성을 제거할 수 있습니다.</p>\n<div class=\"code-block\" data-language=\"html+django\"><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\">li</span><span class=\"p\">&gt;&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;detail&#39;</span> <span class=\"nv\">question.id</span> <span class=\"cp\">%}</span><span class=\"s\">&quot;</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\">a</span><span class=\"p\">&gt;&lt;/</span><span class=\"nt\">li</span><span class=\"p\">&gt;</span>\n</code></pre></div>\n<p>이것이 <code class=\"docutils literal notranslate\">polls.urls</code> 모듈에 서술된 URL 의 정의를 탐색하는 식으로 동작합니다. 다음과 같이 ‘detail’ 이라는 이름의 URL 이 어떻게 정의되어 있는지 확인할 수 있습니다.</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=\"o\">...</span>\n<span class=\"c1\"># the &#39;name&#39; value as called by the {% url %} template tag</span>\npath<span class=\"p\">(</span><span class=\"s1\">&#39;&lt;int:question_id&gt;/&#39;</span><span class=\"p\">,</span> views<span class=\"o\">.</span>detail<span class=\"p\">,</span> name<span class=\"o\">=</span><span class=\"s1\">&#39;detail&#39;</span><span class=\"p\">),</span>\n<span class=\"o\">...</span>\n</code></pre></div>\n<p>만약 상세 뷰의 URL을 <code class=\"docutils literal notranslate\">polls/specifics/12/</code>로 바꾸고 싶다면, 템플릿에서 바꾸는 것이 아니라 <code class=\"docutils literal notranslate\">polls/urls.py</code>에서 바꿔야 합니다.</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=\"o\">...</span>\n<span class=\"c1\"># added the word &#39;specifics&#39;</span>\npath<span class=\"p\">(</span><span class=\"s1\">&#39;specifics/&lt;int:question_id&gt;/&#39;</span><span class=\"p\">,</span> views<span class=\"o\">.</span>detail<span class=\"p\">,</span> name<span class=\"o\">=</span><span class=\"s1\">&#39;detail&#39;</span><span class=\"p\">),</span>\n<span class=\"o\">...</span>\n</code></pre></div>\n</section>\n<section id=\"namespacing-url-names\">\n<h2>URL의 이름공간 정하기<a class=\"heading-anchor\" href=\"#namespacing-url-names\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>튜토리얼의 프로젝트는 <code class=\"docutils literal notranslate\">polls</code>라는 앱 하나만 가지고 진행했습니다. 실제 Django 프로젝트는 앱이 몇개라도 올 수 있습니다. Django는 이 앱들의 URL을 어떻게 구별해 낼까요? 예를 들어, <code class=\"docutils literal notranslate\">polls</code> 앱은 <code class=\"docutils literal notranslate\">detail</code>이라는 뷰를 가지고 있고, 동일한 프로젝트에 블로그를 위한 앱이 있을 수도 있습니다. Django가 <code class=\"docutils literal notranslate\">{% url %}</code> 템플릿태그를 사용할 때, 어떤 앱의 뷰에서 URL을 생성할지 알 수 있을까요?</p>\n<p>정답은 URLconf에 이름공간(namespace)을 추가하는 것입니다. <code class=\"docutils literal notranslate\">polls/urls.py</code> 파일에 <code class=\"docutils literal notranslate\">app_name</code>을 추가하여 어플리케이션의 이름공간을 설정할 수 있습니다.</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/urls.py</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=\"nn\">django.urls</span> <span class=\"kn\">import</span> path\n\n<span class=\"kn\">from</span> <span class=\"nn\">.</span> <span class=\"kn\">import</span> views\n\napp_name <span class=\"o\">=</span> <span class=\"s1\">&#39;polls&#39;</span>\nurlpatterns <span class=\"o\">=</span> <span class=\"p\">[</span>\n    path<span class=\"p\">(</span><span class=\"s1\">&#39;&#39;</span><span class=\"p\">,</span> views<span class=\"o\">.</span>index<span class=\"p\">,</span> name<span class=\"o\">=</span><span class=\"s1\">&#39;index&#39;</span><span class=\"p\">),</span>\n    path<span class=\"p\">(</span><span class=\"s1\">&#39;&lt;int:question_id&gt;/&#39;</span><span class=\"p\">,</span> views<span class=\"o\">.</span>detail<span class=\"p\">,</span> name<span class=\"o\">=</span><span class=\"s1\">&#39;detail&#39;</span><span class=\"p\">),</span>\n    path<span class=\"p\">(</span><span class=\"s1\">&#39;&lt;int:question_id&gt;/results/&#39;</span><span class=\"p\">,</span> views<span class=\"o\">.</span>results<span class=\"p\">,</span> name<span class=\"o\">=</span><span class=\"s1\">&#39;results&#39;</span><span class=\"p\">),</span>\n    path<span class=\"p\">(</span><span class=\"s1\">&#39;&lt;int:question_id&gt;/vote/&#39;</span><span class=\"p\">,</span> views<span class=\"o\">.</span>vote<span class=\"p\">,</span> name<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\">polls/index.html</code> 템플릿의 기존 내용을</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"html+django\"><figcaption class=\"code-block-caption\">polls/templates/polls/index.html</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\">li</span><span class=\"p\">&gt;&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;detail&#39;</span> <span class=\"nv\">question.id</span> <span class=\"cp\">%}</span><span class=\"s\">&quot;</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\">a</span><span class=\"p\">&gt;&lt;/</span><span class=\"nt\">li</span><span class=\"p\">&gt;</span>\n</code></pre></figure>\n<p>아래와 같이 이름공간으로 나눠진 상세 뷰를 가리키도록 변경하세요.</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"html+django\"><figcaption class=\"code-block-caption\">polls/templates/polls/index.html</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\">li</span><span class=\"p\">&gt;&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><span class=\"cp\">{{</span> <span class=\"nv\">question.question_text</span> <span class=\"cp\">}}</span><span class=\"p\">&lt;/</span><span class=\"nt\">a</span><span class=\"p\">&gt;&lt;/</span><span class=\"nt\">li</span><span class=\"p\">&gt;</span>\n</code></pre></figure>\n<p>When you’re comfortable with writing views, read <a class=\"reference internal\" href=\"/ko/3.1/intro/tutorial04/\"><span class=\"doc\">part 4 of this tutorial</span></a> to learn the basics about form processing and generic\nviews.</p>\n</section>","rootId":"writing-your-first-django-app-part-3","toc":[{"title":"개요","anchor":"overview","children":[]},{"title":"뷰 추가하기","anchor":"writing-more-views","children":[]},{"title":"뷰가 실제로 뭔가를 하도록 만들기","anchor":"write-views-that-actually-do-something","children":[{"title":"지름길: render()","anchor":"a-shortcut-render","children":[]}]},{"title":"404 에러 일으키기","anchor":"raising-a-404-error","children":[{"title":"지름길: get_object_or_404()","anchor":"a-shortcut-get-object-or-404","children":[]}]},{"title":"템플릿 시스템 사용하기","anchor":"use-the-template-system","children":[]},{"title":"템플릿에서 하드코딩된 URL 제거하기","anchor":"removing-hardcoded-urls-in-templates","children":[]},{"title":"URL의 이름공간 정하기","anchor":"namespacing-url-names","children":[]}],"breadcrumbs":[{"docname":"intro/index","title":"시작하기","url":"/ko/3.1/intro/"}],"prev":{"docname":"intro/tutorial02","title":"첫 번째 장고 앱 작성하기, part 2","url":"/ko/3.1/intro/tutorial02/"},"next":{"docname":"intro/tutorial04","title":"첫 번째 장고 앱 작성하기, part 4","url":"/ko/3.1/intro/tutorial04/"},"formats":{"html":"/ko/3.1/intro/tutorial03/","markdown":"/ko/3.1/intro/tutorial03.md","json":"/ko/3.1/intro/tutorial03.json"},"source":"https://github.com/django/django/blob/stable/3.1.x/docs/intro/tutorial03.txt","official":"https://docs.djangoproject.com/ko/3.1/intro/tutorial03/","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"]}