{"title":"Escrevendo sua primeira aplicação Django, parte 4","version":"1.9","locale":"pt-br","docname":"intro/tutorial04","url":"/pt-br/1.9/intro/tutorial04/","canonical":"https://djangodocs.dev/pt-br/1.9/intro/tutorial04/","summary":"Este tutorial inicia-se onde o Tutorial 3 terminou. Estamos continuando a aplicação web de enquete e será sobre uma forma simples de processamento de formulário e a…","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>Este tutorial inicia-se onde o <span class=\"xref std std-doc\">Tutorial 3</span> terminou. Estamos continuando a aplicação web de enquete e será sobre uma forma simples de processamento de formulário e a redução de nosso código.</p>\n<section id=\"write-a-simple-form\">\n<h2>Crie um formulário simples<a class=\"heading-anchor\" href=\"#write-a-simple-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>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>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>Nós definimos o parâmetro <code class=\"docutils literal notranslate\"><span class=\"pre\">action</span></code> do formulário para <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>, e definimos <code class=\"docutils literal notranslate\"><span class=\"pre\">method=post</span></code>. Usando <code class=\"docutils literal notranslate\"><span class=\"pre\">method=post</span></code> (em vez de do <code class=\"docutils literal notranslate\"><span class=\"pre\">method=get</span></code>) é muito importante, porque o ato de enviar este formulário irá alterar dados do lado servidor. Sempre que criar um formulário que modifique os dados do lado do servidor, utilize <code class=\"docutils literal notranslate\"><span class=\"pre\">method=&quot;post&quot;</span></code>. Esta dica não é específica do Django; mais sim uma boa  prática para o desenvolvimento é Web.</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>Desde que nós estamos criando um formulário POST (que pode ter o efeito de modificação de dados), nós temos que se preocupar com Cross Site Request Forgeries. Felizmente, você não precisa se preocupar muito, porque o Django vem com um sistema muito fácil de usar para se proteger contra isto. Em suma, todas as formas de POST que são direcionados a URLs internas devem usar uma tag <a class=\"reference internal\" href=\"/pt-br/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></code></a> de template.</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=\"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>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=\"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>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/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> é 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/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> são sempre strings.</p>\n<p>Note que Django também fornece <a class=\"reference internal\" href=\"/pt-br/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> 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/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>.  <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>Como o comentário Python acima salienta, você deve sempre retornar uma      <a class=\"reference internal\" href=\"/pt-br/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> depois de lidar com sucesso com dados POST. Esta dica não é específica do Django; mais sim uma boa prática para o desenvolvimento Web.</p>\n</li>\n<li><p>Estamos usando, neste exemplo, a função <a class=\"reference internal\" href=\"/pt-br/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> no construtor da classe <a class=\"reference internal\" href=\"/pt-br/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>. Essa função ajuda a evitar escrevermos a URL na função da view. O nome da view a qual queremos passar o controle e a porção variável do pattern da URL que aponta para essa view são informados. Neste caso, usando o URLConf, criado no <a class=\"reference internal\" href=\"/pt-br/1.9/intro/tutorial03/\"><span class=\"doc\">Tutorial 3</span></a>, esta chamada a  <a class=\"reference internal\" href=\"/pt-br/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> 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/1.9/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/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. Para mais informações sobre objetos <a class=\"reference internal\" href=\"/pt-br/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>, veja <a class=\"reference internal\" href=\"/pt-br/1.9/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=\"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>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>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>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/1.9/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>As views <code class=\"docutils literal notranslate\"><span class=\"pre\">detail()</span></code> (de <a class=\"reference internal\" href=\"/pt-br/1.9/intro/tutorial03/\"><span class=\"doc\">Tutorial 3</span></a>) e <code class=\"docutils literal notranslate\"><span class=\"pre\">results()</span></code> são muito simples – e, como mencionado acima, redundantes. A view <code class=\"docutils literal notranslate\"><span class=\"pre\">index()</span></code>, que mostra a lista de votações, é 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>Vamos converter a nossa aplicação de enquete para utilizar o sistema de views\ngenéricas, por isso podemos excluir um monte do nosso próprio código. Iremos\napenas ter que executar alguns passos para fazer a conversão. Nós iremos:</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=\"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 que o nome do padrão correspondente na regexes do segundo e terceiro padrão mudou 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=\"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>Nós estamos usando duas views genéricas aqui: <a class=\"reference internal\" href=\"/pt-br/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> e <a class=\"reference internal\" href=\"/pt-br/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>. 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/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> 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/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>  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 aparencia quando rederizada, 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/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> 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>; Nós usamos  <code class=\"docutils literal notranslate\"><span class=\"pre\">template_name</span></code> para informar <a class=\"reference internal\" href=\"/pt-br/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> 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 model Django (<code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code>), Django is able to determine an appropriate name for the context variable. However, for ListView, the automatically generated context variable is <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> attribute, specifying that we want to use <code class=\"docutils literal notranslate\"><span class=\"pre\">latest_question_list</span></code> instead. As an alternative approach, you could change your templates to match the new default context variables – but it’s a lot easier to just tell Django to use the variable you want.</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/1.9/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/1.9/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":"Crie um formulário simples","anchor":"write-a-simple-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/1.9/intro/"}],"prev":{"docname":"intro/tutorial03","title":"Escrevendo sua primeira app Django, parte 3","url":"/pt-br/1.9/intro/tutorial03/"},"next":{"docname":"intro/tutorial05","title":"Escrevendo sua primeira aplicação Django, parte 5","url":"/pt-br/1.9/intro/tutorial05/"},"formats":{"html":"/pt-br/1.9/intro/tutorial04/","markdown":"/pt-br/1.9/intro/tutorial04.md","json":"/pt-br/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/pt-br/1.9/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","fr","ja","id","pt-br","es"]}