{"title":"Writing your first Django app, part 4","version":"1.9","locale":"en","docname":"intro/tutorial04","url":"/en/1.9/intro/tutorial04/","canonical":"https://djangodocs.dev/en/1.9/intro/tutorial04/","summary":"This tutorial begins where Tutorial 3 left off. We’re continuing the Web-poll application and will focus on simple form processing and cutting down our code. Write…","html":"<h1>Writing your first Django app, 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=\"/en/1.9/intro/tutorial03/\"><span class=\"doc\">Tutorial 3</span></a> left off. We’re\ncontinuing the Web-poll application and will focus on simple form processing and\ncutting down our code.</p>\n<section id=\"write-a-simple-form\">\n<h2>Write a simple form<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>A quick rundown:</p>\n<ul class=\"simple\">\n<li><p>The above template displays a radio button for each question choice. The\n<code class=\"docutils literal notranslate\"><span class=\"pre\">value</span></code> of each radio button is the associated question choice’s ID. The\n<code class=\"docutils literal notranslate\"><span class=\"pre\">name</span></code> of each radio button is <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;choice&quot;</span></code>. That means, when somebody\nselects one of the radio buttons and submits the form, it’ll send the\nPOST data <code class=\"docutils literal notranslate\"><span class=\"pre\">choice=#</span></code> where # is the ID of the selected choice. This is the\nbasic concept of HTML forms.</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 just good Web development practice.</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">forloop.counter</span></code> indicates how many times the <a class=\"reference internal\" href=\"/en/1.9/ref/templates/builtins/#std-templatetag-for\"><code class=\"xref std std-ttag docutils literal notranslate\"><span class=\"pre\">for</span></code></a> tag has gone\nthrough its loop</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\na very easy-to-use system for protecting against it. In short, all POST\nforms that are targeted at internal URLs should use the\n<a class=\"reference internal\" href=\"/en/1.9/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> template tag.</p></li>\n</ul>\n<p>Now, let’s create a Django view that handles the submitted data and does\nsomething with it. Remember, in <a class=\"reference internal\" href=\"/en/1.9/intro/tutorial03/\"><span class=\"doc\">Tutorial 3</span></a>, we\ncreated a URLconf for the polls application that includes this line:</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\">url</span><span class=\"p\">(</span><span class=\"sa\">r</span><span class=\"s1\">&#39;^(?P&lt;question_id&gt;[0-9]+)/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>We also created a dummy implementation of the <code class=\"docutils literal notranslate\"><span class=\"pre\">vote()</span></code> function. Let’s\ncreate a real version. Add the following to <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.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.http</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">HttpResponseRedirect</span><span class=\"p\">,</span> <span class=\"n\">HttpResponse</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.core.urlresolvers</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>This code includes a few things we haven’t covered yet in this tutorial:</p>\n<ul>\n<li><p><a class=\"reference internal\" href=\"/en/1.9/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> is a dictionary-like\nobject that lets you access submitted data by key name. In this case,\n<code class=\"docutils literal notranslate\"><span class=\"pre\">request.POST['choice']</span></code> returns the ID of the selected choice, as a\nstring. <a class=\"reference internal\" href=\"/en/1.9/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> values are\nalways strings.</p>\n<p>Note that Django also provides <a class=\"reference internal\" href=\"/en/1.9/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> for accessing GET data in the same way –\nbut we’re explicitly using <a class=\"reference internal\" href=\"/en/1.9/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> in our code, to ensure that data is only\naltered via a POST call.</p>\n</li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">request.POST['choice']</span></code> will raise <a class=\"reference external\" href=\"https://docs.python.org/3/library/exceptions.html#KeyError\" title=\"(in Python v3.14)\"><code class=\"xref py py-exc docutils literal notranslate\"><span class=\"pre\">KeyError</span></code></a> if\n<code class=\"docutils literal notranslate\"><span class=\"pre\">choice</span></code> wasn’t provided in POST data. The above code checks for\n<a class=\"reference external\" href=\"https://docs.python.org/3/library/exceptions.html#KeyError\" title=\"(in Python v3.14)\"><code class=\"xref py py-exc docutils literal notranslate\"><span class=\"pre\">KeyError</span></code></a> and redisplays the question form with an error\nmessage if <code class=\"docutils literal notranslate\"><span class=\"pre\">choice</span></code> isn’t given.</p></li>\n<li><p>After incrementing the choice count, the code returns an\n<a class=\"reference internal\" href=\"/en/1.9/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> rather than a normal\n<a class=\"reference internal\" href=\"/en/1.9/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>.\n<a class=\"reference internal\" href=\"/en/1.9/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> takes a single argument: the\nURL to which the user will be redirected (see the following point for how\nwe construct the URL in this case).</p>\n<p>As the Python comment above points out, you should always return an\n<a class=\"reference internal\" href=\"/en/1.9/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 just good Web\ndevelopment practice.</p>\n</li>\n<li><p>We are using the <a class=\"reference internal\" href=\"/en/1.9/ref/urlresolvers/#django.core.urlresolvers.reverse\" title=\"django.core.urlresolvers.reverse\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">reverse()</span></code></a> function in the\n<a class=\"reference internal\" href=\"/en/1.9/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> constructor in this example.\nThis function helps avoid having to hardcode a URL in the view function.\nIt is given the name of the view that we want to pass control to and the\nvariable portion of the URL pattern that points to that view. In this\ncase, using the URLconf we set up in <a class=\"reference internal\" href=\"/en/1.9/intro/tutorial03/\"><span class=\"doc\">Tutorial 3</span></a>,\nthis <a class=\"reference internal\" href=\"/en/1.9/ref/urlresolvers/#django.core.urlresolvers.reverse\" title=\"django.core.urlresolvers.reverse\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">reverse()</span></code></a> call will return a string like</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>where the <code class=\"docutils literal notranslate\"><span class=\"pre\">3</span></code> is the value of <code class=\"docutils literal notranslate\"><span class=\"pre\">question.id</span></code>. This redirected URL will\nthen call the <code class=\"docutils literal notranslate\"><span class=\"pre\">'results'</span></code> view to display the final page.</p>\n</li>\n</ul>\n<p>As mentioned in <a class=\"reference internal\" href=\"/en/1.9/intro/tutorial03/\"><span class=\"doc\">Tutorial 3</span></a>, <code class=\"docutils literal notranslate\"><span class=\"pre\">request</span></code> is an\n<a class=\"reference internal\" href=\"/en/1.9/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> object. For more on\n<a class=\"reference internal\" href=\"/en/1.9/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> objects, see the <a class=\"reference internal\" href=\"/en/1.9/ref/request-response/\"><span class=\"doc\">request and\nresponse documentation</span></a>.</p>\n<p>After somebody votes in a question, the <code class=\"docutils literal notranslate\"><span class=\"pre\">vote()</span></code> view redirects to the results\npage for the question. Let’s write that view:</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>This is almost exactly the same as the <code class=\"docutils literal notranslate\"><span class=\"pre\">detail()</span></code> view from <a class=\"reference internal\" href=\"/en/1.9/intro/tutorial03/\"><span class=\"doc\">Tutorial 3</span></a>. The only difference is the template name. We’ll fix this\nredundancy later.</p>\n<p>Now, create a <code class=\"docutils literal notranslate\"><span class=\"pre\">polls/results.html</span></code> template:</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>Now, go to <code class=\"docutils literal notranslate\"><span class=\"pre\">/polls/1/</span></code> in your browser and vote in the question. You should see a\nresults page that gets updated each time you vote. If you submit the form\nwithout having chosen a choice, you should see the error message.</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>The code for our <code class=\"docutils literal notranslate\"><span class=\"pre\">vote()</span></code> view does have a small problem. It first gets\nthe <code class=\"docutils literal notranslate\"><span class=\"pre\">selected_choice</span></code> object from the database, then computes the new\nvalue of <code class=\"docutils literal notranslate\"><span class=\"pre\">votes</span></code>, and then saves it back to the database. If two users of\nyour website try to vote at <em>exactly the same time</em>, this might go wrong:\nThe same value, let’s say 42, will be retrieved for <code class=\"docutils literal notranslate\"><span class=\"pre\">votes</span></code>. Then, for\nboth users the new value of 43 is computed and saved, but 44 would be the\nexpected value.</p>\n<p>This is called a <em>race condition</em>. If you are interested, you can read\n<a class=\"reference internal\" href=\"/en/1.9/ref/models/expressions/#avoiding-race-conditions-using-f\"><span class=\"std std-ref\">Avoiding race conditions using F()</span></a> to learn how you can solve this\nissue.</p>\n</aside>\n</section>\n<section id=\"use-generic-views-less-code-is-better\">\n<h2>Use generic views: Less code is better<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=\"/en/1.9/intro/tutorial03/\"><span class=\"doc\">Tutorial 3</span></a>) and <code class=\"docutils literal notranslate\"><span class=\"pre\">results()</span></code>\nviews are very simple – 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>These views represent a common case of basic Web development: getting data from\nthe database according to a parameter passed in the URL, loading a template and\nreturning the rendered template. Because this is so common, Django provides a\nshortcut, called the “generic views” system.</p>\n<p>Generic views abstract common patterns to the point where you don’t even need\nto write Python code to write an app.</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 just have to take a few steps to make the\nconversion. We will:</p>\n<ol class=\"arabic simple\">\n<li><p>Convert the URLconf.</p></li>\n<li><p>Delete some of the old, unneeded views.</p></li>\n<li><p>Introduce new views based on Django’s generic views.</p></li>\n</ol>\n<p>Read on for details.</p>\n<aside class=\"admonition-why-the-code-shuffle admonition\">\n<p class=\"admonition-title\">Why the code-shuffle?</p>\n<p>Generally, when writing a Django app, you’ll evaluate whether generic views\nare a good fit for your problem, and you’ll use them from the beginning,\nrather than refactoring your code halfway through. But this tutorial\nintentionally has focused on writing the views “the hard way” until now, to\nfocus on core concepts.</p>\n<p>You should know basic math before you start using a calculator.</p>\n</aside>\n<section id=\"amend-urlconf\">\n<h3>Amend 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>First, open the <code class=\"docutils literal notranslate\"><span class=\"pre\">polls/urls.py</span></code> URLconf and change it like so:</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.conf.urls</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">url</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\">url</span><span class=\"p\">(</span><span class=\"sa\">r</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\">url</span><span class=\"p\">(</span><span class=\"sa\">r</span><span class=\"s1\">&#39;^(?P&lt;pk&gt;[0-9]+)/$&#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\">url</span><span class=\"p\">(</span><span class=\"sa\">r</span><span class=\"s1\">&#39;^(?P&lt;pk&gt;[0-9]+)/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\">url</span><span class=\"p\">(</span><span class=\"sa\">r</span><span class=\"s1\">&#39;^(?P&lt;question_id&gt;[0-9]+)/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>Note that the name of the matched pattern in the regexes of the second and third\npatterns has changed from <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;question_id&gt;</span></code> to <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;pk&gt;</span></code>.</p>\n</section>\n<section id=\"amend-views\">\n<h3>Amend 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>Next, we’re going to remove our old <code class=\"docutils literal notranslate\"><span class=\"pre\">index</span></code>, <code class=\"docutils literal notranslate\"><span class=\"pre\">detail</span></code>, and <code class=\"docutils literal notranslate\"><span class=\"pre\">results</span></code>\nviews and use Django’s generic views instead. To do so, open the\n<code class=\"docutils literal notranslate\"><span class=\"pre\">polls/views.py</span></code> file and change it like so:</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<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.core.urlresolvers</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>We’re using two generic views here:\n<a class=\"reference internal\" href=\"/en/1.9/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> and\n<a class=\"reference internal\" href=\"/en/1.9/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>. Respectively, those\ntwo views abstract the concepts of “display a list of objects” and\n“display a detail page for a particular type of object.”</p>\n<ul class=\"simple\">\n<li><p>Each generic view needs to know what model it will be acting\nupon. This is provided using the <code class=\"docutils literal notranslate\"><span class=\"pre\">model</span></code> attribute.</p></li>\n<li><p>The <a class=\"reference internal\" href=\"/en/1.9/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> generic view\nexpects the primary key value captured from the URL to be called\n<code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;pk&quot;</span></code>, so we’ve changed <code class=\"docutils literal notranslate\"><span class=\"pre\">question_id</span></code> to <code class=\"docutils literal notranslate\"><span class=\"pre\">pk</span></code> for the generic\nviews.</p></li>\n</ul>\n<p>By default, the <a class=\"reference internal\" href=\"/en/1.9/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> generic\nview uses a template called <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>.\nIn our case, it would use the template <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;polls/question_detail.html&quot;</span></code>. The\n<code class=\"docutils literal notranslate\"><span class=\"pre\">template_name</span></code> attribute is used to tell Django to use a specific\ntemplate name instead of the autogenerated default template name. We\nalso specify the <code class=\"docutils literal notranslate\"><span class=\"pre\">template_name</span></code> for the <code class=\"docutils literal notranslate\"><span class=\"pre\">results</span></code> list view –\nthis ensures that the results view and the detail view have a\ndifferent appearance when rendered, even though they’re both a\n<a class=\"reference internal\" href=\"/en/1.9/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> behind the scenes.</p>\n<p>Similarly, the <a class=\"reference internal\" href=\"/en/1.9/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> generic\nview uses a default template called <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;app</span> <span class=\"pre\">name&gt;/&lt;model</span>\n<span class=\"pre\">name&gt;_list.html</span></code>; we use <code class=\"docutils literal notranslate\"><span class=\"pre\">template_name</span></code> to tell\n<a class=\"reference internal\" href=\"/en/1.9/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> to use our existing\n<code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;polls/index.html&quot;</span></code> template.</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 just\ntell Django to use the variable you want.</p>\n<p>Run the server, and use your new polling app based on generic views.</p>\n<p>For full details on generic views, see the <a class=\"reference internal\" href=\"/en/1.9/topics/class-based-views/\"><span class=\"doc\">generic views documentation</span></a>.</p>\n<p>When you’re comfortable with forms and generic views, read <a class=\"reference internal\" href=\"/en/1.9/intro/tutorial05/\"><span class=\"doc\">part 5 of this\ntutorial</span></a> to learn about testing our polls app.</p>\n</section>\n</section>","rootId":"writing-your-first-django-app-part-4","toc":[{"title":"Write a simple form","anchor":"write-a-simple-form","children":[]},{"title":"Use generic views: Less code is better","anchor":"use-generic-views-less-code-is-better","children":[{"title":"Amend URLconf","anchor":"amend-urlconf","children":[]},{"title":"Amend views","anchor":"amend-views","children":[]}]}],"breadcrumbs":[{"docname":"intro/index","title":"Getting started","url":"/en/1.9/intro/"}],"prev":{"docname":"intro/tutorial03","title":"Writing your first Django app, part 3","url":"/en/1.9/intro/tutorial03/"},"next":{"docname":"intro/tutorial05","title":"Writing your first Django app, part 5","url":"/en/1.9/intro/tutorial05/"},"formats":{"html":"/en/1.9/intro/tutorial04/","markdown":"/en/1.9/intro/tutorial04.md","json":"/en/1.9/intro/tutorial04.json"},"source":"https://github.com/django/django/blob/stable/1.9.x/docs/intro/tutorial04.txt","official":"https://docs.djangoproject.com/en/1.9/intro/tutorial04/","inVersions":["dev","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","1.10","1.9","1.8"],"inLocales":["en","fr","ja","id","pt-br","es"]}