{"title":"Escrevendo sua primeira aplicação Django, parte 4","version":"3.2","locale":"pt-br","docname":"intro/tutorial04","url":"/pt-br/3.2/intro/tutorial04/","canonical":"https://djangodocs.dev/pt-br/3.2/intro/tutorial04/","summary":"This tutorial begins where Tutorial 3 left off. We’re continuing the Web-poll application and will focus on form processing and cutting down our code. Onde obter…","html":"<h1>Escrevendo sua primeira aplicação Django, parte 4<a class=\"heading-anchor\" href=\"#writing-your-first-django-app-part-4\"><span class=\"visually-hidden\">Link para este cabeçalho</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>This tutorial begins where <a class=\"reference internal\" href=\"/pt-br/3.2/intro/tutorial03/\"><span class=\"doc\">Tutorial 3</span></a> left off. We’re\ncontinuing the Web-poll application and will focus on form processing and\ncutting down our code.</p>\n<aside class=\"admonition-where-to-get-help admonition\">\n<p class=\"admonition-title\">Onde obter ajuda:</p>\n<p>Se tiver problemas enquanto caminha por este tutorial, por favor consulte a seção <a class=\"reference internal\" href=\"/pt-br/3.2/faq/help/\"><span class=\"doc\">Obtendo ajuda</span></a> da FAQ.</p>\n</aside>\n<section id=\"write-a-minimal-form\">\n<h2>Write a minimal form<a class=\"heading-anchor\" href=\"#write-a-minimal-form\"><span class=\"visually-hidden\">Link para este cabeçalho</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Vamos atualizar nosso template de detalhamento da enquete (“polls/detail.html”)\ndo último tutorial, para que ele contenha um elemento HTML <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;form&gt;</span></code>:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"html+django\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">polls/templates/polls/detail.html</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Django template code\"><code><span class=\"p\">&lt;</span><span class=\"nt\">form</span> <span class=\"na\">action</span><span class=\"o\">=</span><span class=\"s\">&quot;</span><span class=\"cp\">{%</span> <span class=\"k\">url</span> <span class=\"s1\">&#39;polls:vote&#39;</span> <span class=\"nv\">question.id</span> <span class=\"cp\">%}</span><span class=\"s\">&quot;</span> <span class=\"na\">method</span><span class=\"o\">=</span><span class=\"s\">&quot;post&quot;</span><span class=\"p\">&gt;</span>\n<span class=\"cp\">{%</span> <span class=\"k\">csrf_token</span> <span class=\"cp\">%}</span>\n<span class=\"p\">&lt;</span><span class=\"nt\">fieldset</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">legend</span><span class=\"p\">&gt;&lt;</span><span class=\"nt\">h1</span><span class=\"p\">&gt;</span><span class=\"cp\">{{</span> <span class=\"nv\">question.question_text</span> <span class=\"cp\">}}</span><span class=\"p\">&lt;/</span><span class=\"nt\">h1</span><span class=\"p\">&gt;&lt;/</span><span class=\"nt\">legend</span><span class=\"p\">&gt;</span>\n    <span class=\"cp\">{%</span> <span class=\"k\">if</span> <span class=\"nv\">error_message</span> <span class=\"cp\">%}</span><span class=\"p\">&lt;</span><span class=\"nt\">p</span><span class=\"p\">&gt;&lt;</span><span class=\"nt\">strong</span><span class=\"p\">&gt;</span><span class=\"cp\">{{</span> <span class=\"nv\">error_message</span> <span class=\"cp\">}}</span><span class=\"p\">&lt;/</span><span class=\"nt\">strong</span><span class=\"p\">&gt;&lt;/</span><span class=\"nt\">p</span><span class=\"p\">&gt;</span><span class=\"cp\">{%</span> <span class=\"k\">endif</span> <span class=\"cp\">%}</span>\n    <span class=\"cp\">{%</span> <span class=\"k\">for</span> <span class=\"nv\">choice</span> <span class=\"k\">in</span> <span class=\"nv\">question.choice_set.all</span> <span class=\"cp\">%}</span>\n        <span class=\"p\">&lt;</span><span class=\"nt\">input</span> <span class=\"na\">type</span><span class=\"o\">=</span><span class=\"s\">&quot;radio&quot;</span> <span class=\"na\">name</span><span class=\"o\">=</span><span class=\"s\">&quot;choice&quot;</span> <span class=\"na\">id</span><span class=\"o\">=</span><span class=\"s\">&quot;choice</span><span class=\"cp\">{{</span> <span class=\"nb\">forloop</span><span class=\"nv\">.counter</span> <span class=\"cp\">}}</span><span class=\"s\">&quot;</span> <span class=\"na\">value</span><span class=\"o\">=</span><span class=\"s\">&quot;</span><span class=\"cp\">{{</span> <span class=\"nv\">choice.id</span> <span class=\"cp\">}}</span><span class=\"s\">&quot;</span><span class=\"p\">&gt;</span>\n        <span class=\"p\">&lt;</span><span class=\"nt\">label</span> <span class=\"na\">for</span><span class=\"o\">=</span><span class=\"s\">&quot;choice</span><span class=\"cp\">{{</span> <span class=\"nb\">forloop</span><span class=\"nv\">.counter</span> <span class=\"cp\">}}</span><span class=\"s\">&quot;</span><span class=\"p\">&gt;</span><span class=\"cp\">{{</span> <span class=\"nv\">choice.choice_text</span> <span class=\"cp\">}}</span><span class=\"p\">&lt;/</span><span class=\"nt\">label</span><span class=\"p\">&gt;&lt;</span><span class=\"nt\">br</span><span class=\"p\">&gt;</span>\n    <span class=\"cp\">{%</span> <span class=\"k\">endfor</span> <span class=\"cp\">%}</span>\n<span class=\"p\">&lt;/</span><span class=\"nt\">fieldset</span><span class=\"p\">&gt;</span>\n<span class=\"p\">&lt;</span><span class=\"nt\">input</span> <span class=\"na\">type</span><span class=\"o\">=</span><span class=\"s\">&quot;submit&quot;</span> <span class=\"na\">value</span><span class=\"o\">=</span><span class=\"s\">&quot;Vote&quot;</span><span class=\"p\">&gt;</span>\n<span class=\"p\">&lt;/</span><span class=\"nt\">form</span><span class=\"p\">&gt;</span>\n</code></pre></figure>\n<p>Uma rápida explicação:</p>\n<ul class=\"simple\">\n<li><p>O template acima exibe um botão radio para cada opção da enquete.  O <code class=\"docutils literal notranslate\"><span class=\"pre\">value</span></code> de cada botão radio está associado ao ID da opção.  O <code class=\"docutils literal notranslate\"><span class=\"pre\">name</span></code> de cada botão radio é a escolha <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;choice&quot;</span></code>. Isso significa que, quando alguém escolhe um dos botões de radio e submete a formulário, ele vai enviar o dado``choice=#`` por POST onde # é o ID da escolha selecionada. Este é o conceito básico sobre formulários HTML.</p></li>\n<li><p>We set the form’s <code class=\"docutils literal notranslate\"><span class=\"pre\">action</span></code> to <code class=\"docutils literal notranslate\"><span class=\"pre\">{%</span> <span class=\"pre\">url</span> <span class=\"pre\">'polls:vote'</span> <span class=\"pre\">question.id</span> <span class=\"pre\">%}</span></code>, and we\nset <code class=\"docutils literal notranslate\"><span class=\"pre\">method=&quot;post&quot;</span></code>. Using <code class=\"docutils literal notranslate\"><span class=\"pre\">method=&quot;post&quot;</span></code> (as opposed to\n<code class=\"docutils literal notranslate\"><span class=\"pre\">method=&quot;get&quot;</span></code>) is very important, because the act of submitting this\nform will alter data server-side. Whenever you create a form that alters\ndata server-side, use <code class=\"docutils literal notranslate\"><span class=\"pre\">method=&quot;post&quot;</span></code>. This tip isn’t specific to\nDjango; it’s good Web development practice in general.</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">forloop.counter</span></code> indica quantas vezes a tag :ttag`for` passou pelo laço.</p></li>\n<li><p>Since we’re creating a POST form (which can have the effect of modifying\ndata), we need to worry about Cross Site Request Forgeries.\nThankfully, you don’t have to worry too hard, because Django comes with a\nhelpful system for protecting against it. In short, all POST forms that are\ntargeted at internal URLs should use the <a class=\"reference internal\" href=\"/pt-br/3.2/ref/templates/builtins/#std-templatetag-csrf_token\"><code class=\"xref std std-ttag docutils literal notranslate\"><span class=\"pre\">{%</span> <span class=\"pre\">csrf_token</span> <span class=\"pre\">%}</span></code></a>\ntemplate tag.</p></li>\n</ul>\n<p>Agora, vamos criar uma <code class=\"docutils literal notranslate\"><span class=\"pre\">view</span></code> Django que manipula os dados submetidos e faz algo com eles. Lembre-se, no <span class=\"xref std std-doc\">Tutorial 3</span>, criamos uma URLconf para a aplicação de enquete que inclui esta linha:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">polls/urls.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"n\">path</span><span class=\"p\">(</span><span class=\"s1\">&#39;&lt;int:question_id&gt;/vote/&#39;</span><span class=\"p\">,</span> <span class=\"n\">views</span><span class=\"o\">.</span><span class=\"n\">vote</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s1\">&#39;vote&#39;</span><span class=\"p\">),</span>\n</code></pre></figure>\n<p>Nós tambem criamos uma implementação falsa da função <code class=\"docutils literal notranslate\"><span class=\"pre\">vote()</span></code>. Vamos criar a versão real. Adicione o seguinte em <code class=\"docutils literal notranslate\"><span class=\"pre\">polls/views.py</span></code>:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">polls/views.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.http</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">HttpResponse</span><span class=\"p\">,</span> <span class=\"n\">HttpResponseRedirect</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.shortcuts</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">get_object_or_404</span><span class=\"p\">,</span> <span class=\"n\">render</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.urls</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">reverse</span>\n\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Choice</span><span class=\"p\">,</span> <span class=\"n\">Question</span>\n<span class=\"c1\"># ...</span>\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">vote</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">question_id</span><span class=\"p\">):</span>\n    <span class=\"n\">question</span> <span class=\"o\">=</span> <span class=\"n\">get_object_or_404</span><span class=\"p\">(</span><span class=\"n\">Question</span><span class=\"p\">,</span> <span class=\"n\">pk</span><span class=\"o\">=</span><span class=\"n\">question_id</span><span class=\"p\">)</span>\n    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">selected_choice</span> <span class=\"o\">=</span> <span class=\"n\">question</span><span class=\"o\">.</span><span class=\"n\">choice_set</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">pk</span><span class=\"o\">=</span><span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">POST</span><span class=\"p\">[</span><span class=\"s1\">&#39;choice&#39;</span><span class=\"p\">])</span>\n    <span class=\"k\">except</span> <span class=\"p\">(</span><span class=\"ne\">KeyError</span><span class=\"p\">,</span> <span class=\"n\">Choice</span><span class=\"o\">.</span><span class=\"n\">DoesNotExist</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Redisplay the question voting form.</span>\n        <span class=\"k\">return</span> <span class=\"n\">render</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"s1\">&#39;polls/detail.html&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;question&#39;</span><span class=\"p\">:</span> <span class=\"n\">question</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;error_message&#39;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;You didn&#39;t select a choice.&quot;</span><span class=\"p\">,</span>\n        <span class=\"p\">})</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">selected_choice</span><span class=\"o\">.</span><span class=\"n\">votes</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>\n        <span class=\"n\">selected_choice</span><span class=\"o\">.</span><span class=\"n\">save</span><span class=\"p\">()</span>\n        <span class=\"c1\"># Always return an HttpResponseRedirect after successfully dealing</span>\n        <span class=\"c1\"># with POST data. This prevents data from being posted twice if a</span>\n        <span class=\"c1\"># user hits the Back button.</span>\n        <span class=\"k\">return</span> <span class=\"n\">HttpResponseRedirect</span><span class=\"p\">(</span><span class=\"n\">reverse</span><span class=\"p\">(</span><span class=\"s1\">&#39;polls:results&#39;</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"n\">question</span><span class=\"o\">.</span><span class=\"n\">id</span><span class=\"p\">,)))</span>\n</code></pre></figure>\n<p>Este código inclui algumas coisas que ainda não foram cobertas neste tutorial:</p>\n<ul>\n<li><p><a class=\"reference internal\" href=\"/pt-br/3.2/ref/request-response/#django.http.HttpRequest.POST\" title=\"django.http.HttpRequest.POST\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">request.POST</span></code></a> é um objeto como dicionários que lhe permite acessar os dados submetidos pelos seus nomes chaves. Neste caso, <code class=\"docutils literal notranslate\"><span class=\"pre\">request.POST['choice']</span></code> retorna o ID da opção selecionada, como uma string. Os valores de <a class=\"reference internal\" href=\"/pt-br/3.2/ref/request-response/#django.http.HttpRequest.POST\" title=\"django.http.HttpRequest.POST\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">request.POST</span></code></a> são sempre strings.</p>\n<p>Note que Django também fornece <a class=\"reference internal\" href=\"/pt-br/3.2/ref/request-response/#django.http.HttpRequest.GET\" title=\"django.http.HttpRequest.GET\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">request.GET</span></code></a> para acesar dados GET da mesma forma – mas nós estamos usando attr:request.POST  &lt;django.http.HttpRequest.POST&gt; explicitamente no nosso código, para garantir que os dados só podem ser alterados por meio de uma chamada POST.</p>\n</li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">request.POST['choice']</span></code> irá levantar a exceção <a class=\"reference external\" href=\"https://docs.python.org/3/library/exceptions.html#KeyError\" title=\"(em Python v3.14)\"><code class=\"xref py py-exc docutils literal notranslate\"><span class=\"pre\">KeyError</span></code></a> caso uma <code class=\"docutils literal notranslate\"><span class=\"pre\">choice</span></code> não seja fornecida via dados POST. O código acima checa por <a class=\"reference external\" href=\"https://docs.python.org/3/library/exceptions.html#KeyError\" title=\"(em Python v3.14)\"><code class=\"xref py py-exc docutils literal notranslate\"><span class=\"pre\">KeyError</span></code></a> e re-exibe o formulário da enquete com as mensagens de erro se uma <code class=\"docutils literal notranslate\"><span class=\"pre\">choice</span></code> não for fornecida.</p></li>\n<li><p>Após incrementar uma opção, o código retorna um class:~django.http.HttpResponseRedirect em vez de um normal       <a class=\"reference internal\" href=\"/pt-br/3.2/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponse</span></code></a>.  <code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponseRedirect`</span></code> recebe um único argumento: a URL para o qual o usuário será redirecionado (veja o ponto seguinte para saber como construímos a URL, neste caso).</p>\n<p>As the Python comment above points out, you should always return an\n<a class=\"reference internal\" href=\"/pt-br/3.2/ref/request-response/#django.http.HttpResponseRedirect\" title=\"django.http.HttpResponseRedirect\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponseRedirect</span></code></a> after successfully dealing with\nPOST data. This tip isn’t specific to Django; it’s good Web development\npractice in general.</p>\n</li>\n<li><p>Estamos usando a função  <a class=\"reference internal\" href=\"/pt-br/3.2/ref/urlresolvers/#django.urls.reverse\" title=\"django.urls.reverse\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">reverse()</span></code></a> no construtor da  <a class=\"reference internal\" href=\"/pt-br/3.2/ref/request-response/#django.http.HttpResponseRedirect\" title=\"django.http.HttpResponseRedirect\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponseRedirect</span></code></a> neste exemplo. Essa função nos ajuda a evitar de colocar a URL dentro da view de maneira literal. A ele é dado então o nome da “view” que queremos que ele passe o controle e a parte variável do padrão de formato da URL que aponta para a “view”. Neste caso, usando o URLconf nós definimos em <a class=\"reference internal\" href=\"/pt-br/3.2/intro/tutorial03/\"><span class=\"doc\">Tutorial 3</span></a>, esta chamada de <a class=\"reference internal\" href=\"/pt-br/3.2/ref/urlresolvers/#django.urls.reverse\" title=\"django.urls.reverse\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">reverse()</span></code></a> irá retornar uma string como</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>onde o <code class=\"docutils literal notranslate\"><span class=\"pre\">3</span></code> é o valor para <code class=\"docutils literal notranslate\"><span class=\"pre\">question.id</span></code>. Esta URL redirecionada irá então chamar a view <code class=\"docutils literal notranslate\"><span class=\"pre\">'results'</span></code> para exibir a página final.</p>\n</li>\n</ul>\n<p>Como mencionado no <a class=\"reference internal\" href=\"/pt-br/3.2/intro/tutorial03/\"><span class=\"doc\">Tutorial 3</span></a>, <code class=\"docutils literal notranslate\"><span class=\"pre\">request</span></code> é um objeto <a class=\"reference internal\" href=\"/pt-br/3.2/ref/request-response/#django.http.HttpRequest\" title=\"django.http.HttpRequest\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpRequest</span></code></a> object. Para mais informações sobre objetos <a class=\"reference internal\" href=\"/pt-br/3.2/ref/request-response/#django.http.HttpRequest\" title=\"django.http.HttpRequest\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpRequest</span></code></a>, veja <a class=\"reference internal\" href=\"/pt-br/3.2/ref/request-response/\"><span class=\"doc\">request and response documentation</span></a>.</p>\n<p>Depois que alguém votar em uma enquete, a view <code class=\"docutils literal notranslate\"><span class=\"pre\">vote()</span></code>  redireciona para a página de resultados da enquete. Vamos escrever essa view:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">polls/views.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.shortcuts</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">get_object_or_404</span><span class=\"p\">,</span> <span class=\"n\">render</span>\n\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">results</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">question_id</span><span class=\"p\">):</span>\n    <span class=\"n\">question</span> <span class=\"o\">=</span> <span class=\"n\">get_object_or_404</span><span class=\"p\">(</span><span class=\"n\">Question</span><span class=\"p\">,</span> <span class=\"n\">pk</span><span class=\"o\">=</span><span class=\"n\">question_id</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">render</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"s1\">&#39;polls/results.html&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;question&#39;</span><span class=\"p\">:</span> <span class=\"n\">question</span><span class=\"p\">})</span>\n</code></pre></figure>\n<p>Isto é quase exatamente o mesmo que a view <code class=\"docutils literal notranslate\"><span class=\"pre\">detail()</span></code> do <span class=\"xref std std-doc\">Tutorial 3</span>. A única diferença é o nome do template. Iremos corrigir esta redundância depois.</p>\n<p>Agora, crie o template <code class=\"docutils literal notranslate\"><span class=\"pre\">polls/results.html</span></code>:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"html+django\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">polls/templates/polls/results.html</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Django template code\"><code><span class=\"p\">&lt;</span><span class=\"nt\">h1</span><span class=\"p\">&gt;</span><span class=\"cp\">{{</span> <span class=\"nv\">question.question_text</span> <span class=\"cp\">}}</span><span class=\"p\">&lt;/</span><span class=\"nt\">h1</span><span class=\"p\">&gt;</span>\n\n<span class=\"p\">&lt;</span><span class=\"nt\">ul</span><span class=\"p\">&gt;</span>\n<span class=\"cp\">{%</span> <span class=\"k\">for</span> <span class=\"nv\">choice</span> <span class=\"k\">in</span> <span class=\"nv\">question.choice_set.all</span> <span class=\"cp\">%}</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">li</span><span class=\"p\">&gt;</span><span class=\"cp\">{{</span> <span class=\"nv\">choice.choice_text</span> <span class=\"cp\">}}</span> -- <span class=\"cp\">{{</span> <span class=\"nv\">choice.votes</span> <span class=\"cp\">}}</span> vote<span class=\"cp\">{{</span> <span class=\"nv\">choice.votes</span><span class=\"o\">|</span><span class=\"nf\">pluralize</span> <span class=\"cp\">}}</span><span class=\"p\">&lt;/</span><span class=\"nt\">li</span><span class=\"p\">&gt;</span>\n<span class=\"cp\">{%</span> <span class=\"k\">endfor</span> <span class=\"cp\">%}</span>\n<span class=\"p\">&lt;/</span><span class=\"nt\">ul</span><span class=\"p\">&gt;</span>\n\n<span class=\"p\">&lt;</span><span class=\"nt\">a</span> <span class=\"na\">href</span><span class=\"o\">=</span><span class=\"s\">&quot;</span><span class=\"cp\">{%</span> <span class=\"k\">url</span> <span class=\"s1\">&#39;polls:detail&#39;</span> <span class=\"nv\">question.id</span> <span class=\"cp\">%}</span><span class=\"s\">&quot;</span><span class=\"p\">&gt;</span>Vote again?<span class=\"p\">&lt;/</span><span class=\"nt\">a</span><span class=\"p\">&gt;</span>\n</code></pre></figure>\n<p>Agora, vá para <code class=\"docutils literal notranslate\"><span class=\"pre\">/polls/1/</span></code> no seu navegador e vote em uma enquete. Você deverá ver uma página de resultados que será atualizado cada vez que você votar. Se você enviar o formulário sem ter escolhido uma opção, você deverá ver a mensagem de erro.</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Nota</p>\n<p>O código da nossa view <code class=\"docutils literal notranslate\"><span class=\"pre\">vote()</span></code> tem um pequeno problema. Ele primeiro pega o objeto de <code class=\"docutils literal notranslate\"><span class=\"pre\">selected_choice</span></code> do banco de dados, calcula o novo valor de <code class=\"docutils literal notranslate\"><span class=\"pre\">votes</span></code> e os salva novamente. Se dois usuários do seu site tentarem votar <em>ao mesmo tempo</em>: o mesmo valor, digamos 42, será obtido para <code class=\"docutils literal notranslate\"><span class=\"pre\">votes</span></code>. Então, para ambos usuários, o novo valor 43 é calculado e salvo, quando o valor esperado seria 44.</p>\n<p>Isto é chamado de <em>condição de concorrência</em>. Se você estiver interessado, pode ler <a class=\"reference internal\" href=\"/pt-br/3.2/ref/models/expressions/#avoiding-race-conditions-using-f\"><span class=\"std std-ref\">Avoiding race conditions using F()</span></a> para aprender como resolver este problema.</p>\n</aside>\n</section>\n<section id=\"use-generic-views-less-code-is-better\">\n<h2>Use views genéricas: Menos código é melhor<a class=\"heading-anchor\" href=\"#use-generic-views-less-code-is-better\"><span class=\"visually-hidden\">Link para este cabeçalho</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=\"/pt-br/3.2/intro/tutorial03/\"><span class=\"doc\">Tutorial 3</span></a>) and <code class=\"docutils literal notranslate\"><span class=\"pre\">results()</span></code>\nviews are very short – and, as mentioned above, redundant. The <code class=\"docutils literal notranslate\"><span class=\"pre\">index()</span></code>\nview, which displays a list of polls, is similar.</p>\n<p>Estas views representam um caso comum do desenvolvimento Web básico: obter dados do banco de dados de acordo com um parâmetro passado na URL, carregar um\ntemplate e devolvê-lo renderizado. Por isto ser muito comum, o Django fornece um atalho, chamado sistema de “views genéricas”.</p>\n<p>Views genéricas abstraem padrões comuns para um ponto onde você nem precisa\nescrever código Python para escrever uma aplicação.</p>\n<p>Let’s convert our poll app to use the generic views system, so we can delete a\nbunch of our own code. We’ll have to take a few steps to make the conversion.\nWe will:</p>\n<ol class=\"arabic simple\">\n<li><p>Converta o URLconf.</p></li>\n<li><p>Delete algumas das views antigas, desnecessárias.</p></li>\n<li><p>Introduz novas views baseadas em views genéricas Django’s.</p></li>\n</ol>\n<p>Leia para obter mais detalhes.</p>\n<aside class=\"admonition-why-the-code-shuffle admonition\">\n<p class=\"admonition-title\">Por que o código ficou embarralhado?</p>\n<p>Geralmente, quando estiver escrevendo uma aplicação Django, você vai avaliar se views genéricas são uma escolha adequada para o seu problema e você irá utilizá-las desde o início em vez de refatorar seu código no meio do caminho. Mas este tutorial intencionalmente tem focado em escrever views “do jeito mais difícil” até agora, para concentrarmos nos conceitos fundamentais.</p>\n<p>Você deve saber matemática básica antes de você começar a usar uma calculadora.</p>\n</aside>\n<section id=\"amend-urlconf\">\n<h3>Corrija URLconf<a class=\"heading-anchor\" href=\"#amend-urlconf\"><span class=\"visually-hidden\">Link para este cabeçalho</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Em primeiro lugar, abra a URLconf <code class=\"docutils literal notranslate\"><span class=\"pre\">polls/urls.py</span></code> e modifique para ficar assim:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">polls/urls.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.urls</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">path</span>\n\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">.</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">views</span>\n\n<span class=\"n\">app_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;polls&#39;</span>\n<span class=\"n\">urlpatterns</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"n\">path</span><span class=\"p\">(</span><span class=\"s1\">&#39;&#39;</span><span class=\"p\">,</span> <span class=\"n\">views</span><span class=\"o\">.</span><span class=\"n\">IndexView</span><span class=\"o\">.</span><span class=\"n\">as_view</span><span class=\"p\">(),</span> <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s1\">&#39;index&#39;</span><span class=\"p\">),</span>\n    <span class=\"n\">path</span><span class=\"p\">(</span><span class=\"s1\">&#39;&lt;int:pk&gt;/&#39;</span><span class=\"p\">,</span> <span class=\"n\">views</span><span class=\"o\">.</span><span class=\"n\">DetailView</span><span class=\"o\">.</span><span class=\"n\">as_view</span><span class=\"p\">(),</span> <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s1\">&#39;detail&#39;</span><span class=\"p\">),</span>\n    <span class=\"n\">path</span><span class=\"p\">(</span><span class=\"s1\">&#39;&lt;int:pk&gt;/results/&#39;</span><span class=\"p\">,</span> <span class=\"n\">views</span><span class=\"o\">.</span><span class=\"n\">ResultsView</span><span class=\"o\">.</span><span class=\"n\">as_view</span><span class=\"p\">(),</span> <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s1\">&#39;results&#39;</span><span class=\"p\">),</span>\n    <span class=\"n\">path</span><span class=\"p\">(</span><span class=\"s1\">&#39;&lt;int:question_id&gt;/vote/&#39;</span><span class=\"p\">,</span> <span class=\"n\">views</span><span class=\"o\">.</span><span class=\"n\">vote</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s1\">&#39;vote&#39;</span><span class=\"p\">),</span>\n<span class=\"p\">]</span>\n</code></pre></figure>\n<p>Note que o nome da descrição encontrada nas strings de caminhos da segundo e da terceira descrição foi alterado de <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;question_id&gt;</span></code> para <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;pk&gt;</span></code>.</p>\n</section>\n<section id=\"amend-views\">\n<h3>Views alteradas<a class=\"heading-anchor\" href=\"#amend-views\"><span class=\"visually-hidden\">Link para este cabeçalho</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Em seguida, vamos remover a nossas velhas views <code class=\"docutils literal notranslate\"><span class=\"pre\">index</span></code>, `` detail``, e <code class=\"docutils literal notranslate\"><span class=\"pre\">results</span></code> e usar views genéricas do Django em seu lugar. Para fazer isso, abra o arquivo <code class=\"docutils literal notranslate\"><span class=\"pre\">polls/views.py</span></code> e alterar para:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">polls/views.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.http</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">HttpResponseRedirect</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.shortcuts</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">get_object_or_404</span><span class=\"p\">,</span> <span class=\"n\">render</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.urls</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">reverse</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.views</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">generic</span>\n\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Choice</span><span class=\"p\">,</span> <span class=\"n\">Question</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">IndexView</span><span class=\"p\">(</span><span class=\"n\">generic</span><span class=\"o\">.</span><span class=\"n\">ListView</span><span class=\"p\">):</span>\n    <span class=\"n\">template_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;polls/index.html&#39;</span>\n    <span class=\"n\">context_object_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;latest_question_list&#39;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">get_queryset</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;Return the last five published questions.&quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"n\">Question</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">order_by</span><span class=\"p\">(</span><span class=\"s1\">&#39;-pub_date&#39;</span><span class=\"p\">)[:</span><span class=\"mi\">5</span><span class=\"p\">]</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">DetailView</span><span class=\"p\">(</span><span class=\"n\">generic</span><span class=\"o\">.</span><span class=\"n\">DetailView</span><span class=\"p\">):</span>\n    <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">Question</span>\n    <span class=\"n\">template_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;polls/detail.html&#39;</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">ResultsView</span><span class=\"p\">(</span><span class=\"n\">generic</span><span class=\"o\">.</span><span class=\"n\">DetailView</span><span class=\"p\">):</span>\n    <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">Question</span>\n    <span class=\"n\">template_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;polls/results.html&#39;</span>\n\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">vote</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">question_id</span><span class=\"p\">):</span>\n    <span class=\"o\">...</span> <span class=\"c1\"># same as above, no changes needed.</span>\n</code></pre></figure>\n<p>Nós estamos usando duas views genéricas aqui: <a class=\"reference internal\" href=\"/pt-br/3.2/ref/class-based-views/generic-display/#django.views.generic.list.ListView\" title=\"django.views.generic.list.ListView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ListView</span></code></a> e <a class=\"reference internal\" href=\"/pt-br/3.2/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView\" title=\"django.views.generic.detail.DetailView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">DetailView</span></code></a>. Respectivamente, essas duas <code class=\"docutils literal notranslate\"><span class=\"pre\">views</span></code> abstraem o conceito de exibir uma lista de objetos e exibir uma página de detalhe para um tipo particular de objeto.</p>\n<ul class=\"simple\">\n<li><p>Cada “view” genérica precisa saber qual é o modelo que ela vai agir. Isto é fornecido usando o atributo <code class=\"docutils literal notranslate\"><span class=\"pre\">model</span></code>.</p></li>\n<li><p>A view genérica <a class=\"reference internal\" href=\"/pt-br/3.2/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView\" title=\"django.views.generic.detail.DetailView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">DetailView</span></code></a> espera o valor de chave primaria capturado da URL chamada <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;pk&quot;</span></code>, então mudamos <code class=\"docutils literal notranslate\"><span class=\"pre\">question_id</span></code> para <code class=\"docutils literal notranslate\"><span class=\"pre\">pk</span></code> para as views genérica.</p></li>\n</ul>\n<p>Por padrão, a “view” genérica <a class=\"reference internal\" href=\"/pt-br/3.2/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView\" title=\"django.views.generic.detail.DetailView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">DetailView</span></code></a>  utiliza um template chamado <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> <span class=\"pre\">Em</span> <span class=\"pre\">nosso</span> <span class=\"pre\">caso,</span> <span class=\"pre\">ela</span> <span class=\"pre\">vai</span> <span class=\"pre\">utilizar</span> <span class=\"pre\">o</span> <span class=\"pre\">template</span> <span class=\"pre\">`&quot;polls/question_detail.html&quot;</span></code>. O atributo <code class=\"docutils literal notranslate\"><span class=\"pre\">template_name</span></code> é usado para indicar ao Django para usar um nome de template em vez de auto gerar uma nome de template. Nós também especificamos <code class=\"docutils literal notranslate\"><span class=\"pre\">template_name</span></code> para a view de listagem de <code class=\"docutils literal notranslate\"><span class=\"pre\">results</span></code> – isto garante que a view de detalhe tem uma aparência quando renderizada, mesmo que sejam tanto um  class:~django.views.generic.detail.DetailView por trás das cenas.</p>\n<p>Semelhantemente, a view genérica <a class=\"reference internal\" href=\"/pt-br/3.2/ref/class-based-views/generic-display/#django.views.generic.list.ListView\" title=\"django.views.generic.list.ListView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ListView</span></code></a> utiliza um template chamado <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;app</span> <span class=\"pre\">name&gt;/&lt;model</span> <span class=\"pre\">name&gt;_list.html</span></code>; usamos <code class=\"docutils literal notranslate\"><span class=\"pre\">template_name</span></code> para informar <a class=\"reference internal\" href=\"/pt-br/3.2/ref/class-based-views/generic-display/#django.views.generic.list.ListView\" title=\"django.views.generic.list.ListView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ListView</span></code></a> para usar nossos templates <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;polls/index.html&quot;</span></code>.</p>\n<p>Nas partes anteriores deste tutorial, os templates tem sido fornecidos com um contexto que contém as variáveis <code class=\"docutils literal notranslate\"><span class=\"pre\">question</span></code> e <code class=\"docutils literal notranslate\"><span class=\"pre\">latest_question_list</span></code>. Para a <code class=\"docutils literal notranslate\"><span class=\"pre\">DetailView</span></code> a variavel <code class=\"docutils literal notranslate\"><span class=\"pre\">question</span></code> é fornecida automaticamente – já que estamos usando um modelo Django (<code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code>), Django é capaz de determinar um nome apropriado para a variável de contexto. Contudo, para ListView, a variável de contexto gerada automaticamente é <code class=\"docutils literal notranslate\"><span class=\"pre\">question_list</span></code>. Para sobrescrever nós fornecemos o atributo <code class=\"docutils literal notranslate\"><span class=\"pre\">context_object_name</span></code>, especificando que queremos usar <code class=\"docutils literal notranslate\"><span class=\"pre\">latest_question_list</span></code> no lugar. Como uma abordagem alternativa, você poderia mudar seus templates para casar o novo padrão das variáveis de contexto – mas é muito fácil dizer para o Django usar a variável que você quer.</p>\n<p>Execute o servidor, e use sua nova aplicação de enquete baseada em generic views.</p>\n<p>Para detalhes completos sobre views genéricas, veja a  <a class=\"reference internal\" href=\"/pt-br/3.2/topics/class-based-views/\"><span class=\"doc\">documentação de generic views documentation</span></a>.</p>\n<p>Quando você estiver confortável com formulários e generic views, leia a <a class=\"reference internal\" href=\"/pt-br/3.2/intro/tutorial05/\"><span class=\"doc\">parte 5 deste tutorial</span></a> para aprender sobre como testar nossa aplicação de enquete.</p>\n</section>\n</section>","rootId":"writing-your-first-django-app-part-4","toc":[{"title":"Write a minimal form","anchor":"write-a-minimal-form","children":[]},{"title":"Use views genéricas: Menos código é melhor","anchor":"use-generic-views-less-code-is-better","children":[{"title":"Corrija URLconf","anchor":"amend-urlconf","children":[]},{"title":"Views alteradas","anchor":"amend-views","children":[]}]}],"breadcrumbs":[{"docname":"intro/index","title":"Introdução","url":"/pt-br/3.2/intro/"}],"prev":{"docname":"intro/tutorial03","title":"Escrevendo sua primeira app Django, parte 3","url":"/pt-br/3.2/intro/tutorial03/"},"next":{"docname":"intro/tutorial05","title":"Escrevendo sua primeira aplicação Django, parte 5","url":"/pt-br/3.2/intro/tutorial05/"},"formats":{"html":"/pt-br/3.2/intro/tutorial04/","markdown":"/pt-br/3.2/intro/tutorial04.md","json":"/pt-br/3.2/intro/tutorial04.json"},"source":"https://github.com/django/django/blob/stable/3.2.x/docs/intro/tutorial04.txt","official":"https://docs.djangoproject.com/pt-br/3.2/intro/tutorial04/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0","1.11","1.10","1.9"],"inLocales":["en","zh-hans","fr","ja","id","it","pt-br","ko","es","el","pl"]}