{"title":"Escrevendo sua primeira aplicação Django, parte 4","version":"4.0","locale":"pt-br","docname":"intro/tutorial04","url":"/pt-br/4.0/intro/tutorial04/","canonical":"https://djangodocs.dev/pt-br/4.0/intro/tutorial04/","summary":"This tutorial begins where Tutorial 3 left off. We’re continuing the web-poll application and will focus on form processing and cutting down our code.","html":"<h1>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/4.0/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\" role=\"note\">\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/4.0/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\">&lt;form&gt;</code>:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"html+django\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\">polls/templates/polls/detail.html</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\">value</code> de cada botão radio está associado ao ID da opção.  O <code class=\"docutils literal notranslate\">name</code> de cada botão radio é a escolha <code class=\"docutils literal notranslate\">&quot;choice&quot;</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\">action</code> to <code class=\"docutils literal notranslate\">{% url 'polls:vote' question.id %}</code>, and we\nset <code class=\"docutils literal notranslate\">method=&quot;post&quot;</code>. Using <code class=\"docutils literal notranslate\">method=&quot;post&quot;</code> (as opposed to\n<code class=\"docutils literal notranslate\">method=&quot;get&quot;</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\">method=&quot;post&quot;</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\">forloop.counter</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/4.0/ref/templates/builtins/#std-templatetag-csrf_token\"><code class=\"xref std std-ttag docutils literal notranslate\">{% csrf_token %}</code></a>\ntemplate tag.</p></li>\n</ul>\n<p>Agora, vamos criar uma <code class=\"docutils literal notranslate\">view</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\">polls/urls.py</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>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</code></pre></figure>\n<p>Nós tambem criamos uma implementação falsa da função <code class=\"docutils literal notranslate\">vote()</code>. Vamos criar a versão real. Adicione o seguinte em <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\"><code class=\"docutils literal notranslate\">polls/views.py</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=\"nn\">django.http</span> <span class=\"kn\">import</span> HttpResponse<span class=\"p\">,</span> HttpResponseRedirect\n<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<span class=\"kn\">from</span> <span class=\"nn\">django.urls</span> <span class=\"kn\">import</span> reverse\n\n<span class=\"kn\">from</span> <span class=\"nn\">.models</span> <span class=\"kn\">import</span> Choice<span class=\"p\">,</span> Question\n<span class=\"c1\"># ...</span>\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    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\">try</span><span class=\"p\">:</span>\n        selected_choice <span class=\"o\">=</span> question<span class=\"o\">.</span>choice_set<span class=\"o\">.</span>get<span class=\"p\">(</span>pk<span class=\"o\">=</span>request<span class=\"o\">.</span>POST<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> Choice<span class=\"o\">.</span>DoesNotExist<span class=\"p\">):</span>\n        <span class=\"c1\"># Redisplay the question voting form.</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>\n            <span class=\"s1\">&#39;question&#39;</span><span class=\"p\">:</span> question<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        selected_choice<span class=\"o\">.</span>votes <span class=\"o\">+=</span> <span class=\"mi\">1</span>\n        selected_choice<span class=\"o\">.</span>save<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> HttpResponseRedirect<span class=\"p\">(</span>reverse<span class=\"p\">(</span><span class=\"s1\">&#39;polls:results&#39;</span><span class=\"p\">,</span> args<span class=\"o\">=</span><span class=\"p\">(</span>question<span class=\"o\">.</span>id<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/4.0/ref/request-response/#django.http.HttpRequest.POST\" title=\"django.http.HttpRequest.POST\"><code class=\"xref py py-attr docutils literal notranslate\">request.POST</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\">request.POST['choice']</code> retorna o ID da opção selecionada, como uma string. Os valores de <a class=\"reference internal\" href=\"/pt-br/4.0/ref/request-response/#django.http.HttpRequest.POST\" title=\"django.http.HttpRequest.POST\"><code class=\"xref py py-attr docutils literal notranslate\">request.POST</code></a> são sempre strings.</p>\n<p>Note que Django também fornece <a class=\"reference internal\" href=\"/pt-br/4.0/ref/request-response/#django.http.HttpRequest.GET\" title=\"django.http.HttpRequest.GET\"><code class=\"xref py py-attr docutils literal notranslate\">request.GET</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\">request.POST['choice']</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\">KeyError</code></a> caso uma <code class=\"docutils literal notranslate\">choice</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\">KeyError</code></a> e re-exibe o formulário da enquete com as mensagens de erro se uma <code class=\"docutils literal notranslate\">choice</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/4.0/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\">HttpResponse</code></a>.  <code class=\"xref py py-class docutils literal notranslate\">HttpResponseRedirect`</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/4.0/ref/request-response/#django.http.HttpResponseRedirect\" title=\"django.http.HttpResponseRedirect\"><code class=\"xref py py-class docutils literal notranslate\">HttpResponseRedirect</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/4.0/ref/urlresolvers/#django.urls.reverse\" title=\"django.urls.reverse\"><code class=\"xref py py-func docutils literal notranslate\">reverse()</code></a> no construtor da  <a class=\"reference internal\" href=\"/pt-br/4.0/ref/request-response/#django.http.HttpResponseRedirect\" title=\"django.http.HttpResponseRedirect\"><code class=\"xref py py-class docutils literal notranslate\">HttpResponseRedirect</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/4.0/intro/tutorial03/\"><span class=\"doc\">Tutorial 3</span></a>, esta chamada de <a class=\"reference internal\" href=\"/pt-br/4.0/ref/urlresolvers/#django.urls.reverse\" title=\"django.urls.reverse\"><code class=\"xref py py-func docutils literal notranslate\">reverse()</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\">3</code> é o valor para <code class=\"docutils literal notranslate\">question.id</code>. Esta URL redirecionada irá então chamar a view <code class=\"docutils literal notranslate\">'results'</code> para exibir a página final.</p>\n</li>\n</ul>\n<p>Como mencionado no <a class=\"reference internal\" href=\"/pt-br/4.0/intro/tutorial03/\"><span class=\"doc\">Tutorial 3</span></a>, <code class=\"docutils literal notranslate\">request</code> é um objeto <a class=\"reference internal\" href=\"/pt-br/4.0/ref/request-response/#django.http.HttpRequest\" title=\"django.http.HttpRequest\"><code class=\"xref py py-class docutils literal notranslate\">HttpRequest</code></a> object. Para mais informações sobre objetos <a class=\"reference internal\" href=\"/pt-br/4.0/ref/request-response/#django.http.HttpRequest\" title=\"django.http.HttpRequest\"><code class=\"xref py py-class docutils literal notranslate\">HttpRequest</code></a>, veja <a class=\"reference internal\" href=\"/pt-br/4.0/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\">vote()</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\">polls/views.py</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=\"nn\">django.shortcuts</span> <span class=\"kn\">import</span> get_object_or_404<span class=\"p\">,</span> render\n\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    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/results.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>Isto é quase exatamente o mesmo que a view <code class=\"docutils literal notranslate\">detail()</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\">polls/results.html</code>:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"html+django\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\">polls/templates/polls/results.html</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\">/polls/1/</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\">vote()</code> tem um pequeno problema. Ele primeiro pega o objeto de <code class=\"docutils literal notranslate\">selected_choice</code> do banco de dados, calcula o novo valor de <code class=\"docutils literal notranslate\">votes</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\">votes</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/4.0/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\">detail()</code> (from <a class=\"reference internal\" href=\"/pt-br/4.0/intro/tutorial03/\"><span class=\"doc\">Tutorial 3</span></a>) and <code class=\"docutils literal notranslate\">results()</code>\nviews are very short – and, as mentioned above, redundant. The <code class=\"docutils literal notranslate\">index()</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>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\" role=\"note\">\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\">polls/urls.py</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\">polls/urls.py</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=\"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>IndexView<span class=\"o\">.</span>as_view<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:pk&gt;/&#39;</span><span class=\"p\">,</span> views<span class=\"o\">.</span>DetailView<span class=\"o\">.</span>as_view<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:pk&gt;/results/&#39;</span><span class=\"p\">,</span> views<span class=\"o\">.</span>ResultsView<span class=\"o\">.</span>as_view<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>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\">&lt;question_id&gt;</code> para <code class=\"docutils literal notranslate\">&lt;pk&gt;</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\">index</code>, `` detail``, e <code class=\"docutils literal notranslate\">results</code> e usar views genéricas do Django em seu lugar. Para fazer isso, abra o arquivo <code class=\"docutils literal notranslate\">polls/views.py</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\">polls/views.py</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=\"nn\">django.http</span> <span class=\"kn\">import</span> HttpResponseRedirect\n<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<span class=\"kn\">from</span> <span class=\"nn\">django.urls</span> <span class=\"kn\">import</span> reverse\n<span class=\"kn\">from</span> <span class=\"nn\">django.views</span> <span class=\"kn\">import</span> generic\n\n<span class=\"kn\">from</span> <span class=\"nn\">.models</span> <span class=\"kn\">import</span> Choice<span class=\"p\">,</span> Question\n\n\n<span class=\"k\">class</span> <span class=\"nc\">IndexView</span><span class=\"p\">(</span>generic<span class=\"o\">.</span>ListView<span class=\"p\">):</span>\n    template_name <span class=\"o\">=</span> <span class=\"s1\">&#39;polls/index.html&#39;</span>\n    context_object_name <span class=\"o\">=</span> <span class=\"s1\">&#39;latest_question_list&#39;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">get_queryset</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;Return the last five published questions.&quot;&quot;&quot;</span>\n        <span class=\"k\">return</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\n\n<span class=\"k\">class</span> <span class=\"nc\">DetailView</span><span class=\"p\">(</span>generic<span class=\"o\">.</span>DetailView<span class=\"p\">):</span>\n    model <span class=\"o\">=</span> Question\n    template_name <span class=\"o\">=</span> <span class=\"s1\">&#39;polls/detail.html&#39;</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">ResultsView</span><span class=\"p\">(</span>generic<span class=\"o\">.</span>DetailView<span class=\"p\">):</span>\n    model <span class=\"o\">=</span> Question\n    template_name <span class=\"o\">=</span> <span class=\"s1\">&#39;polls/results.html&#39;</span>\n\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=\"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/4.0/ref/class-based-views/generic-display/#django.views.generic.list.ListView\" title=\"django.views.generic.list.ListView\"><code class=\"xref py py-class docutils literal notranslate\">ListView</code></a> e <a class=\"reference internal\" href=\"/pt-br/4.0/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView\" title=\"django.views.generic.detail.DetailView\"><code class=\"xref py py-class docutils literal notranslate\">DetailView</code></a>. Respectivamente, essas duas <code class=\"docutils literal notranslate\">views</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\">model</code>.</p></li>\n<li><p>A view genérica <a class=\"reference internal\" href=\"/pt-br/4.0/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView\" title=\"django.views.generic.detail.DetailView\"><code class=\"xref py py-class docutils literal notranslate\">DetailView</code></a> espera o valor de chave primaria capturado da URL chamada <code class=\"docutils literal notranslate\">&quot;pk&quot;</code>, então mudamos <code class=\"docutils literal notranslate\">question_id</code> para <code class=\"docutils literal notranslate\">pk</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/4.0/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView\" title=\"django.views.generic.detail.DetailView\"><code class=\"xref py py-class docutils literal notranslate\">DetailView</code></a>  utiliza um template chamado <code class=\"docutils literal notranslate\">&lt;app name&gt;/&lt;model name&gt;_detail.html`. Em nosso caso, ela vai utilizar o template `&quot;polls/question_detail.html&quot;</code>. O atributo <code class=\"docutils literal notranslate\">template_name</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\">template_name</code> para a view de listagem de <code class=\"docutils literal notranslate\">results</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/4.0/ref/class-based-views/generic-display/#django.views.generic.list.ListView\" title=\"django.views.generic.list.ListView\"><code class=\"xref py py-class docutils literal notranslate\">ListView</code></a> utiliza um template chamado <code class=\"docutils literal notranslate\">&lt;app name&gt;/&lt;model name&gt;_list.html</code>; usamos <code class=\"docutils literal notranslate\">template_name</code> para informar <a class=\"reference internal\" href=\"/pt-br/4.0/ref/class-based-views/generic-display/#django.views.generic.list.ListView\" title=\"django.views.generic.list.ListView\"><code class=\"xref py py-class docutils literal notranslate\">ListView</code></a> para usar nossos templates <code class=\"docutils literal notranslate\">&quot;polls/index.html&quot;</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\">question</code> e <code class=\"docutils literal notranslate\">latest_question_list</code>. Para a <code class=\"docutils literal notranslate\">DetailView</code> a variavel <code class=\"docutils literal notranslate\">question</code> é fornecida automaticamente – já que estamos usando um modelo Django (<code class=\"docutils literal notranslate\">Question</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\">question_list</code>. Para sobrescrever nós fornecemos o atributo <code class=\"docutils literal notranslate\">context_object_name</code>, especificando que queremos usar <code class=\"docutils literal notranslate\">latest_question_list</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/4.0/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/4.0/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/4.0/intro/"}],"prev":{"docname":"intro/tutorial03","title":"Escrevendo sua primeira app Django, parte 3","url":"/pt-br/4.0/intro/tutorial03/"},"next":{"docname":"intro/tutorial05","title":"Escrevendo sua primeira aplicação Django, parte 5","url":"/pt-br/4.0/intro/tutorial05/"},"formats":{"html":"/pt-br/4.0/intro/tutorial04/","markdown":"/pt-br/4.0/intro/tutorial04.md","json":"/pt-br/4.0/intro/tutorial04.json"},"source":"https://github.com/django/django/blob/stable/4.0.x/docs/intro/tutorial04.txt","official":"https://docs.djangoproject.com/pt-br/4.0/intro/tutorial04/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0","1.11","1.10","1.9"],"inLocales":["en","zh-hans","fr","ja","id","it","pt-br","ko","es","el","pl"]}