diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:42:52 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:42:52 -0500 |
commit | 074785cea106179cb3305637055ab0a009ca74f2 (patch) | |
tree | e6ae371cccd642aa2b67f39752a2cdf1fd4eb040 /files/pt-br/learn/server-side | |
parent | da78a9e329e272dedb2400b79a3bdeebff387d47 (diff) | |
download | translated-content-074785cea106179cb3305637055ab0a009ca74f2.tar.gz translated-content-074785cea106179cb3305637055ab0a009ca74f2.tar.bz2 translated-content-074785cea106179cb3305637055ab0a009ca74f2.zip |
initial commit
Diffstat (limited to 'files/pt-br/learn/server-side')
29 files changed, 10616 insertions, 0 deletions
diff --git a/files/pt-br/learn/server-side/django/admin_site/index.html b/files/pt-br/learn/server-side/django/admin_site/index.html new file mode 100644 index 0000000000..28b83e9d78 --- /dev/null +++ b/files/pt-br/learn/server-side/django/admin_site/index.html @@ -0,0 +1,364 @@ +--- +title: 'Tutorial Django Parte 4: Django admin site' +slug: Learn/Server-side/Django/Admin_site +tags: + - Aprender + - Artigo + - Iniciante + - Python + - Tutorial + - django + - django_admin + - lado servidor (server-side) +translation_of: Learn/Server-side/Django/Admin_site +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Models", "Learn/Server-side/Django/Home_page", "Learn/Server-side/Django")}}</div> + +<p class="summary">Agora que criamos modelos para o site da <a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/Tutorial_website_biblioteca_local">LocalLibrary</a>, usaremos o site do Django Admin para adicionar alguns dados de livros "reais". Primeiro, mostraremos como registrar os modelos no site de administração, depois mostraremos como fazer login e criar alguns dados. No final do artigo, mostraremos algumas maneiras de melhorar ainda mais a apresentação do site Admin.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré-requisitos:</th> + <td>Primeiro complete: <a href="/en-US/docs/Learn/Server-side/Django/Models">Tutorial Django Parte 3: Usando modelos</a>.</td> + </tr> + <tr> + <th scope="row">Objetivo:</th> + <td>Para entender os benefícios e limitações do site de administração do Django, use-o para criar alguns registros para nossos modelos.</td> + </tr> + </tbody> +</table> + +<h2 id="Visão_Geral">Visão Geral</h2> + +<p>O aplicativo de administração do Django pode usar seus modelos para criar automaticamente uma área de site que você possa usar para criar, visualizar, atualizar e excluir registros. Isso pode poupar muito tempo durante o desenvolvimento, tornando muito fácil testar seus modelos e ter uma ideia de se você tem os dados corretos. O aplicativo administrativo também pode ser útil para gerenciar dados em produção, dependendo do tipo de site. O projeto Django o recomenda apenas para gerenciamento interno de dados (ou seja, apenas para uso por administradores ou pessoas internas à sua organização), pois a abordagem centrada no modelo não é necessariamente a melhor interface possível para todos os usuários e expõe muitos detalhes desnecessários sobre os modelos.</p> + +<p>Toda a configuração necessária para incluir o aplicativo admin em seu site foi feita automaticamente quando você criou o <a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/skeleton_website">esqueleto do projeto</a> (para obter informações sobre as dependências reais necessárias, consulte a <a href="https://docs.djangoproject.com/pt-br/2.1/ref/contrib/admin/">documentação do Django aqui</a>). Como resultado, tudo o que você precisa fazer para adicionar seus modelos ao aplicativo administrativo é registrá-los. No final deste artigo, forneceremos uma breve demonstração de como você pode configurar ainda mais a área de administração para exibir melhor nossos dados de modelo.</p> + +<p>Depois de registrar os modelos, mostraremos como criar um novo "superusuário", acessar o site e criar alguns livros, autores, instâncias de livros e gêneros. Isso será útil para testar as visualizações e os modelos que começaremos a criar no próximo tutorial.</p> + +<h2 id="Registrando_modelos">Registrando modelos</h2> + +<p>Primeiro, abra o admin.py no aplicativo de catálogo (/locallibrary/catalog/admin.py). Atualmente parece com isso - note que ele já importa <code>django.contrib.admin</code>:</p> + +<pre class="brush: python notranslate">from django.contrib import admin + +# Register your models here. +</pre> + +<p>Registre os modelos copiando o seguinte texto na parte inferior do arquivo. Este código simplesmente importa os modelos e, em seguida, chama <code>admin.site.register</code> para registrar cada um deles.</p> + +<pre class="brush: python notranslate">from catalog.models import Author, Genre, Book, BookInstance + +admin.site.register(Book) +admin.site.register(Author) +admin.site.register(Genre) +admin.site.register(BookInstance) +</pre> + +<div class="note">Nota: Se você aceitou o desafio de criar um modelo para representar a linguagem natural de um livro (<a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/Models">consulte o artigo do tutorial de modelos</a>), importe-o e registre-o também!</div> + +<p>Essa é a maneira mais simples de registrar um modelo ou modelos no site. O site de administração é altamente personalizável e falaremos mais sobre as outras maneiras de registrar seus modelos mais abaixo.</p> + +<h2 id="Criando_um_super_usuário">Criando um super usuário</h2> + +<p>Para fazer login no site de administração, precisamos de uma conta de usuário com o status da equipe ativado. Para visualizar e criar registros, também precisamos que esse usuário tenha permissões para gerenciar todos os nossos objetos. Você pode criar uma conta "superusuário" que tenha acesso total ao site e todas as permissões necessárias usando <strong>manage.py</strong>.</p> + +<p>Chame o seguinte comando, no mesmo diretório que manage.py, para criar o superusuário. Você será solicitado a digitar um nome de usuário, endereço de e-mail e senha forte.</p> + +<pre class="brush: bash notranslate">python3 manage.py createsuperuser +</pre> + +<p>Quando esse comando for concluído, um novo superusuário será adicionado ao banco de dados. Agora reinicie o servidor de desenvolvimento para que possamos testar o login:</p> + +<pre class="brush: bash notranslate">python3 manage.py runserver + +</pre> + +<h2 id="Fazendo_o_login_e_usando_o_site">Fazendo o login e usando o site</h2> + +<p>Para fazer login no site, abra o URL /<em>admin</em> (e.g. <a href="http://127.0.0.1:8000/admin/">http://127.0.0.1:8000/admin</a>) e insira suas novas credenciais de usuário e senha de superusuário (você será redirecionado para a página de login e, em seguida, de volta para o URL /<em>admin </em>depois de inserir seus detalhes).</p> + +<p>Esta parte do site exibe todos os nossos modelos, agrupados por aplicativo instalado. Você pode clicar no nome de um modelo para ir a uma tela que lista todos os seus registros associados e clicar nos registros para editá-los. Você também pode clicar diretamente no link Adicionar ao lado de cada modelo para começar a criar um registro desse tipo.</p> + +<p><img alt="Admin Site - Home page" src="https://mdn.mozillademos.org/files/13975/admin_home.png" style="display: block; height: 634px; margin: 0px auto; width: 998px;"></p> + +<p>Clique no link Adicionar à direita de Books para criar um novo livro (isso exibirá um diálogo muito parecido com o abaixo). Observe como os títulos de cada campo, o tipo de widget usado e o <code>help_text</code> (se houver) correspondem aos valores especificados no modelo.</p> + +<p>Digite valores para os campos. Você pode criar novos autores ou gêneros pressionando o botão + ao lado dos respectivos campos (ou selecione os valores existentes nas listas, se você já os criou). Quando estiver pronto, você pode pressionar<strong> SALVAR, Salvar</strong> <strong>e adicionar </strong>outro ou S<strong>alvar e continuar editando</strong> para salvar o registro.</p> + +<p><img alt="Admin Site - Book Add" src="https://mdn.mozillademos.org/files/13979/admin_book_add.png" style="border-style: solid; border-width: 1px; display: block; height: 780px; margin: 0px auto; width: 841px;"></p> + +<div class="note"> +<p>Observação: neste ponto, gostaríamos que você passasse algum tempo adicionando alguns livros, autores e gêneros (por exemplo, Fantasia) à sua inscrição. Certifique-se de que cada autor e gênero inclua alguns livros diferentes (isso tornará suas visualizações de lista e detalhes mais interessantes quando forem implementadas posteriormente na série de artigos).</p> +</div> + +<p>Quando terminar de adicionar livros, clique no link <strong>Home</strong> no marcador superior para ser levado de volta à página principal do administrador. Então clique no link <strong>Books </strong> para exibir a lista atual de livros (ou em um dos outros links para ver outras listas de modelos). Agora que você adicionou alguns livros, a lista pode ser semelhante à captura de tela abaixo. O título de cada livro é exibido; este é o valor retornado no modelo do livro pelo método <code>__str__()</code> que especificamos no último artigo.</p> + +<p><img alt="Admin Site - List of book objects" src="https://mdn.mozillademos.org/files/13935/admin_book_list.png" style="border-style: solid; border-width: 1px; display: block; height: 407px; margin: 0px auto; width: 1000px;"></p> + +<p>Nessa lista, você pode excluir livros marcando a caixa de seleção ao lado do livro que não deseja, selecionando a ação excluir ... na lista suspensa Ação e pressionando o botão Ir. Você também pode adicionar novos livros pressionando o botão <strong>ADD BOOK</strong>. </p> + +<p>Você pode editar um livro selecionando seu nome no link. A página de edição de um livro, mostrada abaixo, é quase idêntica à página "Adicionar". As principais diferenças são o título da página (Change book) e a adição de botões <strong>Delete</strong>, <strong>HISTORY</strong> e <strong>VIEW ON SITE</strong> (este último botão aparece porque definimos o método <code>get_absolute_url()</code> em nosso modelo).</p> + +<p><img alt="Admin Site - Book Edit" src="https://mdn.mozillademos.org/files/13977/admin_book_modify.png" style="border-style: solid; border-width: 1px; display: block; height: 780px; margin: 0px auto; width: 841px;"></p> + +<p>Agora navegue de volta para o <strong>Home</strong> page (usando o link Home, a trilha de navegação) e, em seguida, <strong>Author</strong> e listas de <strong>Genre</strong> — você já deve ter criado a partir de quando adicionou os novos livros, mas fique à vontade para adicionar um pouco mais.</p> + +<p>O que você não terá é qualquer instância do livro, porque elas não são criadas a partir de livros (embora você possa criar <code>Book</code> a partir de <code>BookInstance</code> — esta é a natureza da <code>ForeignKey</code> field). Navegue de volta para a<em> Página inicial</em> e pressione o botão <em>Adicionar</em> associado para exibir a tela <em>Adicionar instância</em> do livro abaixo. Observe o ID grande e globalmente exclusivo, que pode ser usado para identificar separadamente uma única cópia de um livro na biblioteca.</p> + +<p><img alt="Admin Site - BookInstance Add" src="https://mdn.mozillademos.org/files/13981/admin_bookinstance_add.png" style="border-style: solid; border-width: 1px; display: block; height: 514px; margin: 0px auto; width: 863px;"></p> + +<p>Crie vários desses registros para cada um de seus livros. Defina o status como <em>Disponível</em> para pelo menos alguns registros e <em>Em empréstimo</em> para outros. Se o status <strong>não </strong>for <em>Disponível</em>, defina também uma <em>data de vencimento</em> futura.</p> + +<p>É isso aí! Agora você aprendeu como configurar e usar o site de administração. Você também criou registros para <code>Book</code>, <code>BookInstance</code>, <code>Genre</code>, e <code>Author</code> que poderemos usar assim que criarmos nossas próprias visualizações e modelos.</p> + +<h2 id="Configuração_Avançada">Configuração Avançada</h2> + +<p>O Django faz um bom trabalho ao criar um site de administração básico usando as informações dos modelos registrados:</p> + +<ul> + <li>Cada modelo possui uma lista de registros individuais, identificados pela string criada com o método <code>__str__()</code> do modelo, e vinculado a visualizações de views/forms para edição. Por padrão, essa exibição tem um menu de ação na parte superior que você pode usar para executar operações de exclusão em massa nos registros.</li> + <li>Os formulários de registro de detalhes do modelo para edição e adição de registros contêm todos os campos do modelo, dispostos verticalmente em sua ordem de declaração. </li> +</ul> + +<p>Você pode personalizar ainda mais a interface para torná-la ainda mais fácil de usar. Algumas das coisas que você pode fazer são:</p> + +<ul> + <li>List views: + <ul> + <li>Adicionar adicional fields/information exibido para cada registro.</li> + <li>Adicione filtros para selecionar quais registros são listados, com base na data ou em algum outro valor de seleção (e.g. Book loan status).</li> + <li>Adicione opções adicionais ao menu de ações nas exibições de lista e escolha onde esse menu é exibido no formulário.</li> + </ul> + </li> + <li>Detail views + <ul> + <li>Escolha quais campos exibir (ou excluir), junto com sua ordem, agrupamento, se eles são editáveis, o widget usado, a orientação etc.</li> + <li>Adicione campos relacionados a um registro para permitir a edição imediata (por exemplo, adicione a capacidade de adicionar e editar registros de livros enquanto cria o registro de autor).</li> + </ul> + </li> +</ul> + +<p>In this section we're going to look at a few changes that will improve the interface for our <em>LocalLibrary</em>, including adding more information to <code>Book</code> and <code>Author</code> model lists, and improving the layout of their edit views. We won't change the <code>Language</code> and <code>Genre</code> model presentation because they only have one field each, so there is no real benefit in doing so!</p> + +<p>You can find a complete reference of all the admin site customisation choices in <a href="https://docs.djangoproject.com/en/2.0/ref/contrib/admin/">The Django Admin site</a> (Django Docs).</p> + +<h3 id="Registrando_uma_classe_ModelAdmin">Registrando uma classe ModelAdmin</h3> + +<p>Para alterar como um modelo é exibido na interface de administração, você define uma classe ModelAdmin (que descreve o layout) e registra-o no modelo.</p> + +<p>Vamos começar com o <code>Author</code> model. Abra <strong>admin.py</strong> no aplicativo de catálogo (/locallibrary/catalog/admin.py). Comente o seu registro original (prefixo com um #) para o <code>Author</code> model:</p> + +<pre class="brush: js notranslate"># admin.site.register(Author)</pre> + +<p>Agora adicione um novo <code>AuthorAdmin</code> e registre como mostrado abaixo.</p> + +<pre class="brush: python notranslate"># Define the admin class +class AuthorAdmin(admin.ModelAdmin): + pass + +# Register the admin class with the associated model +admin.site.register(Author, AuthorAdmin) +</pre> + +<p>Agora vamos adicionar as classes <code>ModelAdmin</code> para <code>Book</code>, e <code>BookInstance</code>. Precisamos novamente comentar os registros originais:</p> + +<pre class="brush: js notranslate"># admin.site.register(Book) +# admin.site.register(BookInstance)</pre> + +<p>Agora, para criar e registrar os novos modelos; para o propósito desta demonstração, vamos usar o <code>@register</code> decorador para registrar os modelos (isso faz exatamente a mesma coisa que <code>admin.site.register()</code> sintaxe):</p> + +<pre class="brush: python notranslate"># Register the Admin classes for Book using the decorator +@admin.register(Book) +class BookAdmin(admin.ModelAdmin): + pass + +# Register the Admin classes for BookInstance using the decorator +@admin.register(BookInstance) +class BookInstanceAdmin(admin.ModelAdmin): + pass +</pre> + +<p>Atualmente todas as nossas classes administrativas estão vazias (veja <code>pass</code>) então o comportamento do administrador não será alterado! Agora podemos estendê-los para definir nosso comportamento administrativo específico do modelo.</p> + +<h3 id="Configure_list_views">Configure list views</h3> + +<p>A LocalLibrary atualmente lista todos os autores usando o nome do objeto gerado a partir do método <code>__str__()</code> do modelo. Isso é bom quando você tem apenas alguns autores, mas quando você tem muitos, você pode acabar tendo duplicatas. Para diferenciá-los, ou apenas porque você quer mostrar informações mais interessantes sobre cada autor, você pode usar <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display">list_display</a> para adicionar campos adicionais à vista.</p> + +<p>Substitua seu<code>AuthorAdmin</code> class com o código abaixo. Os nomes de campo a serem exibidos na lista são declarados em uma <em>tupla </em>na ordem requerida, conforme mostrado (esses são os mesmos nomes especificados em seu modelo original).</p> + +<pre class="brush: python notranslate">class AuthorAdmin(admin.ModelAdmin): + list_display = ('last_name', 'first_name', 'date_of_birth', 'date_of_death') +</pre> + +<p>Agora navegue até a lista de autores em seu site. Os campos acima devem agora ser exibidos, assim:</p> + +<p><img alt="Admin Site - Improved Author List" src="https://mdn.mozillademos.org/files/14023/admin_improved_author_list.png" style="border-style: solid; border-width: 1px; display: block; height: 302px; margin: 0px auto; width: 941px;"></p> + +<p>Para o nosso <code>Book</code> model nós vamos adicionalmente exibir o <code>author</code> e <code>genre</code>. O <code>author</code> é uma variável <code>ForeignKey</code> (um-para-um) relacionamento, e assim será representado pelo valor <code>__str__()</code> para o registro associado. Substitua o <code>BookAdmin</code> class com a versão abaixo.</p> + +<pre class="brush: python notranslate">class BookAdmin(admin.ModelAdmin): + list_display = ('title', 'author', 'display_genre') +</pre> + +<p>Infelizmente não podemos especificar diretamente a variável <font face="Consolas, Liberation Mono, Courier, monospace">genre </font>na <code>list_display</code> porque é um <code>ManyToManyField</code>(O Django evita isso porque há um grande "custo" de acesso ao banco de dados ao fazer isso). Em vez disso, vamos definir uma função <code>display_genre</code> para obter as informações como uma string (esta é a função que chamamos acima; vamos defini-lo abaixo).</p> + +<div class="note"> +<p>Nota: Obtendo o <code>genre</code> pode não ser uma boa ideia aqui, por causa do "custo" da operação do banco de dados. Estamos mostrando como as funções de chamada em seus modelos podem ser muito úteis por outros motivos - por exemplo, para adicionar um link <em>Apagar </em>ao lado de cada item da lista.</p> +</div> + +<p>Adicione o seguinte código ao seu <code>Book</code> model (<strong>models.py</strong>). Isso cria uma string a partir dos três primeiros valores da variavel <code>genre</code> (se existirem) e cria um <code>short_description</code> que pode ser usado no site administrativo para esse método.</p> + +<pre class="brush: python notranslate"> def display_genre(self): + """Create a string for the Genre. This is required to display genre in Admin.""" + return ', '.join(genre.name for genre in self.genre.all()[:3]) + + display_genre.short_description = 'Genre' +</pre> + +<p>Depois de salvar o modelo e o administrador atualizado, abra o site e vá para a página da lista Livros; você deve ver uma lista de livros como a abaixo:</p> + +<p><img alt="Admin Site - Improved Book List" src="https://mdn.mozillademos.org/files/14025/admin_improved_book_list.png" style="border-style: solid; border-width: 1px; display: block; height: 337px; margin: 0px auto; width: 947px;"></p> + +<p>O <code>Genre</code> model (e a <code>Language</code> model, se você definiu um) ambos têm um único campo, portanto, não faz sentido criar um modelo adicional para exibir campos adicionais.</p> + +<div class="note"> +<p>Nota: Vale a pena atualizar o<code>BookInstance</code> model list para mostrar pelo menos o status e a data de retorno esperada. Nós adicionamos isso como um desafio no final deste artigo!</p> +</div> + +<h3 id="Adicionando_list_filters">Adicionando list filters</h3> + +<p>Uma vez que você tenha muitos itens em uma lista, pode ser útil filtrar quais itens são exibidos. Isso é feito listando os campos no atributo <code>list_filter</code>. Substitua sua atual <code style="font-style: normal; font-weight: normal;">BookInstanceAdmin</code> class com o fragmento de código abaixo.</p> + +<pre class="brush: python notranslate">class BookInstanceAdmin(admin.ModelAdmin): +<strong> list_filter = ('status', 'due_back')</strong> +</pre> + +<p>A visualização de lista agora incluirá uma caixa de filtro à direita. Observe como você pode escolher datas e status para filtrar os valores:</p> + +<p><img alt="Admin Site - BookInstance List Filters" src="https://mdn.mozillademos.org/files/14037/admin_improved_bookinstance_list_filters.png" style="height: 528px; width: 960px;"></p> + +<h3 id="Organizando_o_layout_da_detail_view">Organizando o layout da detail view</h3> + +<p>Por padrão, as exibições detalhadas exibem todos os campos verticalmente, em sua ordem de declaração no modelo. Você pode alterar a ordem da declaração, quais campos são exibidos (ou excluídos), se as seções são usadas para organizar as informações, se os campos são exibidos horizontalmente ou verticalmente e até mesmo quais widgets de edição são usados nos formulários admin.</p> + +<div class="note"> +<p>Nota: Os modelos <em>LocalLibrary </em>são relativamente simples, portanto não é necessário alterar o layout; No entanto, faremos algumas alterações, só para mostrar como.</p> +</div> + +<h4 id="Controlando_quais_campos_são_exibidos">Controlando quais campos são exibidos</h4> + +<p>Atualize seu <code>AuthorAdmin</code> class para adicionar a linha <code>fields</code>, como mostrado abaixo (em negrito):</p> + +<pre class="brush: python notranslate">class AuthorAdmin(admin.ModelAdmin): + list_display = ('last_name', 'first_name', 'date_of_birth', 'date_of_death') +<strong> fields = ['first_name', 'last_name', ('date_of_birth', 'date_of_death')]</strong> +</pre> + +<p>O atributo <code>fields</code> lista apenas os campos que devem ser exibidos no formulário, em ordem. Os campos são exibidos verticalmente por padrão, mas serão exibidos horizontalmente se você agrupá-los posteriormente em uma tupla (conforme mostrado nos campos "data" acima).</p> + +<p>No seu site, acesse a visualização de detalhes do autor. Agora, ele deve aparecer como mostrado abaixo:</p> + +<p><img alt="Admin Site - Improved Author Detail" src="https://mdn.mozillademos.org/files/14027/admin_improved_author_detail.png" style="border-style: solid; border-width: 1px; display: block; height: 282px; margin: 0px auto; width: 928px;"></p> + +<div class="note"> +<p>Nota: você também pode usar o atributo <code>exclude</code> para declarar uma lista de atributos a serem excluídos do formulário (todos os outros atributos no modelo serão exibidos).</p> +</div> + +<h4 id="Seccionando_a_detail_view">Seccionando a detail view</h4> + +<p>Você pode adicionar "seções" para agrupar informações de modelo relacionadas dentro do formulário detalhado, usando o atributo <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.fieldsets">fieldsets</a>.</p> + +<p>Na <code>BookInstance</code> model temos informações relacionadas ao que o livro é (i.e. <code>name</code>, <code>imprint</code>, e <code>id</code>) e quando estará disponível (<code>status</code>, <code>due_back</code>). Podemos adicionar estes em diferentes seções, adicionando o texto em negrito para o nosso <code>BookInstanceAdmin</code> class. </p> + +<pre class="brush: python notranslate">@admin.register(BookInstance) +class BookInstanceAdmin(admin.ModelAdmin): + list_filter = ('status', 'due_back') + +<strong> fieldsets = ( + (None, { + 'fields': ('book', 'imprint', 'id') + }), + ('Availability', { + 'fields': ('status', 'due_back') + }), + )</strong></pre> + +<p>Cada seção tem seu próprio título (ou <code>None</code>,se você não quiser um título) e uma tupla associada de campos em um dicionário - o formato é complicado de descrever, mas bastante fácil de entender se você olhar o fragmento de código imediatamente acima.</p> + +<p>Agora, navegue até uma visualização de instância do livro em seu website; o formulário deve aparecer como mostrado abaixo:</p> + +<p><img alt="Admin Site - Improved BookInstance Detail with sections" src="https://mdn.mozillademos.org/files/14029/admin_improved_bookinstance_detail_sections.png" style="border-style: solid; border-width: 1px; display: block; height: 580px; margin: 0px auto; width: 947px;"></p> + +<h3 id="Edição_inline_de_registros_associados">Edição inline de registros associados</h3> + +<p>Às vezes, pode fazer sentido adicionar registros associados ao mesmo tempo. Por exemplo, pode fazer sentido ter as informações do livro e as informações sobre as cópias específicas que você tem na mesma página de detalhes.</p> + +<p>Você pode fazer isso declarando <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.inlines">inlines</a>, do tipo <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.TabularInline">TabularInline</a> (horizonal layout) or <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.StackedInline">StackedInline</a> (layout vertical, assim como o layout do modelo padrão). Você pode adicionar ao <code>BookInstance</code> informações inline para o nosso <code>Book</code> detalhe, adicionando as linhas abaixo em negrito perto do seu <code>BookAdmin</code>:</p> + +<pre class="brush: python notranslate"><strong>class BooksInstanceInline(admin.TabularInline): + model = BookInstance</strong> + +@admin.register(Book) +class BookAdmin(admin.ModelAdmin): + list_display = ('title', 'author', 'display_genre') +<strong> inlines = [BooksInstanceInline]</strong> +</pre> + +<p>Agora navegue até uma view pala um <code>Book</code> no seu site - na parte inferior, você verá as instâncias do livro relacionadas a este livro (imediatamente abaixo dos campos de gênero do livro):</p> + +<p><img alt="Admin Site - Book with Inlines" src="https://mdn.mozillademos.org/files/14033/admin_improved_book_detail_inlines.png" style="border-style: solid; border-width: 1px; display: block; height: 889px; margin: 0px auto; width: 937px;"></p> + +<p>Nesse caso, tudo o que fizemos foi declarar nossa classe inline tabular, que apenas adiciona todos os campos do modelo embutido. Você pode especificar todos os tipos de informações adicionais para o layout, incluindo os campos a serem exibidos, sua ordem, se eles são somente leitura ou não, etc. (veja <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.TabularInline">TabularInline</a> para maiores informações).</p> + +<div class="note"> +<p>Nota: Existem alguns limites dolorosos nesta funcionalidade! Na captura de tela acima, temos três instâncias de livros existentes, seguidas de três espaços reservados para novas instâncias de livros (que são muito semelhantes!). Seria melhor não ter instâncias do livro reserva por padrão e apenas adicioná-las com o link <strong>Add another Book instance</strong> , ou poder listar apenas <code>BookInstance</code>s como links não legíveis daqui. A primeira opção pode ser feita configurando atributo <code>extra</code> para 0 no <code>BooksInstanceInline</code> model, tente você mesmo.</p> +</div> + +<h2 id="Desafie-se">Desafie-se</h2> + +<p>Aprendemos muito nesta seção, então agora é hora de você tentar algumas coisas.</p> + +<ol> + <li>Para a <em>listview</em> <code>BookInstance</code>, adicione o código para exibir o livro, o status, a data de devolução e o id (em vez do texto padrão <code>__str__()</code>).</li> + <li>Adicione uma listagem <em>inline</em> de itens <code>Book</code> para a lista detalhada de <code>Author</code> usando a mesma abordagem que fizemos para <code>Book</code>/<code>BookInstance</code>.</li> +</ol> + +<ul> +</ul> + +<h2 id="Resumo">Resumo</h2> + +<p>É isso aí! Agora você aprendeu como configurar o site de administração na sua forma simples e aprimorada, como criar um superusuário, como navegar no site de administração e visualizar, excluir e atualizar registros. Ao longo do caminho você criou um monte de Livros, Instâncias de livros, Gêneros e Autores que poderemos listar e exibir assim que criarmos nossas próprias <em>views</em> e <em>templates</em>.</p> + +<h2 id="Leitura_adicional">Leitura adicional</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.0/intro/tutorial02/#introducing-the-django-admin">Escrevendo seu primeiro app Django, parte 2: Apresentando o Django Admin</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/contrib/admin/">O Django Admin site</a> (Django Docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Models", "Learn/Server-side/Django/Home_page", "Learn/Server-side/Django")}}</p> + +<h2 id="Neste_módulo">Neste módulo</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Introdução ao Django</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Configurando um ambiente de desenvolvimento Django</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django: Website de uma biblioteca local</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Tutorial Django Parte 2: Criando o escopo do website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial </a><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Parte 3: Utilizando models</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial </a><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Parte 4: Django admin site</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial </a><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Parte 5: Criando nossa página principal</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial </a><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Parte 6: Lista genérica e detail views</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial </a><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Parte 7: Framework de Sessões</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial </a><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Parte 8: Autenticação de Usuário e permissões</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial </a><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Parte 9: Trabalhando com formulários</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial </a><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Parte 10: Testando uma aplicação web Django</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial Django Parte 11: Implantando Django em produção</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Segurança de aplicações Django</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> diff --git a/files/pt-br/learn/server-side/django/ambiente_de_desenvolvimento/index.html b/files/pt-br/learn/server-side/django/ambiente_de_desenvolvimento/index.html new file mode 100644 index 0000000000..101d1a15ad --- /dev/null +++ b/files/pt-br/learn/server-side/django/ambiente_de_desenvolvimento/index.html @@ -0,0 +1,431 @@ +--- +title: Configurando um ambiente de desenvolvimento Django +slug: Learn/Server-side/Django/ambiente_de_desenvolvimento +tags: + - Ambiente de desenvolvimento + - Aprender + - Iniciante + - Instalação + - Introdução + - Python + - django +translation_of: Learn/Server-side/Django/development_environment +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Introduction", "Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django")}}</div> + +<p>Agora que você sabe para que serve o Django, nós iremos te mostrar como instalar, configurar e testar um ambiente de desenvolvimento no Windows, Linux (Ubuntu), e macOS - seja qual for o sistema operacional (SO) que você usar, este artigo deve fornecê-lo o suficiente para conseguir começar a desenvolver aplicativos Django.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré-requisitos:</th> + <td>Saber como usar um teminal / linha de comando. Saber instalar softwares em seu sistema operacional.</td> + </tr> + <tr> + <th scope="row">Objetivo:</th> + <td>Ter uma ambiente de desenvolvimento Django (2.0) operando em seu computador.</td> + </tr> + </tbody> +</table> + +<h2 id="Visão_geral_do_ambiente_de_desenvolvimento_Django">Visão geral do ambiente de desenvolvimento Django</h2> + +<p>Django facilita muito a configuração em seu computador para iniciar logo o desenvolvimento de aplicações web. Essa seção explica o que você ganha com o ambiente de desenvolvimento e fornece um plano geral de algumas opções de instalação e configuração. O resto do artigo explica o método <em>recomendado</em> de instalar o ambiente Django no Ubuntu, macOS e Windows e como testar.</p> + +<h3 id="O_que_é_o_ambiente_de_desenvolvimento_Django">O que é o ambiente de desenvolvimento Django?</h3> + +<p>O ambiente de desenvolvimento é uma instalação do Django em seu computador local para que você use-o para desenvolver e testar apps Django antes de implementá-los em um ambiente de produção</p> + +<p>A principal ferramenta que Django fornece é um conjunto de scripts Python para criar e trabalhar com projetos Django, junto com um simples<em> webserver de desenvolvimento</em> que você pode usar para testar localmente (i.e. no seu computador, não em um web server externo) aplicações web Django no seu navegador.</p> + +<p>Existem outras ferramentas secundárias que fazem parte do ambiente de desenvolvimento que não cobriremos aqui. Isso inclui coisas como um <a href="https://developer.mozilla.org/en-US/docs/Learn/Common_questions/Available_text_editors">editor de texto</a> ou IDE para edição de código, e uma ferramenta pra gerenciamento do controle de origem de códigos (como o <a href="https://git-scm.com/">Git</a>) para administrar com segurança as diferentes versões de seu sistema. Nós estamos assumindo que você já tem um editor de texto instalado.</p> + +<h3 id="Quais_são_as_opções_de_instalação_do_Django">Quais são as opções de instalação do Django?</h3> + +<p>Django é extremamente flexível em termos de como e onde ele pode ser instalado e configurado. Django pode:</p> + +<ul> + <li>Ser instalado em diferentes sistemas operacionais.</li> + <li>Ser instalado pelo código-fonte, pelo Python Package Index (PyPi) e, em muitos casos, pelo aplicativo gerenciador de pacotes do computador host.</li> + <li>Ser configurado para uso de um dos vários bancos de dados, que também podem ser instalados e configurados separadamente.</li> + <li>Operar no ambiente principal do sistema Python ou em ambientes virtuais Python, separadamente.</li> +</ul> + +<p>Cada opção requer leves diferenças de configuração e instalação. As subseções abaixo explicam algumas de suas escolhas. No resto do artigo nós iremos mostrar como instalar o Django em um pequeno número de sistemas operacionais. No resto do módulo, assumiremos que você tenha instalado o Django em sua máquina.</p> + +<div class="note"> +<p><strong>Nota</strong>: Outras possíveis opções de instalação são cobertas pela documentação oficial do Django. Nós linkamos os <a href="#Veja_também" id="See_also">documents adequados abaixo</a>.</p> +</div> + +<h4 id="Quais_sistemas_operacionais_suportam_Django">Quais sistemas operacionais suportam Django?</h4> + +<p>Aplicações web Django podem rodar em quase todas as maquinas que suportam a linguagem de programação Python 3. Windows, macOS, Linux/Unix e Solaris são alguns desses SO's. A maioria dos computadores atuais devem ter o desempenho necessário para operar Django.</p> + +<p>Neste artigo, iremos fornecer instruções para Windows, macOS a Linux/Unix.</p> + +<h4 id="Qual_versão_de_Python_deve_ser_usada">Qual versão de Python deve ser usada?</h4> + +<p>Nós recomendamos que use a mais recente versão disponível — no momento que escrevo é Python 3.7.1.</p> + +<p>Se necessário, versões a partir de Python 3.5 podem ser usadas (o suporte para Python 3.5 irá acabar em versões futuras).</p> + +<div class="note"> +<p><strong>Nota</strong>: Python 2.7 não pode ser usado com Django 2.1 (A série Django 1.11.x é a última que suporta Python 2.7).</p> +</div> + +<h4 id="Onde_posso_baixar_o_Django">Onde posso baixar o Django?</h4> + +<p>Existem três lugares para fazer o download do Django:</p> + +<ul> + <li>Python Package Repository (PyPi), usando o comando <em>pip</em>. Esta é a melhor forma de conseguir a última versão estável do Django.</li> + <li>A partir de uma versão do gerenciador de pacotes de seu computador. Distribuições de Django que são empacotadas com o sistema operacional oferecem uma "instalação familiar". Contudo, note que a versão disponível pode ser um pouco antiga, e que pode ser instalada apenas dentro do sistema ambiente do Python (podendo ser algo que você não queira).</li> + <li>Instalar pelo código-fonte. Você pode pegar a última versão acessível do código do Django e instalar no seu computador. Não é recomendado aos iniciantes, mas é necessário quando você se sentir pronto para contribuir com o Django.</li> +</ul> + +<p>Este artigo mostra a instalação pelo Pypi, pois queremos a última versão estável do Django.</p> + +<h4 id="Qual_banco_de_dados">Qual banco de dados?</h4> + +<p>Django suporta (principalmente) quatro bancos de dados (PostgreSQL, MySQL, Oracle, e SQLite ), contudo, existem bibliotecas community que fornecem níveis variados de suporte para outros populares bancos de dados SQL e NoSQL. Nós recomendamos que você use o mesmo banco de dados tanto para produção quanto para desenvolvimento (embora o Django abstraia muitas das diferenças dos bancos de dados usando seu Object-Relational Mapper (ORM), ainda há <a href="https://docs.djangoproject.com/en/2.1/ref/databases/">problemas em potencial</a> que é melhor evitar).</p> + +<p>Neste artigo (e na maior parte deste módulo) nós usaremos o banco de Dados <em>SQL</em><em>ite</em>, que armazena dados em um arquivo. SQLite é destinado para uso sendo um banco de dados leve e que não consegue suportar uma demanda muito alta. Entretanto, uma excelente opção para aplicações de que focam em leitura de dados.</p> + +<div class="note"> +<p><strong>Nota:</strong> Django é configurado por padrão a usar SQLite ao iniciar seu projeto usando as ferramentas padrão (django-admin). É uma ótima escolha quando você está começando, porque não requer configurações adicionais ou instalações.</p> +</div> + +<h4 id="Instalar_em_todo_o_sistema_ou_em_um_ambiente_virtual_Python">Instalar em todo o sistema ou em um ambiente virtual Python?</h4> + +<p>Quando você instala Python 3 você pega um único ambiente global que é compartilhado por todo o código Python 3. Enquanto você pode instalar qualquer pacote Python que quiser no ambiente, você pode instalar apenas uma versão particular de cada pacote por vez.</p> + +<div class="note"> +<p><strong>Nota</strong>: Aplicações Python instaladas no ambiente global têm forte potêncial de entrar em conflito entre si (i.e. se elas dependem de versões diferentes do mesmo pacote).</p> +</div> + +<p>Se você instalar Django no ambiente padrão/global você só será capaz de ter uma versão do Django em seu computador. Isto pode ser um problema se você quer criar novos websites (usando a versão mais recente do Django) enquanto ainda realiza manutenção nos websites que dependem das versões antigas.</p> + +<p>Pensando nisso, desenvolvedores experientes de Python/Django normalmente executam apps Python dentro de um <em>ambiente virtual Python </em>independente. Isso permite usar diferentes ambientes Django em um único computador. A própria equipe de desenvolvedores Django recomenda o uso de ambientes virtuais Python!</p> + +<p>Esse módulo assume que você instalou o Django em um ambiente virtual, nós iremos mostrá-lo como fazer isso logo abaixo.</p> + +<h2 id="Instalando_Python_3">Instalando Python 3</h2> + +<p>Você deve ter Python instalado em seu sistema operacional para usar Django. Se você estiver usando <em>Python 3</em>, também precisará da ferramenta <a href="https://pypi.python.org/pypi">Python Package Index</a> — <em>pip3 </em>— que é usada para administrar (instalar, editar, remover) pacotes/bibliotecas Python usadas por Django e seus outros aplicativos Python.</p> + +<p>Essa parte explica brevemente como você pode checar quais versões de Python estão disponíveis e instalar novas versões se necessário (em Ubuntu 18.04, macOS e Windows 10).</p> + +<div class="note"> +<p><strong>Nota</strong>: Dependendo da sua plataforma, você também pode instalar Python/pip3 no seu sistema operacional através de seu próprio gerenciador de pacotes ou por outros mecanismos. Para a maioria das plataformas, você pode baixar os arquivos necessários para instalação em <a href="https://www.python.org/downloads/">https://www.python.org/downloads/</a> e instalá-los usando o método específico da plataforma em questão.</p> +</div> + +<h3 id="Ubuntu_18.04">Ubuntu 18.04</h3> + +<p>Ubuntu Linux 18.04 LTS inclui Python 3.6.6 por padrão. Você pode confirmar isso executando o seguinte comando no Terminal:</p> + +<pre class="brush: bash notranslate"><span style="line-height: 1.5;">python3 -V + Python 3.6.6</span></pre> + +<p>Contudo, o Python Package Index, que você precisará para instalar pacotes para Python 3 (incluindo Django), <strong>não</strong> está disponível por padrão. Você pode instalar pip3 pelo Terminal usando:</p> + +<pre class="brush: bash notranslate">sudo apt install python3-pip +</pre> + +<h3 id="macOS">macOS</h3> + +<p>macOS "El Capitan" e outras versões mais recentes não incluem Python 3. Você pode confirmar isto executando os comandos abaixo no Terminal:</p> + +<pre class="brush: bash notranslate"><span style="line-height: 1.5;">python3 -V + </span>-bash: python3: command not found</pre> + +<p>Você pode instalar Python 3 (com a ferramenta pip3) facilmente em <a href="https://www.python.org/">python.org</a>:</p> + +<ol> + <li>Baixe o instalador exigido: + <ol> + <li>Acesse <a href="https://www.python.org/downloads/">https://www.python.org/downloads/</a></li> + <li>Selecione o botão <strong>Download Python 3.7.1</strong> (o número exato da versão menor pode diferir).</li> + </ol> + </li> + <li>Localize o arquivo usando <em>o Finder</em>, e clique duplo no arquivo do pacote. Siga os passos da instalação dos prompts.</li> +</ol> + +<p>Agora você pode confirmar se tudo deu certo checando o<em> Python 3 </em>como mostrado abaixo:</p> + +<pre class="brush: bash notranslate"><span style="line-height: 1.5;">python3 -V + Python 3.7.1</span> +</pre> + +<p>Você pode checar se<em> pip3</em> está instalado listando todos os pacotes disponíveis.</p> + +<pre class="brush: bash notranslate">pip3 list</pre> + +<h3 id="Windows_10">Windows 10</h3> + +<p>Windows não inclui Python por padrão, mas você pode instalá-lo facilmente (com a ferramenta<em> pip3</em>) em <a href="https://www.python.org/">python.org</a>:</p> + +<ol> + <li>Baixe o instalador exigido: + <ol> + <li>Acesse <a href="https://www.python.org/downloads/">https://www.python.org/downloads/</a></li> + <li>Selecione o botão <strong>Download Python 3.7.1</strong> (o número exato da versão menor pode diferir).</li> + </ol> + </li> + <li>Instale Python com um clique duplo no arquivo baixado e siga a instalação dos prompts.</li> + <li>Tenha certeza que a caixa "Add Python to PATH" está checada.</li> +</ol> + +<p>Você pode verificar se o Python 3 foi instalado colocando o seguinte texto no Prompt de Comando</p> + +<pre class="brush: bash notranslate"><span style="line-height: 1.5;">py -3 -V + Python 3.7.1</span> +</pre> + +<p>O instalador do Windows incorpora<em> pip3</em> (o administrador de pacotes Python) por padrão. Você pode facilmente listar os pacotes instalados com o comando abaixo:</p> + +<pre class="brush: bash notranslate"><span style="line-height: 1.5;">pip3 list</span> +</pre> + +<div class="note"> +<p><strong>Nota</strong>: O instalador deve ter configurado tudo que você precisa antes para esse comando funcionar. Se for exibida uma mensagem que Python não encontrou, você pode ter esquecido de adicioná-lo ao PATH do Sistema. Você pode fazer isso exexutando o instalador novamente, selecionando "Modify", e checando a caixa chamada " Add Python to environment variables " na segunda tela.</p> +</div> + +<h2 id="Usando_Django_em_um_ambiente_virtual_Python">Usando Django em um ambiente virtual Python</h2> + +<p>As bibliotecas que nós iremos usar para criar nossos ambientes virtuais são <a href="https://virtualenvwrapper.readthedocs.io/en/latest/index.html">virtualenvwrapper</a> (Linux e macOS) e <a href="https://pypi.python.org/pypi/virtualenvwrapper-win">virtualenvwrapper-win</a> (Windows), sendo que ambas usam a ferramenta <a href="https://developer.mozilla.org/en-US/docs/Python/Virtualenv">virtualenv</a>. as bibliotecas criam uma interface consistente para manusear interfaces em todas plataformas;</p> + +<h3 id="Instalando_o_software_de_ambiente_virtual">Instalando o software de ambiente virtual</h3> + +<h4 id="Instalação_do_ambiente_virtual_no_Ubuntu">Instalação do ambiente virtual no Ubuntu</h4> + +<p>Após instalar Python e pip, você pode instalar<em> virtualenvwrapper</em> (que inclui<em>virtualenv</em>). O guia oficial para a instalação pode ser encontrado <a href="http://virtualenvwrapper.readthedocs.io/en/latest/install.html">aqui</a>, ou siga as instruções abaixo.</p> + +<p>Instale a ferramenta usando<em> pip3</em>:</p> + +<pre class="brush: bash notranslate"><code>sudo pip3 install virtualenvwrapper</code></pre> + +<p>Em seguida, adicione as linhas abaixo no fim de seu arquivo shell startup (este é um arquivo oculto nomeado <strong>.bashrc </strong>em seu diretório home). Isto coloca a localização de onde seus ambientes virtuais deveriam estar, a localização dos diretórios para desevolvimento de projetos e a localização do script instalado com o pacote.</p> + +<pre class="brush: bash notranslate"><code>export WORKON_HOME=$HOME/.virtualenvs +export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3 +export VIRTUALENVWRAPPER_VIRTUALENV_ARGS=' -p /usr/bin/python3 ' +export PROJECT_HOME=$HOME/Devel +source /usr/local/bin/virtualenvwrapper.sh</code> +</pre> + +<div class="note"> +<p><strong>Note</strong>: As variáveis <code>VIRTUALENVWRAPPER_PYTHON</code> e <code>VIRTUALENVWRAPPER_VIRTUALENV_ARGS </code>apontam para a localização em uma instalação normal de Python 3, e <code>source /usr/local/bin/virtualenvwrapper.sh</code> aponta para a localização normal do script <code>virtualenvwrapper.sh</code> Se<em> virtualenv</em> não funciona quando você testa, uma coisa a se verificar é se o Python e o script estão na localização esperada (e então alterar o arquivo de startup com os caminhos corretos).<br> + <br> + Você pode encontrar a localização correta no seu sistema usando os comandos <code>which virtualenvwrapper.sh</code> e <code>which python3</code>.</p> +</div> + +<p>Recarregue o arquivo de startup executando o seguinte comando no Terminal:</p> + +<pre class="brush: bash notranslate"><code>source ~/.bashrc</code></pre> + +<p>Após executar o comando, você deveria ver scripts como esses:</p> + +<pre class="brush: bash notranslate"><code>virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/premkproject +virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/postmkproject +... +virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/preactivate +virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/postactivate +virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/get_env_details</code> +</pre> + +<p>Agora você pode criar um novo ambiente virtual com o comando <code>mkvirtualenv</code>.</p> + +<h4 id="Instalação_do_ambiente_virtual_no_macOS">Instalação do ambiente virtual no macOS</h4> + +<p>Instalar<em> virtualenvwrapper</em> no macOS é quase a mesma coisa que instalar no Ubuntu (novamente, você pode seguir as instruções do <a href="http://virtualenvwrapper.readthedocs.io/en/latest/install.html">guia oficial de instalação </a>ou as instruções abaixo).</p> + +<p>Instale<em> virtualenvwrapper</em> (e<em> virtualenv</em>) usando<em> pip</em> como abaixo.</p> + +<pre class="brush: bash notranslate"><code>sudo pip3 install virtualenvwrapper</code></pre> + +<p>Então adicione as seguintes linhas no arquivo de startup do seu shell.</p> + +<pre class="brush: bash notranslate"><code>export WORKON_HOME=$HOME/.virtualenvs +export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3 +export PROJECT_HOME=$HOME/Devel +source /usr/local/bin/virtualenvwrapper.sh</code></pre> + +<div class="note"> +<p><strong>Note</strong>: A variável <code>VIRTUALENVWRAPPER_PYTHON</code> aponta para uma localização em uma instalação normal de Python 3, e <code>source /usr/local/bin/virtualenvwrapper.sh</code> aponta para a localização comum do script <code>virtualenvwrapper.sh</code>. Se <em>virtualenv</em> não funciona quando você testa, uma coisa a se verificar é se o Python e o script estão na localização esperada (e então alterar o arquivo de startup com os caminhos corretos).</p> + +<p>Por exemplo, uma instalação teste no macOS termina com as seguintes linhas no arquivo de startup:</p> + +<pre class="brush: bash notranslate">export WORKON_HOME=$HOME/.virtualenvs +export VIRTUALENVWRAPPER_PYTHON=/Library/Frameworks/Python.framework/Versions/3.7/bin/python3 +export PROJECT_HOME=$HOME/Devel +source /Library/Frameworks/Python.framework/Versions/3.7/bin/virtualenvwrapper.sh</pre> + +<p>Você pode encontrar a localização correta no seu sistema usando os comandos <code>which virtualenvwrapper.sh</code> e <code>which python3</code>.</p> +</div> + +<p>São as mesmas linhas digitadas no Ubuntu, mas o arquivo de startup é diferente nomeado como <strong>.bash_profile</strong>, oculto no seu diretório home.</p> + +<div class="note"> +<p><strong>Nota</strong>: Se você não acha o arquivo <strong>.bash_profile</strong> pelo finder, você pode abir pelo terminal usando o <em>nano</em>.</p> + +<p>Os comandos são como esses:</p> + +<pre class="notranslate"><code>cd ~ # Navigate to my home directory +ls -la #List the content of the directory. YOu should see .bash_profile +nano .bash_profile # Open the file in the nano text editor, within the terminal +# Scroll to the end of the file, and copy in the lines above +# Use Ctrl+X to exit nano, Choose Y to save the file.</code> +</pre> +</div> + +<p>Atualize o arquivo de startup fazendo o seguinte chamado no terminal:</p> + +<pre class="brush: bash notranslate"><code>source ~/.bash_profile</code></pre> + +<p>Com isso, você deveria ver alguns scripts na tela do terminal sendo executados (os mesmos scripts da instalação no Ubuntu). Agora você está apto a criar um novo ambiente virtual pelo comando <code>mkvirtualenv</code>.</p> + +<h4 id="Instalação_do_ambiente_virtual_no_Windows_10">Instalação do ambiente virtual no Windows 10</h4> + +<p>Instalar <a href="https://pypi.python.org/pypi/virtualenvwrapper-win">virtualenvwrapper-win</a> é ainda mais simples que instalar <em>virtualenvwrapper</em>, porque você não precisa configurar onde a ferramenta armazena as informações do ambiente virtual (pois é um valor padrão). Tudo que você precisa fazer é rodar o seguinte comando no Prompt de Comando.</p> + +<pre class="notranslate"><code>pip3 install virtualenvwrapper-win</code></pre> + +<p>Agora você pode criar um novo ambiente virtual com o comando <code>mkvirtualenv</code>.</p> + +<h3 id="Criando_um_ambiente_virtual">Criando um ambiente virtual</h3> + +<p>Uma vez que você tenha instalado <em>virtualenvwrapper</em> ou <em>virtualenvwrapper-win</em>, trabalhar com ambientes virtuais é bem parecido em todas as plataformas.</p> + +<p>Agora você pode criar um novo ambiente virtual com o comando <code>mkvirtualenv</code>. Ao executar esse comando, você verá o ambiente sendo configurado (o que você verá varia um pouco em cada plataforma). Quando o comando encerrar a configuração, o ambiente virtual estará ativo — você pode ver isso porque no topo do prompt (aquela barra de título do programa) estará escrito o nome do ambiente entre colchetes (abaixo nós mostramos como é a criação do ambiente no Ubuntu, mas o comando é igual para o Windows/macOS).</p> + +<pre class="notranslate"><code>$ mkvirtualenv my_django_environment + +Running virtualenv with interpreter /usr/bin/python3 +... +virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/t_env7/bin/get_env_details +(my_django_environment) ubuntu@ubuntu:~$</code> +</pre> + +<p>Agora que você está em um ambiente virtual, você pode instalar Django e iniciar o desenvolvimento.</p> + +<div class="note"> +<p><strong>Nota</strong>: De agora em diante, esse artigo (na verdade todo o módulo) está supondo que todos os comando serão executados em um ambiente virtual Python como o que configuramos acima.</p> +</div> + +<h3 id="Usando_um_ambiente_virtual">Usando um ambiente virtual</h3> + +<p>Existem apenas alguns poucos comandos que você deveria conhecer (há mais comandos que você pode encontrar na documentação da ferramenta, porém, os comandos abaixo serão os que você usará regularmente):</p> + +<ul> + <li><code>deactivate</code> — Encerra o ambiente virtual Python corrente.</li> + <li><code>workon</code> — Lista ambientes virtuais disponíveis.</li> + <li><code>workon name_of_environment</code> — Ativa o ambiente virtual Python especificado.</li> + <li><code>rmvirtualenv name_of_environment</code> — Remove o ambiente especificado.</li> +</ul> + +<h2 id="Instalando_o_Django">Instalando o Django</h2> + +<p>Após criar um ambiente virtual e usado o comando <code>workon</code> para ativá-lo, você pode usar <em>pip3 </em>para instalar o Django. </p> + +<pre class="brush: bash notranslate">pip3 install django +</pre> + +<p>Você pode testar a instalação do Django executando o seguinte comando (isso apenas testa se o Python pode achar o módulo Django):</p> + +<pre class="brush: bash notranslate"># Linux/macOS +python3 -m django --version + 2.1.5 + +# Windows +py -3 -m django --version + 2.1.5 +</pre> + +<div class="note"> +<p><strong>Nota</strong>: Se o comando Windows acima não mostrar um módulo django, tente:</p> + +<pre class="brush: bash notranslate">py -m django --version</pre> + +<p>No Windows, os scripts <em>Python 3</em> são iniciados prefixando o comando com <code>py -3</code>, embora isso possa variar de acordo com sua instalação. Tente omitir o modificador <code>-3</code> se você encontrar algum problema com os comandos. No Linux/macOS, o comando é <code>python3</code>.</p> +</div> + +<div class="warning"> +<p><strong>Importante</strong>: O resto deste <strong>módulo </strong>usa o comando <em>Linux</em> para chamar o Python 3 (<code>python3</code>). Se você está usando o Windows, substitua o prefixo por: <code>py -3</code></p> +</div> + +<h2 id="Testando_sua_instalação">Testando sua instalação</h2> + +<p>O teste acima funciona, mas não é muito divertido. Um teste mais interessante é criar o esqueleto de um projeto e vê-lo funcionando. Para fazer isso, para isso navegue em seu prompt de comando/terminal até o diretório que quer armazenar seus aplicativos Django. Crie uma pasta para seu site e navegue nela.</p> + +<pre class="brush: bash notranslate">mkdir django_test +cd django_test +</pre> + +<p>Agora você pode criar um novo site chamado "<em>mytestsite</em>" usando a ferramenta <strong>django-admin</strong>. Após criar o site você pode navegar dentro da pasta onde encontrará o script principal para gerenciar projetos, nomeado <strong>manage.py</strong>.</p> + +<pre class="brush: bash notranslate">django-admin startproject mytestsite +cd mytestsite</pre> + +<p>Nós podemos rodar o <em>web server de desenvolvimento</em> dentro dessa pasta usando o <strong>manage.py</strong> e o comando <code>runserver</code>, como mostrado.</p> + +<pre class="brush: bash notranslate">$ python3 manage.py runserver +Performing system checks... + +System check identified no issues (0 silenced). + +You have 15 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions. +Run 'python manage.py migrate' to apply them. + +December 16, 2018 - 07:06:30 +Django version 2.1.5, using settings 'mytestsite.settings' +Starting development server at http://127.0.0.1:8000/ +Quit the server with CONTROL-C. +</pre> + +<div class="note"> +<p><strong>Nota</strong>: Acima foi mostrado o comando em Linux/macOS. Você já pode ignorar o aviso sobre "15 unapplied migration(s)"!</p> +</div> + +<p>Uma vez que o servidor está operando, você pode acessar o site colocando a seguinte URL no seu navegador local:<code>http://127.0.0.1:8000/</code>. Você deveria ver um site como esse:<br> + <img alt="Django Skeleton App Homepage - Django 2.0" src="https://mdn.mozillademos.org/files/16288/Django_Skeleton_Website_Homepage_2_1.png" style="height: 714px; width: 806px;"></p> + +<ul> +</ul> + +<h2 id="Resumo">Resumo</h2> + +<p>Agora você tem um ambiente de desenvolvimento em Django funcionando em seu computador.</p> + +<p>Na seção <em>Testando sua instalação </em>você viu brevemente como criar um website Django usando <code>django-admin startproject</code>, e executá-lo em seu navegador usando um web server de desenvolvimento (<code>python3 manage.py runserver</code>). No próximo artigo nós iremos expandir esse processo, construindo uma aplicação web simples, mas completa.</p> + +<h2 id="Veja_também">Veja também</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.1/intro/install/">Guia de Instalação Rápida</a> (documentação Django)</li> + <li><a href="https://docs.djangoproject.com/en/2.1/topics/install/">Como instalar Django — Guia completo</a> (documentação Django) - inclui informações para remover o Django</li> + <li><a href="https://docs.djangoproject.com/en/2.1/howto/windows/">Como instalar Django no Windows</a> (documentação Django)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Introduction", "Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django")}}</p> + +<h2 id="Neste_módulo">Neste módulo</h2> + +<ul> + <li><a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/Introduction">Introdução ao Django</a></li> + <li><a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/development_environment">Configurando um ambiente de desenvolvimento Django</a></li> + <li><a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django: Website de uma Biblioteca Local</a></li> + <li><a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/skeleton_website">Tutorial Django Parte 2: Criando a base do website</a></li> + <li><a href="https://developer.mozilla.org/pt-br/docs/Learn/Server-side/Django/Models">Tutorial Django Parte 3: Utilizando models</a></li> + <li><a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/Admin_site">Tutorial Django Parte 4: Django admin site</a></li> + <li><a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/Home_page">Tutorial Django Parte 5: Criando nossa página principal</a></li> + <li><a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/Generic_views">Tutorial Django Parte 6: Lista genérica e detail views</a></li> + <li><a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/Sessions">Tutorial Django Parte 7: Framework de Sessões</a></li> + <li><a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: Autenticação de Usuário e permissões</a></li> + <li><a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/Forms">Tutorial Django Parte 9: Trabalhando com formulários</a></li> + <li><a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/Testing">Tutorial Django Parte 10: Testando uma aplicação web Django</a></li> + <li><a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/Deployment">Tutorial Django Parte 11: Implantando Django em produção</a></li> + <li><a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/web_application_security">Segurança de aplicações web Django</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> diff --git a/files/pt-br/learn/server-side/django/authentication/index.html b/files/pt-br/learn/server-side/django/authentication/index.html new file mode 100644 index 0000000000..77535ae7ba --- /dev/null +++ b/files/pt-br/learn/server-side/django/authentication/index.html @@ -0,0 +1,692 @@ +--- +title: 'Tutorial Django Parte 8: Autenticação de usuário e permissões' +slug: Learn/Server-side/Django/Authentication +translation_of: Learn/Server-side/Django/Authentication +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Sessions", "Learn/Server-side/Django/Forms", "Learn/Server-side/Django")}}</div> + +<p class="summary">Neste tutorial, mostraremos como permitir que os usuários efetuem login no seu site com suas próprias contas e como controlar o que eles podem fazer e ver com base em se eles estão ou não conectados e em suas permissões. Como parte desta demonstração, estenderemos o <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> website, adicionando páginas de login e logout e páginas específicas do usuário e da equipe para visualizar os livros emprestados.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré-requisitos:</th> + <td>Conclua todos os tópicos do tutorial anterior, incluindo <a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a>.</td> + </tr> + <tr> + <th scope="row">Objetivo:</th> + <td>Para entender como configurar e usar a autenticação e permissões de usuário.</td> + </tr> + </tbody> +</table> + +<h2 id="Visão_global">Visão global</h2> + +<p>O Django fornece um sistema de autenticação e autorização ("permissão"), construído sobre a estrutura da sessão discutida no <a href="/en-US/docs/Learn/Server-side/Django/Sessions">tutorial anterior</a>, que permite verificar as credenciais do usuário e definir quais ações cada usuário tem permissão para executar. A estrutura inclui modelos internos para <code>Users</code> e <code>Groups</code> (uma maneira genérica de aplicar permissões a mais de um usuário por vez), permissões/sinalizadores que designam se um usuário pode executar uma tarefa, formulários e exibições para efetuar logon em usuários e exibir ferramentas para restringir o conteúdo.</p> + +<div class="note"> +<p><strong>Nota</strong>: De acordo com o Django, o sistema de autenticação pretende ser muito genérico e, portanto, não fornece alguns recursos fornecidos em outros sistemas de autenticação na web. Soluções para alguns problemas comuns estão disponíveis como pacotes de terceiros. Por exemplo, limitação de tentativas de login e autenticação contra terceiros (por exemplo, OAuth).</p> +</div> + +<p>Neste tutorial, mostraremos como habilitar a autenticação do usuário no diretório <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> website, crie suas próprias páginas de logon e logout, adicione permissões aos seus modelos e controle o acesso às páginas. Usaremos a autenticação/permissões para exibir listas de livros que foram emprestados para usuários e bibliotecários.</p> + +<p>O sistema de autenticação é muito flexível e você pode criar seus URLs, formulários, visualizações e modelos a partir do zero, se quiser, apenas chamando a API fornecida para efetuar login no usuário. No entanto, neste artigo, vamos usar as visualizações e formulários de autenticação "stock" do Django para nossas páginas de logon e logout. Ainda precisamos criar alguns modelos, mas isso é bem fácil.</p> + +<p>Também mostraremos como criar permissões e verificar o status e as permissões de login nas visualizações e nos modelos.</p> + +<h2 id="Ativando_a_autenticação">Ativando a autenticação</h2> + +<p>A autenticação foi ativada automaticamente quando <a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">criamos o esqueleto do site</a> (no tutorial 2), para que você não precise fazer mais nada neste momento.</p> + +<div class="note"> +<p><strong>Nota</strong>: A configuração necessária foi feita para nós quando criamos o aplicativo usando o comando <code>django-admin startproject</code>. As tabelas de banco de dados para usuários e permissões de modelo foram criadas quando chamamos pela primeira vez <code>python manage.py migrate</code>.</p> +</div> + +<p>A configuração está definida nas seções <code>INSTALLED_APPS</code> e <code>MIDDLEWARE</code> no settings.py (<strong>locallibrary/locallibrary/settings.py</strong>), como mostrado abaixo:</p> + +<pre class="brush: python notranslate">INSTALLED_APPS = [ + ... +<strong> 'django.contrib.auth', </strong>#Core authentication framework and its default models. +<strong> 'django.contrib.contenttypes', #</strong>Django content type system (allows permissions to be associated with models). + .... + +MIDDLEWARE = [ + ... +<strong> 'django.contrib.sessions.middleware.SessionMiddleware',</strong> #Manages sessions across requests + ... +<strong> 'django.contrib.auth.middleware.AuthenticationMiddleware',</strong> #Associates users with requests using sessions. + .... +</pre> + +<h2 id="Criando_usuários_e_grupos">Criando usuários e grupos</h2> + +<p>Você já criou seu primeiro usuário quando olhamos para o <a href="/en-US/docs/Learn/Server-side/Django/Admin_site">site Django admin</a> no tutorial 4 (este era um superusuário, criado com o comando <code>python manage.py createsuperuser)</code>. Nosso superusuário já está autenticado e tem todas as permissões, portanto, precisamos criar um usuário de teste para representar um usuário normal do site. Usaremos o site de administração para criar nossos grupos de bibliotecas de locais e logins de sites, pois é uma das maneiras mais rápidas de fazer isso.</p> + +<div class="note"> +<p><strong>Nota</strong>: Você também pode criar usuários programaticamente, conforme mostrado abaixo. Você precisaria fazer isso, por exemplo, se desenvolvesse uma interface para permitir que os usuários criassem seus próprios logins (você não deve conceder aos usuários acesso ao site de administração).</p> + +<pre class="brush: python notranslate">from django.contrib.auth.models import User + +# Create user and save to the database +user = User.objects.create_user('myusername', 'myemail@crazymail.com', 'mypassword') + +# Update fields and then save again +user.first_name = 'John' +user.last_name = 'Citizen' +user.save() +</pre> +</div> + +<p>Abaixo, primeiro criaremos um grupo e depois um usuário. Embora ainda não tenhamos permissões para adicionar aos membros da nossa biblioteca, se precisarmos mais tarde, será muito mais fácil adicioná-los uma vez ao grupo do que individualmente a cada membro.</p> + +<p>Inicie o servidor de desenvolvimento e navegue até o site de administração em seu navegador da web local (<a href="http://127.0.0.1:8000/admin/">http://127.0.0.1:8000/admin/</a>). Entre no site usando as credenciais da sua conta de superusuário. O nível superior do site Admin exibe todos os seus modelos, classificados por "aplicativo Django". Na seção <strong>Autenticação e Autorização</strong>, você pode clicar nos links <strong>Usuários </strong>ou <strong>Grupos </strong>para ver seus registros existentes.</p> + +<p><img alt="Admin site - add groups or users" src="https://mdn.mozillademos.org/files/14091/admin_authentication_add.png" style="border-style: solid; border-width: 1px; display: block; height: 364px; margin: 0px auto; width: 661px;"></p> + +<p>Primeiro vamos criar um novo grupo para os membros da nossa biblioteca.</p> + +<ol> + <li>Clique no botão <strong>Adicionar</strong> (ao lado de Grupo) para criar um novo grupo; digite o <strong>Nome</strong> "Library Members" para o grupo.<img alt="Admin site - add group" src="https://mdn.mozillademos.org/files/14093/admin_authentication_add_group.png" style="border-style: solid; border-width: 1px; display: block; height: 561px; margin: 0px auto; width: 800px;"></li> + <li>Não precisamos de permissões para o grupo, então pressione <strong>SALVAR </strong>(você será direcionado para uma lista de grupos).</li> +</ol> + +<p>Agora vamos criar um usuário:</p> + +<ol> + <li>Volte para a página inicial do site de administração</li> + <li>Clique no botão <strong>Adicionar </strong>ao lado de <em>Usuários </em>para abrir a caixa de diálogo <em>Adicionar usuário</em>.<img alt="Admin site - add user pt1" src="https://mdn.mozillademos.org/files/14095/admin_authentication_add_user_prt1.png" style="border-style: solid; border-width: 1px; display: block; height: 409px; margin: 0px auto; width: 800px;"></li> + <li>Digite um nome de <strong>usuário </strong>e uma <strong>senha/confirmação de senha</strong> adequados para o usuário de teste</li> + <li>Pressione <strong>SALVAR </strong>para criar o usuário.<br> + <br> + O site de administração criará o novo usuário e levará você imediatamente para uma tela Alterar usuário, na qual é possível alterar seu <strong>nome de usuário</strong> e adicionar informações aos campos opcionais do modelo de usuário. Esses campos incluem o nome, o sobrenome, o endereço de email e o status e as permissões do usuário (somente o sinalizador <strong>Ativo </strong>deve ser definido). Mais abaixo, você pode especificar os grupos e permissões do usuário e ver datas importantes relacionadas ao usuário (por exemplo, a data de ingresso e a última data de login).<img alt="Admin site - add user pt2" src="https://mdn.mozillademos.org/files/14097/admin_authentication_add_user_prt2.png" style="border-style: solid; border-width: 1px; display: block; height: 635px; margin: 0px auto; width: 800px;"></li> + <li>Na seção <em>Grupos</em>, selecione grupo de <strong>Library Members</strong> na lista de <em>Grupos disponíveis</em> e pressione a <strong>seta para a direita</strong> entre as caixas para movê-lo para a caixa <em>Grupos escolhidos</em>.<img alt="Admin site - add user to group" src="https://mdn.mozillademos.org/files/14099/admin_authentication_user_add_group.png" style="border-style: solid; border-width: 1px; display: block; height: 414px; margin: 0px auto; width: 933px;"></li> + <li>Não precisamos fazer mais nada aqui; basta selecionar <strong>SALVAR </strong>novamente, para ir para a lista de usuários.</li> +</ol> + +<p>É isso aí! Agora você tem uma conta de "membro normal da biblioteca" que poderá usar nos testes (depois de implementarmos as páginas para permitir o login).</p> + +<div class="note"> +<p><strong>Nota</strong>: Você deve tentar criar outro usuário membro da biblioteca. Além disso, crie um grupo para bibliotecários e adicione um usuário a ele também!</p> +</div> + +<h2 id="Configurando_suas_views_de_autenticação">Configurando suas views de autenticação</h2> + +<p>O Django fornece quase tudo que você precisa para criar páginas de autenticação para lidar com o login, logout e gerenciamento de senhas "out of the box". Isso inclui um mapeador de URL, visualizações e formulários, mas não inclui os modelos - precisamos criar os nossos!</p> + +<p>Nesta seção, mostramos como integrar o sistema padrão no site <em>LocalLibrary </em>e criar os modelos. Vamos colocá-los nos principais URLs do projeto.</p> + +<div class="note"> +<p><strong>Nota</strong>: Você não precisa usar nenhum desses códigos, mas é provável que queira, porque isso facilita muito as coisas. Você quase certamente precisará alterar o código de manipulação de formulários se alterar seu modelo de usuário (um tópico avançado!), Mas, mesmo assim, ainda poderá usar as funções padrão das views.</p> +</div> + +<div class="note"> +<p><strong>Nota: </strong>Nesse caso, poderíamos colocar razoavelmente as páginas de autenticação, incluindo os URLs e modelos, dentro do nosso aplicativo de catálogo. No entanto, se tivéssemos vários aplicativos, seria melhor separar esse comportamento de login compartilhado e disponibilizá-lo em todo o site, e é isso que mostramos aqui!</p> +</div> + +<h3 id="URLs_do_Projeto">URLs do Projeto</h3> + +<p>Adicione o seguinte à parte inferior do arquivo urls.py do projeto (<strong>locallibrary/locallibrary/urls.py</strong>):</p> + +<pre class="brush: python notranslate">#Add Django site authentication urls (for login, logout, password management) +urlpatterns += [ + path('accounts/', include('django.contrib.auth.urls')), +] +</pre> + +<p>Navegue até URL <a href="http://127.0.0.1:8000/accounts/">http://127.0.0.1:8000/accounts/</a> (observe a barra à direita!) e o Django mostrará um erro que não foi possível encontrar esse URL e listará todos os URLs que ele tentou. A partir disso, você pode ver os URLs que funcionarão, por exemplo:</p> + +<div class="note"> +<p><strong>Nota: </strong>O uso do método acima adiciona os seguintes URLs com nomes entre colchetes, que podem ser usados para reverter os mapeamentos de URL. Você não precisa implementar mais nada - o mapeamento de URL acima mapeia automaticamente os URLs mencionados abaixo.</p> + +<pre class="brush: python notranslate">accounts/ login/ [name='login'] +accounts/ logout/ [name='logout'] +accounts/ password_change/ [name='password_change'] +accounts/ password_change/done/ [name='password_change_done'] +accounts/ password_reset/ [name='password_reset'] +accounts/ password_reset/done/ [name='password_reset_done'] +accounts/ reset/<uidb64>/<token>/ [name='password_reset_confirm'] +accounts/ reset/done/ [name='password_reset_complete']</pre> +</div> + +<p>Agora tente navegar para o URL de login (<a href="http://127.0.0.1:8000/accounts/login/">http://127.0.0.1:8000/accounts/login/</a>). Isso falhará novamente, mas com um erro informando que estamos perdendo o modelo necessário (<strong>registration/login.html</strong>) no caminho de pesquisa do modelo. Você verá as seguintes linhas listadas na seção amarela na parte superior:</p> + +<pre class="brush: python notranslate">Exception Type: TemplateDoesNotExist +Exception Value: <strong>registration/login.html</strong></pre> + +<p>A próxima etapa é criar um diretório de registro no caminho de pesquisa e adicionar o arquivo <strong>login.html</strong>.</p> + +<h3 id="Diretório_de_Templates">Diretório de Templates</h3> + +<p>Os URLs (e implicitamente, visualizações) que acabamos de adicionar esperam encontrar seus modelos associados em um diretório <strong>/registration/</strong> em algum lugar no caminho de pesquisa de modelos.</p> + +<p>Neste site, colocaremos nossas páginas HTML no diretório <strong>templates/registration/</strong>. Esse diretório deve estar no diretório raiz do projeto, ou seja, o mesmo diretório que a pasta <strong>catalog</strong> e <strong>locallibrary</strong>. Por favor, crie essas pastas agora.</p> + +<div class="note"> +<p><strong>Nota:</strong> Sua estrutura de pastas agora deve se parecer como abaixo:<br> + locallibrary (Django project folder)<br> + |_catalog<br> + |_locallibrary<br> + |_templates <strong>(new)</strong><br> + |_registration</p> +</div> + +<p>Para tornar esses diretórios visíveis para o carregador de modelos (ou seja, para colocar esse diretório no caminho de pesquisa de modelos), abra as configurações do projeto (<strong>/locallibrary/locallibrary/settings.py</strong>) e atualize o seção <code>TEMPLATES</code> linha <code>'DIRS'</code> como mostrado abaixo.</p> + +<pre class="brush: python notranslate">TEMPLATES = [ + { + ... +<strong> 'DIRS': [os.path.join(BASE_DIR, 'templates')],</strong> + 'APP_DIRS': True, + ... +</pre> + +<h3 id="Template_de_login">Template de login</h3> + +<div class="warning"> +<p><strong>Importante</strong>: Os modelos de autenticação fornecidos neste artigo são uma versão muito básica/ligeiramente modificada dos modelos de login de demonstração do Django. Pode ser necessário personalizá-los para seu próprio uso!</p> +</div> + +<p>Crie um novo arquivo HTML chamado <strong>/locallibrary/templates/registration/login.html</strong> e forneça o seguinte conteúdo:</p> + +<pre class="brush: html notranslate">{% extends "base_generic.html" %} + +{% block content %} + + {% if form.errors %} + <p>Your username and password didn't match. Please try again.</p> + {% endif %} + + {% if next %} + {% if user.is_authenticated %} + <p>Your account doesn't have access to this page. To proceed, + please login with an account that has access.</p> + {% else %} + <p>Please login to see this page.</p> + {% endif %} + {% endif %} + + <form method="post" action="{% url 'login' %}"> + {% csrf_token %} + <table> + <tr> + <td>\{{ form.username.label_tag }}</td> + <td>\{{ form.username }}</td> + </tr> + <tr> + <td>\{{ form.password.label_tag }}</td> + <td>\{{ form.password }}</td> + </tr> + </table> + <input type="submit" value="login" /> + <input type="hidden" name="next" value="\{{ next }}" /> + </form> + + {# Assumes you setup the password_reset view in your URLconf #} + <p><a href="{% url 'password_reset' %}">Lost password?</a></p> + +{% endblock %}</pre> + +<p id="sect1">Este modelo compartilha algumas semelhanças com as que já vimos antes - estende nosso modelo base e substitui o bloco <code>content</code>. O restante do código é um código de manipulação de formulário bastante padrão, que discutiremos em um tutorial posterior. Por enquanto, tudo o que você precisa saber é que isso exibirá um formulário no qual é possível inserir seu nome de usuário e senha e que, se você inserir valores inválidos, será solicitado que você digite os valores corretos quando a página for atualizada.</p> + +<p>Navegue de volta para a página de login (<a href="http://127.0.0.1:8000/accounts/login/">http://127.0.0.1:8000/accounts/login/</a>). Depois de salvar seu modelo, você verá algo assim:</p> + +<p><img alt="Library login page v1" src="https://mdn.mozillademos.org/files/14101/library_login.png" style="border-style: solid; border-width: 1px; display: block; height: 173px; margin: 0px auto; width: 441px;"></p> + +<p>Se você fizer login usando credenciais válidas, será redirecionado para outra página (por padrão, isso será <a href="http://127.0.0.1:8000/accounts/profile/">http://127.0.0.1:8000/accounts/profile/</a>). O problema é que, por padrão, o Django espera que, ao fazer o login, você deseje ser levado para uma página de perfil, o que pode ou não ser o caso. Como você ainda não definiu esta página, receberá outro erro!</p> + +<p>Abra as configurações do projeto (<strong>/locallibrary/locallibrary/settings.py</strong>) e adicione o texto abaixo na parte inferior. Agora, quando você faz login, deve ser redirecionado para a página inicial do site por padrão.</p> + +<pre class="brush: python notranslate"># Redirect to home URL after login (Default redirects to /accounts/profile/) +LOGIN_REDIRECT_URL = '/' +</pre> + +<h3 id="Template_de_logout">Template de logout</h3> + +<p>Se você navegar para o URL de logout (<a href="http://127.0.0.1:8000/accounts/logout/">http://127.0.0.1:8000/accounts/logout/</a>) você verá um comportamento estranho - seu usuário será desconectado com certeza, mas será direcionado para a pagina de logout do <strong>Admin</strong>. Não é isso que você deseja, apenas porque o link de login nessa página o leva para a tela de login do administrador (e está disponível apenas para usuários que têm a permissão <code>is_staff</code>).</p> + +<p>Crie e abra /<strong>locallibrary/templates/registration/logged_out.html</strong>. Copie o texto abaixo:</p> + +<pre class="brush: html notranslate">{% extends "base_generic.html" %} + +{% block content %} + <p>Logged out!</p> + <a href="{% url 'login'%}">Click here to login again.</a> +{% endblock %}</pre> + +<p>Este modelo é muito simples. Ele apenas exibe uma mensagem informando que você foi desconectado e fornece um link que você pode pressionar para voltar à tela de login. Se você acessar o URL de logoff novamente, deverá ver esta página:</p> + +<p><img alt="Library logout page v1" src="https://mdn.mozillademos.org/files/14103/library_logout.png" style="border-style: solid; border-width: 1px; display: block; height: 169px; margin: 0px auto; width: 385px;"></p> + +<h3 id="Templates_para_reset_de_password">Templates para reset de password</h3> + +<p>O sistema de redefinição de senha padrão usa o email para enviar ao usuário um link de redefinição. Você precisa criar formulários para obter o endereço de email do usuário, enviar o email, permitir que ele insira uma nova senha e anotar quando todo o processo está completo.</p> + +<p>Os seguintes modelos podem ser usados como ponto de partida.</p> + +<h4 id="Formulário_para_reset_de_password">Formulário para reset de password</h4> + +<p>Este é o formulário usado para obter o endereço de email do usuário (para enviar o email de redefinição de senha). Crie <strong>/locallibrary/templates/registration/password_reset_form.html</strong> e forneça o seguinte conteúdo:</p> + +<pre class="brush: html notranslate">{% extends "base_generic.html" %} + +{% block content %} + <form action="" method="post"> + {% csrf_token %} + {% if form.email.errors %} + \{{ form.email.errors }} + {% endif %} + <p>\{{ form.email }}</p> + <input type="submit" class="btn btn-default btn-lg" value="Reset password"> + </form> +{% endblock %} +</pre> + +<h4 id="Password_reset_done">Password reset done</h4> + +<p>Este formulário é exibido após a coleta do seu endereço de email. Crie <strong>/locallibrary/templates/registration/password_reset_done.html</strong>, e forneça o seguinte conteúdo:</p> + +<pre class="brush: html notranslate">{% extends "base_generic.html" %} + +{% block content %} + <p>We've emailed you instructions for setting your password. If they haven't arrived in a few minutes, check your spam folder.</p> +{% endblock %} +</pre> + +<h4 id="Password_reset_email">Password reset email</h4> + +<p>Este modelo fornece o texto do email em HTML que contém o link de redefinição que enviaremos aos usuários. Crie<strong> /locallibrary/templates/registration/password_reset_email.html</strong> e forneça o seguinte conteúdo:</p> + +<pre class="brush: html notranslate">Someone asked for password reset for email \{{ email }}. Follow the link below: +\{{ protocol}}://\{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %} +</pre> + +<h4 id="Password_reset_confirm">Password reset confirm</h4> + +<p>É nesta página que você digita sua nova senha depois de clicar no link no e-mail de redefinição de senha. Crie <strong>/locallibrary/templates/registration/password_reset_confirm.html</strong> e forneça o seguinte conteúdo:</p> + +<pre class="brush: html notranslate">{% extends "base_generic.html" %} + +{% block content %} + {% if validlink %} + <p>Please enter (and confirm) your new password.</p> + <form action="" method="post"> + {% csrf_token %} + <table> + <tr> + <td>\{{ form.new_password1.errors }} + <label for="id_new_password1">New password:</label></td> + <td>\{{ form.new_password1 }}</td> + </tr> + <tr> + <td>\{{ form.new_password2.errors }} + <label for="id_new_password2">Confirm password:</label></td> + <td>\{{ form.new_password2 }}</td> + </tr> + <tr> + <td></td> + <td><input type="submit" value="Change my password" /></td> + </tr> + </table> + </form> + {% else %} + <h1>Password reset failed</h1> + <p>The password reset link was invalid, possibly because it has already been used. Please request a new password reset.</p> + {% endif %} +{% endblock %} +</pre> + +<h4 id="Password_reset_complete">Password reset complete</h4> + +<p>Este é o último modelo de redefinição de senha, exibido para notificá-lo quando a redefinição de senha for bem-sucedida. Crie <strong>/locallibrary/templates/registration/password_reset_complete.html</strong> e forneça o seguinte conteúdo:</p> + +<pre class="brush: html notranslate">{% extends "base_generic.html" %} + +{% block content %} + <h1>The password has been changed!</h1> + <p><a href="{% url 'login' %}">log in again?</a></p> +{% endblock %}</pre> + +<h3 id="Testando_as_novas_páginas_de_autenticação">Testando as novas páginas de autenticação</h3> + +<p>Agora que você adicionou a configuração da URL e criou todos esses modelos, as páginas de autenticação agora devem funcionar!</p> + +<p>Você pode testar as novas páginas de autenticação tentando fazer login e sair da sua conta de superusuário usando estes URLs:</p> + +<ul> + <li><a href="http://127.0.0.1:8000/accounts/login/">http://127.0.0.1:8000/accounts/login/</a></li> + <li><a href="http://127.0.0.1:8000/accounts/logout/">http://127.0.0.1:8000/accounts/logout/</a></li> +</ul> + +<p>Você poderá testar a funcionalidade de redefinição de senha no link na página de login. <strong>Esteja ciente de que o Django enviará apenas emails de redefinição para endereços (usuários) que já estão armazenados em seu banco de dados!</strong></p> + +<div class="note"> +<p><strong>Nota</strong>: O sistema de redefinição de senha exige que seu site suporte e-mail, que está além do escopo deste artigo, portanto esta parte ainda não funcionará. Para permitir o teste, coloque a seguinte linha no final do seu arquivo settings.py. Isso registra todos os emails enviados ao console (para que você possa copiar o link de redefinição de senha do console).</p> + +<pre class="brush: python notranslate">EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' +</pre> + +<p>Para mais informações, veja <a href="https://docs.djangoproject.com/en/2.1/topics/email/">Sending email</a> (Django docs).</p> +</div> + +<h2 id="Testando_contra_usuários_autenticados">Testando contra usuários autenticados</h2> + +<p>Esta seção analisa o que podemos fazer para controlar seletivamente o conteúdo que o usuário vê, com base em se está logado ou não.</p> + +<h3 id="Testando_nos_templates">Testando nos templates</h3> + +<p>Você pode obter informações sobre o usuário conectado no momento em modelos com a variável de template <code>\{{ user }}</code> (isso é adicionado ao contexto do template por padrão quando você configura o projeto como fizemos em nosso esqueleto).</p> + +<p>Normalmente você primeiro testará contra a variável de template <code>\{{ user.is_authenticated }}</code> para determinar se o usuário está qualificado para ver conteúdo específico. Para demonstrar isso, em seguida, atualizaremos nossa barra lateral para exibir um link "Login" se o usuário estiver desconectado e um link "Logout" se estiverem conectados.</p> + +<p>Abra o template base (<strong>/locallibrary/catalog/templates/base_generic.html</strong>) e copie o texto a seguir no bloco <code>sidebar</code>, imediatamente antes da template tag <code>endblock</code>.</p> + +<pre class="brush: html notranslate"> <ul class="sidebar-nav"> + + ... + + <strong>{% if user.is_authenticated %}</strong> + <li>User: <strong>\{{ user.get_username }}</strong></li> + <li><a href="{% url 'logout'%}?next=\{{request.path}}">Logout</a></li> + <strong>{% else %}</strong> + <li><a href="{% url 'login'%}?next=\{{request.path}}">Login</a></li> + <strong>{% endif %} </strong> + </ul></pre> + +<p>Como você pode ver, usamos template tags <code>if</code>-<code>else</code>-<code>endif</code> para exibir condicionalmente o texto com base em <code>\{{ user.is_authenticated }}</code> ser verdadeiro. Se o usuário estiver autenticado, sabemos que temos um usuário válido, por isso chamamos <code>\{{ user.get_username }}</code><strong> </strong>para exibir o nome deles.</p> + +<p>Criamos os URLs dos links de logon e logout usando a template tag <code>url</code> e os nomes das respectivas configurações de URL. Observe também como anexamos <code>?next=\{{request.path}}</code> no final dos URLs. O que isso faz é adicionar um parâmetro de URL a seguir, contendo o endereço (URL) da página atual, ao final do URL vinculado. Após o usuário ter efetuado login/logout com sucesso, as visualizações usarão este valor "<code>next</code>" para redirecionar o usuário de volta à página em que ele clicou pela primeira vez no link de logon/logout.</p> + +<div class="note"> +<p><strong>Nota</strong>: Experimente! Se você estiver na página inicial e clicar em Login/Logout na barra lateral, depois que a operação for concluída, você deverá voltar à mesma página.</p> +</div> + +<h3 id="Testando_nas_views">Testando nas views</h3> + +<p>Se você estiver usando views baseadas em funções, a maneira mais fácil de restringir o acesso a suas funções é aplicando o decorator <code>login_required</code> à sua função view, como mostrado abaixo. Se o usuário estiver logado, seu código de exibição será executado normalmente. Se o usuário não estiver conectado, isso será redirecionado para o URL de login definido nas configurações do projeto.(<code>settings.LOGIN_URL</code>), passando o caminho absoluto atual como o <code>next</code> no parametro da URL. Se o usuário conseguir fazer login, ele retornará a esta página, mas desta vez autenticado.</p> + +<pre class="brush: python notranslate">from django.contrib.auth.decorators import login_required + +@login_required +def my_view(request): + ...</pre> + +<div class="note"> +<p><strong>Nota:</strong> Você pode fazer o mesmo tipo de coisa manualmente testando em<code>request.user.is_authenticated</code>, mas o decorator é muito mais conveniente!</p> +</div> + +<p>Da mesma forma, a maneira mais fácil de restringir o acesso a usuários logados em suas visualizações baseadas em classe é derivar de <code>LoginRequiredMixin</code>. Você precisa declarar esse mixin primeiro na lista de superclasses, antes da classe de visualização principal.</p> + +<pre class="brush: python notranslate">from django.contrib.auth.mixins import LoginRequiredMixin + +class MyView(LoginRequiredMixin, View): + ...</pre> + +<p>Isso tem exatamente o mesmo comportamento de redirecionamento que o decorator <code>login_required</code>. Você também pode especificar um local alternativo para redirecionar o usuário se ele não estiver autenticado (<code>login_url</code>), e um nome de parâmetro de URL em vez de "<code>next</code>" para inserir o caminho absoluto atual (<code>redirect_field_name</code>).</p> + +<pre class="brush: python notranslate">class MyView(LoginRequiredMixin, View): + login_url = '/login/' + redirect_field_name = 'redirect_to' +</pre> + +<p>Para detalhes adicionais, consulte o <a href="https://docs.djangoproject.com/en/2.1/topics/auth/default/#limiting-access-to-logged-in-users">Django docs here</a>.</p> + +<h2 id="Exemplo_-_listando_os_livros_do_usuário_atual">Exemplo - listando os livros do usuário atual</h2> + +<p>Agora que sabemos como restringir uma página a um usuário específico, vamos criar uma visualização dos livros que o usuário atual emprestou.</p> + +<p>Infelizmente, ainda não temos como os usuários emprestarem livros! Portanto, antes que possamos criar a lista de livros, primeiro estenderemos o modelo <code>BookInstance</code> para suportar o conceito de empréstimo e usar o aplicativo Django Admin para emprestar vários livros ao nosso usuário de teste.</p> + +<h3 id="Models">Models</h3> + +<p>Primeiro, teremos que possibilitar que os usuários tenham um <code>BookInstance</code> emprestado (já temos um <code>status</code> e uma data <code>due_back</code>, mas ainda não temos nenhuma associação entre esse modelo e um usuário. Vamos criar um usando um campo <code>ForeignKey</code> (one-to-many). Também precisamos de um mecanismo fácil para testar se um livro emprestado está vencido.</p> + +<p>Abra <strong>catalog/models.py</strong>, e importe o model <code>User</code> de <code>django.contrib.auth.models</code> (adicione isso logo abaixo da linha de importação anterior na parte superior do arquivo, para <code>User</code> estar disponível para o código subsequente que faz uso dele):</p> + +<pre class="brush: python notranslate">from django.contrib.auth.models import User +</pre> + +<p>Em seguida, adicione o campo <code>borrower</code> para o modelo <code>BookInstance</code>:</p> + +<pre class="brush: python notranslate">borrower = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True) +</pre> + +<p>Enquanto estamos aqui, vamos adicionar uma propriedade que podemos chamar de nossos modelos para saber se uma instância específica de um livro está atrasada. Embora possamos calcular isso no próprio modelo, usando uma <a href="https://docs.python.org/3/library/functions.html#property">property</a> como mostrado abaixo será muito mais eficiente.</p> + +<p>Adicione isso em algum lugar perto da parte superior do arquivo:</p> + +<pre class="brush: python notranslate">from datetime import date</pre> + +<p class="brush: python">Agora adicione a seguinte definição de propriedade a classe <code>BookInstance</code>:</p> + +<pre class="brush: python notranslate">@property +def is_overdue(self): + if self.due_back and date.today() > self.due_back: + return True + return False</pre> + +<div class="note"> +<p><strong>Nota</strong>: Primeiro, verificamos se <code>due_back</code> está vazio antes de fazer uma comparação. Um campo <code>due_back</code> vazio faria com que o Django gerasse um erro em vez de mostrar a página: valores vazios não são comparáveis. Isso não é algo que gostaríamos que nossos usuários experimentassem!</p> +</div> + +<p>Agora que atualizamos nossos modelos, precisaremos fazer novas migrações no projeto e aplicá-las:</p> + +<pre class="brush: bash notranslate">python3 manage.py makemigrations +python3 manage.py migrate +</pre> + +<h3 id="Admin">Admin</h3> + +<p>Agora abra <strong>catalog/admin.py</strong>, e adicione o campo <code>borrower</code> para a classe <code>BookInstanceAdmin</code> em ambos os <code>list_display</code> e o <code>fieldsets</code> como mostrado abaixo. Isso tornará o campo visível na seção Admin, permitindo atribuir um <code>User</code> para um <code>BookInstance</code> quando necessário.</p> + +<pre class="brush: python notranslate">@admin.register(BookInstance) +class BookInstanceAdmin(admin.ModelAdmin): + list_display = ('book', 'status'<strong>, 'borrower'</strong>, 'due_back', 'id') + list_filter = ('status', 'due_back') + + fieldsets = ( + (None, { + 'fields': ('book','imprint', 'id') + }), + ('Availability', { + 'fields': ('status', 'due_back'<strong>,'borrower'</strong>) + }), + )</pre> + +<h3 id="Emprestando_alguns_livros">Emprestando alguns livros</h3> + +<p>Agora que é possível emprestar livros para um usuário específico, vá e empreste vários <code>BookInstance</code>. Defina o campo <code>borrowed</code> para o usuário de teste, faça o <code>status</code> "On loan", e defina datas de vencimento no futuro e no passado.</p> + +<div class="note"> +<p><strong>Nota</strong>: Não detalharemos o processo, pois você já sabe como usar o site Admin!</p> +</div> + +<h3 id="Na_view_loan">Na view loan</h3> + +<p>Agora, adicionaremos uma view para obter a lista de todos os livros que foram emprestados ao usuário atual. Usaremos a mesma view de lista genérica baseada em classe com a qual estamos familiarizados, mas desta vez também importaremos e derivaremos de <code>LoginRequiredMixin</code>, para que apenas um usuário conectado possa chamar essa visualização. Também optaremos por declarar um <code>template_name</code>, em vez de usar o padrão, pois podemos ter algumas listas diferentes de registros BookInstance, com diferentes visualizações e modelos.</p> + +<p>Adicione o seguinte a <strong>catalog/views.py</strong>:</p> + +<pre class="brush: python notranslate">from django.contrib.auth.mixins import LoginRequiredMixin + +class LoanedBooksByUserListView(LoginRequiredMixin,generic.ListView): + """Generic class-based view listing books on loan to current user.""" + model = BookInstance + template_name ='catalog/bookinstance_list_borrowed_user.html' + paginate_by = 10 + + def get_queryset(self): + return BookInstance.objects.filter(borrower=self.request.user).filter(status__exact='o').order_by('due_back')</pre> + +<p>Para restringir nossa consulta apenas ao objeto <code>BookInstance</code> para o usuário atual, reimplementamos <code>get_queryset()</code> como mostrado abaixo. Observe que "o" is the stored code for "on loan" (emprestado) e nós pedimos pela data <code>due_back</code> para que os itens mais antigos sejam exibidos primeiro.</p> + +<h3 id="URL_conf_para_livros_on_loan_emprestado">URL conf para livros on loan (emprestado)</h3> + +<p>Agora abra <strong>/catalog/urls.py</strong> e adicione um <code>path()</code> apontando para a visualização acima (você pode copiar o texto abaixo no final do arquivo).</p> + +<pre class="brush: python notranslate">urlpatterns += [ + path('mybooks/', views.LoanedBooksByUserListView.as_view(), name='my-borrowed'), +]</pre> + +<h3 id="Template_para_livros_on_loan_emprestado">Template para livros on loan (emprestado)</h3> + +<p>Agora, tudo o que precisamos fazer para esta página é adicionar um modelo. Primeiro, crie o arquivo de modelo <strong>/catalog/templates/catalog/bookinstance_list_borrowed_user.html</strong> e forneça o seguinte conteúdo:</p> + +<pre class="brush: python notranslate">{% extends "base_generic.html" %} + +{% block content %} + <h1>Borrowed books</h1> + + {% if bookinstance_list %} + <ul> + + {% for bookinst in bookinstance_list %} + <li class="{% if bookinst.is_overdue %}text-danger{% endif %}"> + <a href="{% url 'book-detail' bookinst.book.pk %}">\{{bookinst.book.title}}</a> (\{{ bookinst.due_back }}) + </li> + {% endfor %} + </ul> + + {% else %} + <p>There are no books borrowed.</p> + {% endif %} +{% endblock %}</pre> + +<p>Este modelo é muito semelhante ao que criamos anteriormente para os objetos <code>Book</code> e <code>Author</code>. A única coisa "nova" aqui é que verificamos o método que adicionamos no modelo <code>(bookinst.is_overdue</code>) e use-o para alterar a cor dos itens em atraso.</p> + +<p>Quando o servidor de desenvolvimento estiver em execução, agora você poderá visualizar a lista de um usuário conectado no seu navegador em <a href="http://127.0.0.1:8000/catalog/mybooks/">http://127.0.0.1:8000/catalog/mybooks/</a>. Experimente isso com o usuário conectado e desconectado (no segundo caso, você deve ser redirecionado para a página de login).</p> + +<h3 id="Adicione_a_lista_à_barra_lateral">Adicione a lista à barra lateral</h3> + +<p>O último passo é adicionar um link para esta nova página na barra lateral. Colocaremos isso na mesma seção em que exibimos outras informações para o usuário conectado.</p> + +<p>Abra o template base (<strong>/locallibrary/catalog/templates/base_generic.html</strong>) e adicione a linha em negrito à barra lateral, como mostrado.</p> + +<pre class="brush: python notranslate"> <ul class="sidebar-nav"> + {% if user.is_authenticated %} + <li>User: \{{ user.get_username }}</li> +<strong> <li><a href="{% url 'my-borrowed' %}">My Borrowed</a></li></strong> + <li><a href="{% url 'logout'%}?next=\{{request.path}}">Logout</a></li> + {% else %} + <li><a href="{% url 'login'%}?next=\{{request.path}}">Login</a></li> + {% endif %} + </ul> +</pre> + +<h3 id="Com_o_que_se_parece">Com o que se parece?</h3> + +<p>Quando qualquer usuário estiver conectado, ele verá o link <em>My Borrowed</em> na barra lateral e a lista de livros exibida abaixo (o primeiro livro não tem data de vencimento, que é um bug que esperamos corrigir em um tutorial posterior!) .</p> + +<p><img alt="Library - borrowed books by user" src="https://mdn.mozillademos.org/files/14105/library_borrowed_by_user.png" style="border-style: solid; border-width: 1px; display: block; height: 215px; margin: 0px auto; width: 530px;"></p> + +<h2 id="Permissões">Permissões</h2> + +<p>As permissões são associadas aos modelos e definem as operações que podem ser executadas em uma instância de modelo por um usuário que possui a permissão. Por padrão, o Django automaticamente fornece permissões de adição, alteração e exclusão para todos os modelos, o que permite que usuários com permissões executem as ações associadas através do site de administração. Você pode definir suas próprias permissões para modelos e concedê-las a usuários específicos. Você também pode alterar as permissões associadas a diferentes instâncias do mesmo modelo.</p> + +<p>Testar permissões nas views e templates é muito semelhante ao teste no status de autenticação (e, na verdade, testar uma permissão também testa a autenticação).</p> + +<h3 id="Models_2">Models</h3> + +<p>A definição de permissões é feita na seção "<code>class Meta</code>" do modelo, usando o campo <code>permissions</code>. Você pode especificar quantas permissões você precisar em uma tupla, cada permissão sendo definida em uma tupla aninhada que contém o nome da permissão e o valor de exibição da permissão. Por exemplo, podemos definir uma permissão para permitir que um usuário marque que um livro foi retornado como mostrado:</p> + +<pre class="brush: python notranslate">class BookInstance(models.Model): + ... + class Meta: + ... +<strong> permissions = (("can_mark_returned", "Set book as returned"),) </strong> </pre> + +<p>Poderíamos então atribuir a permissão a um grupo "Librarian" no site do administrador.</p> + +<p>Abra <strong>catalog/models.py</strong>, e adicione a permissão como mostrado acima. Você ira precisar atualizar seus <em>migrations</em> (execute <code>python3 manage.py makemigrations</code> e <code>python3 manage.py migrate</code>) para atualizar o banco de dados apropriadamente.</p> + +<h3 id="Templates">Templates</h3> + +<p>As permissões do usuário atual são armazenadas em uma variável de modelo chamada <code>\{{ perms }}</code>. Você pode verificar se o usuário atual tem uma permissão específica usando o nome da variável específica no "aplicativo" associado ao Django — e.g. <code>\{{ perms.catalog.can_mark_returned }}</code> será <code>True</code> se o usuário tiver essa permissão, caso contrário, <code>False</code>. Normalmente testamos a permissão usando a template tag <code>{% if %}</code> como mostrado:</p> + +<pre class="brush: python notranslate">{% if perms.catalog.can_mark_returned %} + <!-- We can mark a BookInstance as returned. --> + <!-- Perhaps add code to link to a "book return" view here. --> +{% endif %} +</pre> + +<h3 id="Views">Views</h3> + +<p>As permissões podem ser testadas na exibição de funções usando o decorator <code>permission_required</code> ou em uma view baseada em classe usando o <code>PermissionRequiredMixin</code>. O padrão e o comportamento são os mesmos da autenticação de login, embora, é claro, você possa razoavelmente precisar adicionar várias permissões.</p> + +<p>Função view decorator:</p> + +<pre class="brush: python notranslate">from django.contrib.auth.decorators import permission_required + +@permission_required('catalog.can_mark_returned') +@permission_required('catalog.can_edit') +def my_view(request): + ...</pre> + +<p>Um permission-required mixin para class-based views.</p> + +<pre class="brush: python notranslate">from django.contrib.auth.mixins import PermissionRequiredMixin + +class MyView(PermissionRequiredMixin, View): + permission_required = 'catalog.can_mark_returned' + # Or multiple permissions + permission_required = ('catalog.can_mark_returned', 'catalog.can_edit') + # Note that 'catalog.can_edit' is just an example + # the catalog application doesn't have such permission!</pre> + +<h3 id="Exemplo">Exemplo</h3> + +<p>Não atualizaremos a <em>LocalLibrary </em>aqui; talvez no próximo tutorial!</p> + +<h2 id="Desafie-se">Desafie-se</h2> + +<p>No início deste artigo, mostramos como criar uma página para o usuário atual, listando os livros emprestados. O desafio agora é criar uma página semelhante que seja visível apenas para bibliotecários, que exiba <em>todos </em>os livros que foram emprestados e que inclua o nome de cada mutuário.</p> + +<p>Você deve seguir o mesmo padrão da outra view. A principal diferença é que você precisará restringir a visualização apenas a bibliotecários. Você pode fazer isso com base no fato de o usuário ser um membro da equipe (decorator da função: <code>staff_member_required</code>, variável do template: <code>user.is_staff</code>) mas recomendamos que você use a permissão <code>can_mark_returned</code> e <code>PermissionRequiredMixin</code>, conforme descrito na seção anterior.</p> + +<div class="warning"> +<p><strong>Importante</strong>: Lembre-se de não usar seu superusuário para testes baseados em permissões (as verificações de permissão sempre retornam verdadeiras para os superusuários, mesmo que uma permissão ainda não tenha sido definida!). Em vez disso, crie um usuário bibliotecário e adicione o recurso necessário.</p> +</div> + +<p>Quando terminar, sua página será semelhante à captura de tela abaixo.</p> + +<p><img alt="All borrowed books, restricted to librarian" src="https://mdn.mozillademos.org/files/14115/library_borrowed_all.png" style="border-style: solid; border-width: 1px; display: block; height: 283px; margin: 0px auto; width: 500px;"></p> + +<ul> +</ul> + +<h2 id="Resumo">Resumo</h2> + +<p>Excelente trabalho — Você criou um site no qual os membros da biblioteca podem fazer login e ver seu próprio conteúdo e que os bibliotecários (com as permissões corretas) podem usar para visualizar todos os livros emprestados e seus devedores. No momento, ainda estamos apenas visualizando conteúdo, mas os mesmos princípios e técnicas são usadas quando você deseja começar a modificar e adicionar dados.</p> + +<p>Em nosso próximo artigo, veremos como você pode usar os formulários Django para coletar entradas do usuário, e então começar a modificar alguns dos nossos dados armazenados.</p> + +<h2 id="Veja_também">Veja também</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.1/topics/auth/">Autenticação de usuário no Django</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.1/topics/auth/default//">Usando o sistema (default) de Autenticação do Django</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.1/topics/class-based-views/intro/#decorating-class-based-views">Introdução a views baseadas em classe > Decorating class-based views</a> (Django docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Sessions", "Learn/Server-side/Django/Forms", "Learn/Server-side/Django")}}</p> + +<h2 id="Neste_módulo">Neste módulo</h2> + +<ul> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Introduction">Introdução ao Django</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/development_environment">Configurando um ambiente de desenvolvimento Django</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django: Website de uma Biblioteca Local</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/skeleton_website">Tutorial Django Parte 2: Criando a base do website</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Models">Tutorial Django Parte 3: Usando models</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Admin_site">Tutorial Django Parte 4: Django admin site</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Home_page">Tutorial Django Parte 5: Criando nossa página principal</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Generic_views">Tutorial Django Parte 6: Lista genérica e detail views</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Sessions">Tutorial Django Parte 7: Framework de Sessões</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Authentication">Tutorial Django Parte 8: Autenticação de Usuário e permissões</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Forms">Tutorial Django Parte 9: Trabalhando com formulários</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Testing">Tutorial Django Parte 10: Testando uma aplicação web Django</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Deployment">Tutorial Django Parte 11: Implantando Django em produção</a></li> + <li><a rel="nofollow" title="A página ainda não foi criada.">Segurança de aplicações web Django</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> diff --git a/files/pt-br/learn/server-side/django/forms/index.html b/files/pt-br/learn/server-side/django/forms/index.html new file mode 100644 index 0000000000..dda15b7657 --- /dev/null +++ b/files/pt-br/learn/server-side/django/forms/index.html @@ -0,0 +1,679 @@ +--- +title: 'Tutorial Django Parte 9: Trabalhando com formulários' +slug: Learn/Server-side/Django/Forms +translation_of: Learn/Server-side/Django/Forms +--- +<div> {{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/authentication_and_sessions", "Learn/Server-side/Django/Testing", "Learn/Server-side/Django")}}</div> + +<p class="summary">Neste tutorial, vamos te mostrar como trabalhar com formulários HTML no Django e, em particular, a maneira mais fácil de programar formulários para criar, alterar e excluir instâncias de modelos. Como parte desta demonstração, vamos estender o site da <a href="/pt-BR/docs/Learn/Server-side/Django/Tutorial_website_biblioteca_local">BibliotecaLocal</a> para que bibliotecários possam renovar reservas e criar, alterar e excluir autores usando nossos próprios formulários em vez do "admin" do Django.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré-requisitos:</th> + <td>Completar todos os tópicos anteriores deste tutorial, incluindo <a href="/en-US/docs/Learn/Server-side/Django/authentication_and_sessions">Django Tutorial Parte 8: Autenticação e Permissões de Usuário</a>.</td> + </tr> + <tr> + <th scope="row">Objetivo:</th> + <td> + <p>Entender como programar formulários para obter informações dos usuários e atualizar a base de dados. Entender como as <em>views</em> genéricas de edição de formulários baseadas em classes podem simplificar a criação de formulários para trabalhar com um único <em>model</em>.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="Visão_Geral">Visão Geral</h2> + +<p>Um <a href="/pt-BR/docs/Web/Guide/HTML/Forms">Formulário HTML</a> é um grupo de um ou mais campos/<em>widgets</em> em uma página web, que podem ser utilizados para coletar informações dos usuários para submetê-las a um servidor. Formulários são um mecanismo flexível para coletar input de usuário porque há <em>widgets</em> adequados para entrada de variados tipos de dados, incluindo caixas de texto, caixas de seleção, botões radiais, seletores de data etc. Formulários são também um meio relativamente seguro de compartilhar dados com o servidor, pois nos permitem enviar dados em requisições <code>POST</code> com proteção contra ataques maliciosos <strong>CSRF</strong> (<em><strong>Cross-Site Request Forgery</strong></em> - em inglês, falsificação de solicitação entre sites).</p> + +<p>Apesar de ainda não termos criado formulários até o momento neste tutorial, já os encontramos na página do Django Admin — por exemplo, a captura de tela abaixo mostra um formulário para editar um dos nossos modelos de <a href="/pt-br/docs/Learn/Server-side/Django/Models">Livros</a>, incluindo algumas listas de seleção e editores de texto.</p> + +<p><img alt="Admin Site - Book Add" src="https://mdn.mozillademos.org/files/13979/admin_book_add.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<p>Trabalhar com formulários pode ser complicado! Desenvolvedores precisam escrever HTML para o formulário, validar e limpar dados submetidos ao servidor (e possivelmente também ao navegador), programar mensagens de erro no formulário para informar o usuário de quaisquer preenchimentos inválidos, lidar com os dados quando enviados com sucesso e, finalmente, mostrar ao usuário algum indicativo de sucesso. Os <em>Django Forms </em>adiantam boa parte desses passos disponibilizando uma estrutura que permite a você definir formulários e seus campos programaticamente, e então utilizar esses objetos tanto para gerar o código HTML do formulário como para cuidar de boa parte da validação e interação de usuário.</p> + +<p>Neste tutorial, vamos te mostrar alguns dos métodos para se criar e trabalhar com formulários e, em particular, como as <em>views</em> genéricas de edição de formulários podem reduzir significativamente o seu trabalho ao criar formulários para manipular seus <em>models</em>. Ao longo do caminho, vamos estender nossa aplicação <em>LocalLibrary </em>adicionando um formulário que permita que bibliotecários renovem locações de livros, e vamos construir páginas para criar, alterar e excluir livros e autores (reproduzindo uma versão básica do formulário exibido acima para alterar livros).</p> + +<h2 id="Formulários_HTML">Formulários HTML</h2> + +<p>Antes de mais nada, um breve resumo de <a href="/pt-br/docs/Learn/HTML/Forms">Formulários HTML</a>. Considere um formulário HTML simples, com um único campo de texto para entrada do nome de uma "equipe", e sua respectiva legenda:</p> + +<p><img alt="Simple name field example in HTML form" src="https://mdn.mozillademos.org/files/14117/form_example_name_field.png" style="border-style: solid; border-width: 1px; display: block; height: 44px; margin: 0px auto; width: 399px;"></p> + +<p>O formulário é definido no HTML como uma coleção de elementos dentro das tags <code><form>...</form></code>, contendo ao menos um elemento <code>input</code> do tipo <code>type="submit"</code>.</p> + +<pre class="brush: html"><form action="/team_name_url/" method="post"> + <label for="team_name">Enter name: </label> + <input id="team_name" type="text" name="name_field" value="Default name for team."> + <input type="submit" value="OK"> +</form></pre> + +<p>Apesar de aqui nós termos um único para inserir o nome da equipe, um formulário pode ter qualquer quantidade de outros elementos de entrada e suas respectivas legendas. O atributo <code>type</code> de um campo define que tipo de widget será exibido. O <code>name</code> e o <code>id</code> de cada campo são utilizados para identificá-lo no JavaScript/CSS/HTML, enquanto <code>value</code> define o valor preenchido inicialmente no campo quando ele é exibido pela primeira vez. A legenda da equipe é especificada usando a tag <code>label</code> (veja "Enter name" na imagem acima), com um atributo <code>for</code> contendo o valor de <code>id</code> do <code>input</code> a ele associado.</p> + +<p>A entrada <code>submit</code> será exibida como um botão (por padrão) que pode ser pressionado pelo usuário para enviar ao servidor os dados preenchidos em todos os outros elementos de entrada naquele formulário (neste caso, apenas <code>team_name</code>). Os atributos do formulário definem o método HTTP (<code>method</code>) utilizado para enviar os dados e o destino para esses dados no servidor (<code>action</code>):</p> + +<ul> + <li><code>action</code>: O recurso/URL para onde os dados devem ser enviados para processamento quando o formulário é enviado. Se isso não estiver configurado (ou configurado para uma string vazia), o formulário será enviado de volta para URL da página atual.</li> + <li><code>method</code>: O método HTTP method utilizado para enviar os dados: <em>post</em> or <em>get</em>. + <ul> + <li>O método <code>POST</code> deve sempre ser utilizado se os dados forem resultar em uma alteração no banco de dados do servidor, pois é mais resistente a ataques de falsificação de solicitação entre sites.</li> + <li>O método <code>GET</code> deve ser utilizado somente para formulários que não alteram dados de usuário (um formulário de busca, por exemplo). Ele é recomendado para quando você quiser poder favoritar ou compartilhar a URL.</li> + </ul> + </li> +</ul> + +<p>O papel do servidor é primeiramente carregar o estado inicial do formulário — seja contendo campos em branco ou preenchidos com valores iniciais. Após o usuário clicar no botão de envio, o servidor receberá do navegador os dados do formulário preenchido e deverá validar as informações. Se o formulário contiver dados inválidos, o servidor deverá exibir o formulário novamente, desta vez já com os valores enviados pelo usuário nos campos preenchidos corretamente, mais uma mensagem descrevendo o problema encontrado em cada campo considerado inválido. Uma vez que o servidor receber uma requisição do formulário com todos os dados válidos, poderá exercer a ação apropriada (por exemplo, salvar os dados, retornar o resultado de uma busca, subir um arquivo etc) e então notificar o usuário.</p> + +<p>Como você pode imaginar, as ações de criar o HTML, validar os dados recebidos, re-exibir os dados enviados com mensagens de erro se necessário e realizar a operação desejada com os dados válidos podem todas tomar bastante tempo e esforço. O Django torna tudo isso muito mais fácil, adiantando parte do "trabalho braçal" e código repetitivo!</p> + +<h2 id="Processo_de_manipulação_de_formulários_Django">Processo de manipulação de formulários Django</h2> + +<p>O tratamento de formulários do Django usa todas as mesmas técnicas que aprendemos nos tutoriais anteriores (para exibir informações sobre nossos modelos): a view recebe uma solicitação, executa todas as ações necessárias, incluindo a leitura de dados dos modelos, gera e retorna uma página HTML ( de um modelo, no qual passamos um <em>contexto </em>que contém os dados a serem exibidos). O que torna as coisas mais complicadas é que o servidor também precisa processar dados fornecidos pelo usuário e exibir novamente a página se houver algum erro.</p> + +<p>Um fluxograma do processo de como o Django lida com solicitações de formulário é mostrado abaixo, começando com uma solicitação para uma página contendo um formulário (mostrado em verde).</p> + +<p><img alt="Updated form handling process doc." src="https://mdn.mozillademos.org/files/14205/Form%20Handling%20-%20Standard.png" style="display: block; height: 569px; margin: 0px auto; width: 800px;"></p> + +<p>Com base no diagrama acima, as principais coisas que o manuseio de formulários do Django faz são:</p> + +<ol> + <li>Exiba o formulário padrão na primeira vez em que for solicitado pelo usuário + <ul> + <li>O formulário pode conter campos em branco (por exemplo, se você estiver criando um novo registro) ou pode ser preenchido previamente com valores iniciais (por exemplo, se você estiver alterando um registro ou tiver valores iniciais padrão úteis).</li> + <li>O formulário é referido como <em>unbound</em> neste momento, porque não está associado a nenhum dado inserido pelo usuário (embora possa ter valores iniciais).</li> + </ul> + </li> + <li>Receba dados de uma solicitação de envio e vincule-os ao formulário. + <ul> + <li>Vincular dados ao formulário significa que os dados inseridos pelo usuário e quaisquer erros estão disponíveis quando precisamos exibir novamente o formulário.</li> + </ul> + </li> + <li>Limpe e valide os dados. + <ul> + <li>A limpeza dos dados executa a higienização da entrada (por exemplo, removendo caracteres inválidos que podem ser usados para enviar conteúdo malicioso ao servidor) e os converte em tipos consistentes de Python.</li> + <li>A validação verifica se os valores são apropriados para o campo (por exemplo, estão no período certo, não são muito curtos ou muito longos etc.)</li> + </ul> + </li> + <li>Se algum dado for inválido, exiba novamente o formulário, desta vez com valores preenchidos pelo usuário e mensagens de erro para os campos problemáticos.</li> + <li>Se todos os dados forem válidos, execute as ações necessárias (por exemplo, salve os dados, envie e envie por e-mail, retorne o resultado de uma pesquisa, faça o upload de um arquivo etc.)</li> + <li>Quando todas as ações estiverem concluídas, redirecione o usuário para outra página.</li> +</ol> + +<p>O Django fornece várias ferramentas e abordagens para ajudá-lo nas tarefas detalhadas acima. O mais fundamental é a classe <code>Form</code>, o que simplifica a geração de HTML de formulário e a limpeza/validação de dados. Na próxima seção, descreveremos como os formulários funcionam usando o exemplo prático de uma página para permitir que os bibliotecários renovem os livros.</p> + +<div class="note"> +<p><strong>Nota:</strong> Entendendo como <code>Form</code> é usado para ajudá-lo quando discutirmos as classes de estrutura de formulário mais "de alto nível" do Django.</p> +</div> + +<h2 id="Renew-book_form_usando_uma_function_view">Renew-book form usando uma function view</h2> + +<p>Em seguida, adicionaremos uma página para permitir que os bibliotecários renovem os livros emprestados. Para fazer isso, criaremos um formulário que permita aos usuários inserir um valor de data. Preencheremos o campo com um valor inicial três semanas a partir da data atual (o período normal de empréstimo) e adicionaremos alguma validação para garantir que o bibliotecário não possa inserir uma data no passado ou uma data muito distante no futuro. Quando uma data válida for inserida, nós a escreveremos no registro atual no campo <code>BookInstance.due_back</code>.</p> + +<p>O exemplo usará uma function-based view e uma classe <code>Form</code>. As seções a seguir explicam como os formulários funcionam e as alterações que você precisa fazer em nosso projeto <em>LocalLibrary</em>.</p> + +<h3 id="Form">Form</h3> + +<p>A classe <code>Form</code> é o coração do sistema de manipulação de formulários do Django. Ele especifica os campos no formulário, seu layout, exibe widgets, rótulos, valores iniciais, valores válidos e (uma vez validadas) as mensagens de erro associadas a campos inválidos. A classe também fornece métodos para renderizar-se em modelos usando formatos predefinidos (tabelas, listas etc.) ou para obter o valor de qualquer elemento (habilitando a renderização manual refinada).</p> + +<h4 id="Declarando_um_Form">Declarando um Form</h4> + +<p>A sintaxe da declaração para um <code>Form</code> é muito semelhante ao da declaração de um <code>Model</code>, e compartilha os mesmos tipos de campo (e alguns parâmetros semelhantes). Isso faz sentido porque, em ambos os casos, precisamos garantir que cada campo lide com os tipos corretos de dados, seja restrito a dados válidos e tenha uma descrição para exibição/documentação.</p> + +<p>Os dados do formulário são armazenados no arquivo forms.py de um aplicativo, dentro do diretório do aplicativo. Crie e abra o arquivo <strong>locallibrary/catalog/forms.py</strong>. Para criar um <code>Form</code>, nós importamos a biblioteca <code>forms</code>, deriva da classe <code>Form</code>, e declarar os campos do formulário. Uma classe de formulário muito básica para nosso formulário de renovação de livros da biblioteca é mostrada abaixo - adicione-a ao seu novo arquivo:</p> + +<pre class="brush: python">from django import forms + +class RenewBookForm(forms.Form): + renewal_date = forms.DateField(help_text="Enter a date between now and 4 weeks (default 3).") +</pre> + +<h4 id="Campos_do_Form">Campos do Form</h4> + +<p>Nesse caso, temos um único <code><a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#datefield">DateField</a></code> para inserir a data de renovação que será renderizada em HTML com um valor em branco, o valor padrão da label "<em>Renewal date:</em>", e algum texto de ajuda: "<em>Enter a date between now and 4 weeks (default 3 weeks).</em>" Como nenhum dos outros argumentos opcionais é especificado, o campo aceita datas usando o <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#django.forms.DateField.input_formats">input_formats</a>: YYYY-MM-DD (2016-11-06), MM/DD/YYYY (02/26/2016), MM/DD/YY (10/25/16), e será renderizado usando o padrão <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#widget">widget</a>: <a href="https://docs.djangoproject.com/en/2.1/ref/forms/widgets/#django.forms.DateInput">DateInput</a>.</p> + +<p>Existem muitos outros tipos de campos de formulário que você reconhecerá amplamente por sua semelhança com as classes de campo de modelo equivalentes: <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#booleanfield"><code>BooleanField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#charfield"><code>CharField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#choicefield"><code>ChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#typedchoicefield"><code>TypedChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#datefield"><code>DateField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#datetimefield"><code>DateTimeField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#decimalfield"><code>DecimalField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#durationfield"><code>DurationField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#emailfield"><code>EmailField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#filefield"><code>FileField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#filepathfield"><code>FilePathField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#floatfield"><code>FloatField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#imagefield"><code>ImageField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#integerfield"><code>IntegerField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#genericipaddressfield"><code>GenericIPAddressField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#multiplechoicefield"><code>MultipleChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#typedmultiplechoicefield"><code>TypedMultipleChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#nullbooleanfield"><code>NullBooleanField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#regexfield"><code>RegexField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#slugfield"><code>SlugField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#timefield"><code>TimeField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#urlfield"><code>URLField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#uuidfield"><code>UUIDField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#combofield"><code>ComboField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#multivaluefield"><code>MultiValueField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#splitdatetimefield"><code>SplitDateTimeField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#modelmultiplechoicefield"><code>ModelMultipleChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#modelchoicefield"><code>ModelChoiceField</code></a>.</p> + +<p>Os argumentos comuns à maioria dos campos estão listados abaixo (estes têm valores padrão sensíveis):</p> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#required">required</a>: Se <code>True</code>, o campo não pode ser deixado em branco ou receber um valor <code>None</code>. Os campos são obrigatórios por padrão, então você deve definir <code>required=False</code> para permitir valores em branco no formulário.</li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#label">label</a>: O label a ser usado ao renderizar o campo em HTML. Se um <a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#label">label</a> não for especificado, o Django criará um a partir do nome do campo colocando em maiúscula a primeira letra e substituindo sublinhados por espaços (e.g. <em>Renewal date</em>).</li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#label-suffix">label_suffix</a>: Por padrão, dois pontos são exibidos após o rótulo (e.g. Renewal date<strong>:</strong>). Esse argumento permite especificar um sufixo diferente contendo outros caractere(s).</li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#initial">initial</a>: O valor inicial para o campo quando o formulário é exibido.</li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#widget">widget</a>: O widget de exibição a ser usado.</li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#help-text">help_text</a> (como visto no exemplo acima): Texto adicional que pode ser exibido em formulários para explicar como usar o campo.</li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#error-messages">error_messages</a>: Uma lista de mensagens de erro para o campo. Você pode substituí-los por suas próprias mensagens, se necessário.</li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#validators">validators</a>: Uma lista de funções que serão chamadas no campo quando validadas.</li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#localize">localize</a>:Permite a localização da entrada de dados do formulário (consulte o link para obter mais informações).</li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/#disabled">disabled</a>: O campo é exibido, mas seu valor não pode ser editado se este for <code>True</code>. O padrão é <code>False</code>.</li> +</ul> + +<h4 id="Validação">Validação</h4> + +<p>O Django fornece vários locais onde você pode validar seus dados. A maneira mais fácil de validar um único campo é substituir o método <code>clean_<strong><fieldname></strong>()</code> para o campo que você deseja verificar. Por exemplo, podemos validar esse valor inserido <code>renewal_date</code> daqui a quatro semanas, implementando <code>clean_<strong>renewal_date</strong>()</code> como mostrado abaixo.</p> + +<p>Atualize seu arquivo forms.py para ficar assim:</p> + +<pre class="brush: python"><strong>import datetime</strong> + +from django import forms +<strong>from django.core.exceptions import ValidationError +from django.utils.translation import ugettext_lazy as _ +</strong> +class RenewBookForm(forms.Form): + renewal_date = forms.DateField(help_text="Enter a date between now and 4 weeks (default 3).") + +<strong> def clean_renewal_date(self): + data = self.cleaned_data['renewal_date'] + + # Check if a date is not in the past. + if data < datetime.date.today(): + raise ValidationError(_('Invalid date - renewal in past')) + + # Check if a date is in the allowed range (+4 weeks from today). + if data > datetime.date.today() + datetime.timedelta(weeks=4): + raise ValidationError(_('Invalid date - renewal more than 4 weeks ahead')) + + # Remember to always return the cleaned data. + return data</strong></pre> + +<p>Há duas coisas importantes a serem observados. A primeira é que temos nossos dados usando <code>self.cleaned_data['renewal_date']</code> e que nós retornaremos esses dados ou não podemos alterá-lo no final da função. Este passo nos leva a dados "limpos" e higienizados de potencialmente inseguro usando os validadores de entrada padrão e convertidos para o tipo padrão correto para os dados (neste caso, um objeto Python <code>datetime.datetime</code>).</p> + +<p>O segundo ponto é que, se um valor cai fora da nossa gama que levanta um <code>ValidationError</code>, especificando o texto de erro que deseja exibir no formulário se um valor inválido for inserido. Os exemplos acima também envolvem este texto em um dos <a href="https://docs.djangoproject.com/en/2.1/topics/i18n/translation/">Django's translation functions</a> <code>ugettext_lazy()</code> (importado como <code>_()</code>), que é uma boa prática se você quiser traduzir o seu site mais tarde.</p> + +<div class="note"> +<p><strong>Nota:</strong> Existem muitos outros exemplos e métodos para validar os forms <a href="https://docs.djangoproject.com/en/2.1/ref/forms/validation/">Form e field validation</a> (Django docs). Por exemplo, nos casos em que você tem vários campos que dependem uns dos outros, você pode substituir a função <a href="https://docs.djangoproject.com/en/2.1/ref/forms/api/#django.forms.Form.clean">Form.clean()</a> e novamente levantar uma <code>ValidationError</code>.</p> +</div> + +<p>Isso é tudo que necessitamos para o form neste exemplo?</p> + +<h3 id="Configuração_da_URL">Configuração da URL</h3> + +<p>Antes de criar nossa view, vamos adicionar a configuração da URL para a pagina <em>renew-books</em>. Copie a seguinte configuração para o final do aquivo <strong>locallibrary/catalog/urls.py</strong>.</p> + +<pre class="brush: python">urlpatterns += [ + path('book/<uuid:pk>/renew/', views.renew_book_librarian, name='renew-book-librarian'), +]</pre> + +<p>A configuração da URL irá redirecionar as URLs com o formato <strong>/catalog/book/<em><bookinstance id></em>/renew/</strong> para a função chamada <code>renew_book_librarian()</code> em <strong>views.py</strong>, e enviar o id <code>BookInstance</code> como parâmetro nomeado <code>pk</code>. O padrão corresponde apenas se <code>pk</code> estiver com a formatação <code>uuid</code> correta.</p> + +<div class="note"> +<p><strong>Nota</strong>: Podemos citar nos nossos dados capturados na URL "<code>pk</code>" qualquer coisa que quisermos, porque nós temos o controle completo sobra a função view (nós não estamos usando uma view detail genérica, onde se espera os parâmetros com um certo nome). Contudo, a abreviação <code>pk</code> para "chave primária", é uma convenção razoável para uso!</p> +</div> + +<h3 id="View">View</h3> + +<p>Como discutido no <a href="#django_form_handling_process">processo de manipulação de formulários Django </a>acima, a view renderizará o formulário padrão chamado pela primeira vez e então retorná-lo com mensagens de erro se os dados forem inválidos, ou processar os dados e redirecioná-lo para uma nova página se os dados forem válidos.A fim de executar essas ações diferentes, a view deve ser capas de saber se está sendo chamada pela primeira vez para renderizar o form padrão ou um subsequente para a validação dos dados.</p> + +<p>Para forms que usam uma solicitação <code>POST</code> para enviar informações para o servidor, o padrão mais comum para a view é testar se o tipo de solicitação é <code>POST</code> (<code>if request.method == 'POST':</code>) para identificar requisições válidas de formulário e <code>GET</code> (usando uma condição <code>else</code>) para identificar a requisição de criação do form inicial. Se você deseja enviar seus dados usando uma reuquisição <code>GET</code> uma abordagem típica para identificar se é a primeira ou subsequente requisição é ler os dados do formulário (por exemplo, ler um valor oculto no form).</p> + +<p>O processo de renovação de livros será gravado em nosso banco de dados, portanto, por convenção, usamos a abordagem de requisição <code>POST</code>. O fragmento de código abaixo mostra o padrão (bem padrão) para esse tipo de exibição de função.</p> + +<pre class="brush: python">import datetime + +from django.shortcuts import render, get_object_or_404 +from django.http import HttpResponseRedirect +from django.urls import reverse + +from catalog.forms import RenewBookForm + +def renew_book_librarian(request, pk): + book_instance = get_object_or_404(BookInstance, pk=pk) + + # If this is a POST request then process the Form data +<strong> if request.method == 'POST':</strong> + + # Create a form instance and populate it with data from the request (binding): + form = RenewBookForm(request.POST) + + # Check if the form is valid: + <strong>if form.is_valid():</strong> + # process the data in form.cleaned_data as required (here we just write it to the model due_back field) + book_instance.due_back = form.cleaned_data['renewal_date'] + book_instance.save() + + # redirect to a new URL: + return HttpResponseRedirect(reverse('all-borrowed') ) + + # If this is a GET (or any other method) create the default form. +<strong> else:</strong> + proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3) + form = RenewBookForm(initial={'renewal_date': proposed_renewal_date}) + + context = { + 'form': form, + 'book_instance': book_instance, + } + + return render(request, 'catalog/book_renew_librarian.html', context)</pre> + +<p>Primeiro, importamos nosso formulário (<code>RenewBookForm</code>) e outros objetos/métodos úteis usados no corpo da função <em>view</em>:</p> + +<ul> + <li><code><a href="https://docs.djangoproject.com/en/2.1/topics/http/shortcuts/#get-object-or-404">get_object_or_404()</a></code>: Retorna um objeto especificado de um modelo com base em seu valor de chave primária, e gera uma exceção <code>Http404</code> (não encontrada) se o registro não existir. </li> + <li><code><a href="https://docs.djangoproject.com/en/2.1/ref/request-response/#django.http.HttpResponseRedirect">HttpResponseRedirect</a></code>: Isso cria um redirecionamento para uma URL especificada (código de status HTTP 302). </li> + <li><code><a href="https://docs.djangoproject.com/en/2.1/ref/urlresolvers/#django.urls.reverse">reverse()</a></code>: Isso gera uma URL a partir de uma configuração de nome de URL e um conjunto de argumentos. É o equivalente em Python da tag <code>url</code> que usamos em nossos <em>templates</em>.</li> + <li><code><a href="https://docs.python.org/3/library/datetime.html">datetime</a></code>: Uma biblioteca Python para a manipulação de dadas e tempo.</li> +</ul> + +<p>Na <em>view</em>, primeiro usamos o argumento <code>pk</code> em <code>get_object_or_404()</code> para obter o <code>BookInstance</code> atual (se isso não existir, a <em>view</em> será imediatamente encerrada e a página exibirá um erro "não encontrada"). Se essa não for uma solicitação <code>POST</code> (manipulada pela cláusula <code>else</code>) criamos o formulário padrão passando o valor <code>initial</code> para o campo <code>renewal_date</code> (como mostrado abaixo em negrito, isso é, 3 semanas a partir da data atual). </p> + +<pre class="brush: python"> book_instance = get_object_or_404(BookInstance, pk=pk) + + # If this is a GET (or any other method) create the default form + else: + proposed_renewal_date = datetime.date.today() + datetime.timedelta(<strong>weeks=3</strong>) + <strong>form = RenewBookForm(initial={'renewal_date': proposed_renewal_date})</strong> + + context = { + 'form': form, + 'book_instance': book_instance, + } + + return render(request, 'catalog/book_renew_librarian.html', context)</pre> + +<p>Depois de criar o <em>form</em>, chamamos <code>render()</code> para criar a página HTML, especificando o <em>template</em> e o <em>context</em> que contém o nosso <em>form</em>. Nesse caso, o <em>context</em> também contem nosso <code>BookInstance</code>, que usaremos no <em>template</em> para fornecer informações sobre o livro que estamos renovando.</p> + +<p>No entenato, se essa for uma solicitação <code>POST</code> , criamos nosso objeto <code>form</code> e prenchemos com dados da requisição. Esse processo é chamado <em>"binding"</em> e permite validar o formulário. Em seguida, verificamos se o formulário é válido, que executa todo o código de validação em todos os campos — incluindo o código genérico para verificar se nosso campo de data é realmente uma data válida e a função específica <code>clean_renewal_date()</code> do nosso formulário para verificar se a data está na faixa certa. </p> + +<pre class="brush: python"> book_instance = get_object_or_404(BookInstance, pk=pk) + + # If this is a POST request then process the Form data + if request.method == 'POST': + + # Create a form instance and populate it with data from the request (binding): +<strong> form = RenewBookForm(request.POST)</strong> + + # Check if the form is valid: + if form.is_valid(): + # process the data in form.cleaned_data as required (here we just write it to the model due_back field) + book_instance.due_back = form.cleaned_data['renewal_date'] + book_instance.save() + + # redirect to a new URL: + return HttpResponseRedirect(reverse('all-borrowed') ) + + context = { + 'form': form, + 'book_instance': book_instance, + } + + return render(request, 'catalog/book_renew_librarian.html', context)</pre> + +<p>Se o formulário não é válido, chamamos <code>render()</code> novamente, mas dessa vez o valor passado de <em>form</em> no <em>context</em> incluirá mensagens de erro. </p> + +<p>Se o formulário é válido, então podemos começar a utilizar os dados, acessando-o por meio do atributo<code>form.cleaned_data</code> (Ex. <code>data = form.cleaned_data['renewal_date']</code>). Aqui, apenas salvamos os dados no atributo <code>due_back</code> do objeto <code>BookInstance</code> associado.</p> + +<div class="warning"> +<p><strong>Importante</strong>: Embora você também possa acessar os dados do formulário diretamente por meio do <em>request</em> (por exemplo, <code>request.POST['renewal_date']</code> ou <code>request.GET['renewal_date']</code> se utilizando requisição GET), isso NÃO é recomendado. O dado limpo é "higienizado", validado, e convertido em tipo compatível com Python.</p> +</div> + +<p>A estapa final da manipulação de formulário na parte da <em>view</em> é redirecionar para outra página, geralmente uma página de "êxito". Nesse caso, usamos <code>HttpResponseRedirect</code> e <code>reverse()</code> para redirecionar para a <em>view </em>chamada <code>'all-borrowed'</code> (isso foi criado como desafio em <a href="/en-US/docs/Learn/Server-side/Django/authentication_and_sessions#Challenge_yourself">Tutorial Django Parte 8: Autenticação de usuário e permissões</a>). Se você não criou está página considere redirecionar para a página principal na URL '/').</p> + +<p>Isso é tudo que é necessário para a manipulação do formulario, mas ainda precisamo restringir o acesso a <em>view</em> aos bibliotecários. Provavelmente devemos criar uma nova permissão em <code>BookInstance</code> ("<code>can_renew</code>"), mas, para simplificar as coisa aqui, apenas usamos o <em>decorator </em>da função<em>, </em><code>@permission_required</code> com nossa permissão existente <code>can_mark_returned</code>.</p> + +<p>A <em>view</em> final, é portanto, como mostrado abaixo. Por favor, copie isso na parte inferior de <strong>locallibrary/catalog/views.py</strong>.</p> + +<pre><strong>import datetime + +from django.contrib.auth.decorators import permission_required</strong> +from django.shortcuts import get_object_or_404 +from django.http import HttpResponseRedirect +from django.urls import reverse + +from catalog.forms import RenewBookForm + +<strong>@permission_required('catalog.can_mark_returned')</strong> +def renew_book_librarian(request, pk): + """View function for renewing a specific BookInstance by librarian.""" + book_instance = get_object_or_404(BookInstance, pk=pk) + + # If this is a POST request then process the Form data + if request.method == 'POST': + + # Create a form instance and populate it with data from the request (binding): + form = RenewBookForm(request.POST) + + # Check if the form is valid: + if form.is_valid(): + # process the data in form.cleaned_data as required (here we just write it to the model due_back field) + book_instance.due_back = form.cleaned_data['renewal_date'] + book_instance.save() + + # redirect to a new URL: + return HttpResponseRedirect(reverse('all-borrowed') ) + + # If this is a GET (or any other method) create the default form. + else: + proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3) + form = RenewBookForm(initial={'renewal_date': proposed_renewal_date}) + + context = { + 'form': form, + 'book_instance': book_instance, + } + + return render(request, 'catalog/book_renew_librarian.html', context) +</pre> + +<h3 id="O_template">O <em>template</em></h3> + +<p>Crie o <em>template</em> mencionado na <em>view</em> (<strong>/catalog/templates/catalog/book_renew_librarian.html</strong>) e copie o código abaixo nele:</p> + +<pre class="brush: html">{% extends "base_generic.html" %} + +{% block content %} + <h1>Renew: \{{ book_instance.book.title }}</h1> + <p>Borrower: \{{ book_instance.borrower }}</p> + <p{% if book_instance.is_overdue %} class="text-danger"{% endif %}>Due date: \{{ book_instance.due_back }}</p> + +<strong> <form action="" method="post"> + {% csrf_token %} + <table> + \{{ form.as_table }} + </table> + <input type="submit" value="Submit"> + </form></strong> +{% endblock %}</pre> + +<p>A maior parte disso será totalmente familiar dos tutoriais anteriores. Estendemos o <em>template</em> base e então redefinimos o bloco <em>content</em>. Somos capazes de referenciar <code>\{{ book_instance }}</code> (e suas variáveis) porque foi passado no objeto <em>context</em> na função <code>render()</code>, e nós as usamos para listar o título do livro, tomador do empréstimo, e a data de devolução original.</p> + +<p>O código do formulário é relativamente simples. Primeiro, declaramos a tag <code>form</code>, especificando onde o formulário deve ser submetido (<code>action</code>) e o <code>method</code> para submeter os dados (nesse caso, um "HTTP POST") — se você lembrar da visão geral de <a href="#HTML_forms">Formulários HTML</a> na parte superior da página, uma <code>action</code> vazia, como mostrada, significa que os dados do formulário serão postados de volta para a URL atual da página (que é o que queremos!). Dentro das tags, definimos a entrada <code>submit</code>, que um usuário pode apertar para submeter os dados. O <code>{% csrf_token %}</code> adicionado apenas dentro das tags do formulário é parte da proteção de falsificação ente sites (cross-site forgery protection) do Django.</p> + +<div class="note"> +<p><strong>Nota:</strong> Adicione o <code>{% csrf_token %}</code> para todos os <em>templates </em>Django que você cria que utiliza <code>POST</code> para submeter dados. Isso reduzirá a chance de que os formulários sejam invadidos por usuários maliciosos.</p> +</div> + +<p>Tudo que resta é a variável <code>\{{ form }}</code> do <em>template</em>, que passamos para o <em>template</em> no dicionário <em>context</em>. Talvez, sem supresa, quando usado como mostrado, isto fornece a renderização padrão de todos os campos do formulário, incluindo seus <em>labels</em>, <em>widgets</em> e texto de ajuda — a renderização é como mostrado abaixo:</p> + +<pre class="brush: html"><tr> + <th><label for="id_renewal_date">Renewal date:</label></th> + <td> + <input id="id_renewal_date" name="renewal_date" type="text" value="2016-11-08" required> + <br> + <span class="helptext">Enter date between now and 4 weeks (default 3 weeks).</span> + </td> +</tr> +</pre> + +<div class="note"> +<p><strong>Nota:</strong> Talvez não seja óbvio porque temos apenas um campo, mas, por padrão, todo campo é definido em sua própria linha de tabela. Essa mesma renderização é fornecida se você referenciar a váriavel de <em>template</em> <code>\{{ form.as_table }}</code>.</p> +</div> + +<p>Se você fosse inserir uama data inválida, você também obteria uma lista dos erros renderizados na página (mostrado em negrito abaixo).</p> + +<pre class="brush: html"><tr> + <th><label for="id_renewal_date">Renewal date:</label></th> + <td> +<strong> <ul class="errorlist"> + <li>Invalid date - renewal in past</li> + </ul></strong> + <input id="id_renewal_date" name="renewal_date" type="text" value="2015-11-08" required> + <br> + <span class="helptext">Enter date between now and 4 weeks (default 3 weeks).</span> + </td> +</tr></pre> + +<h4 id="Outras_maneiras_de_usar_variável_de_formulário_de_template">Outras maneiras de usar variável de formulário de <em>template</em></h4> + +<p>Usando <code>\{{ form.as_table }}</code> como mostrado acima, cada campo é renderizado como uma linha da tabela. Você também pode renderizar cada campo como um item da lista (usando <code>\{{ form.as_ul }}</code> ) como um parágrafo (usando <code>\{{ form.as_p }}</code>).</p> + +<p>Também é possível ter controle completo sobre a renderização de cada parte do formulário, indexando suas propriedades usando notação de ponto. Assim, por exemplo, podemos acessar vários itens separados pelo nosso campo <code>renewal_date</code>:</p> + +<ul> + <li><code>\{{ form.renewal_date }}:</code> O campo todo.</li> + <li><code>\{{ form.renewal_date.errors }}</code>: A lista de erros.</li> + <li><code>\{{ form.renewal_date.id_for_label }}</code>: O id do <em>label</em>.</li> + <li><code>\{{ form.renewal_date.help_text }}</code>: O texto de ajuda do campo.</li> +</ul> + +<p>Para mais exemplos de como renderizar formulários manualmente em <em>templates </em>e fazer loop nos campos de <em>templates</em>, veja <a href="https://docs.djangoproject.com/en/2.1/topics/forms/#rendering-fields-manually">Trabalhando com formulários > Renderizando campos manualmente</a> (Django docs).</p> + +<h3 id="Testando_a_página">Testando a página</h3> + +<p>Se você aceitou o "desafio" em <a href="/en-US/docs/Learn/Server-side/Django/authentication_and_sessions#Challenge_yourself">Tutorial Django Parte 8: Autenticação de usuário e permissões</a> você terá uma lista de todos os livros emprestados na biblioteca, que é visível apenas aos funcionários da biblioteca. Podemos adicionar um <em>link</em> para nossa página de renovação ao lado de cada item, usando o código de modelo abaixo.</p> + +<pre class="brush: html">{% if perms.catalog.can_mark_returned %}- <a href="{% url 'renew-book-librarian' bookinst.id %}">Renew</a> {% endif %}</pre> + +<div class="note"> +<p><strong>Nota</strong>: Lembre que seu login de teste precisará ter a permissão "<code>catalog.can_mark_returned</code>" para acessar a página de renovação de livro (talvez use sua conta de superusuário).</p> +</div> + +<p>Você pode, alternativamente, construir manualmente uma URL de teste como esta — <a href="http://127.0.0.1:8000/catalog/book/<bookinstance id>/renew/">http://127.0.0.1:8000/catalog/book/<em><bookinstance_id></em>/renew/</a> (um id válido de <em>bookinstance</em> pode ser obtido navegando para a página de detalhes de um livro em sua biblioteca, e copiando o campo<code>id</code>).</p> + +<h3 id="Com_o_que_se_parece">Com o que se parece?</h3> + +<p>Se você tiver sucesso, o formulário padrão será semelhante a este:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14209/forms_example_renew_default.png" style="border-style: solid; border-width: 1px; display: block; height: 292px; margin: 0px auto; width: 680px;"></p> + +<p>O formulário com um valor inválido inserido terá a seguinte aparência:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14211/forms_example_renew_invalid.png" style="border-style: solid; border-width: 1px; display: block; height: 290px; margin: 0px auto; width: 658px;"></p> + +<p>A lista de todos os livros com o link de renovação será assim:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14207/forms_example_renew_allbooks.png" style="border-style: solid; border-width: 1px; display: block; height: 256px; margin: 0px auto; width: 613px;"></p> + +<h2 id="ModelForms">ModelForms</h2> + +<p>Criar uma classe<code>Form</code> usando a abordagem descrita acima é muito flexível, permitindo criar qualquer tipo de página de formulário que você desejar e associá-la a qualquer modelo ou modelos.</p> + +<p>Contudo, se você só precisa de um formulário para mapear os campos de um único modelo, então seu modelo já definirá a maioria das informações que vocÊ precisa em seu formulário: campos, rótulos, texto de ajuda, etc. Em vez de recriar as definições do modelo em seu formulário, é mais fácil usar a classe auxiliar <a href="https://docs.djangoproject.com/en/2.1/topics/forms/modelforms/">ModelForm</a> para criar o formulário a partir do seu modelo. Esse <code>ModelForm</code> pode ser usado em suas <em>views</em> exatamente da mesma maneira como um <code>Form</code> comum.</p> + +<p>Uma <code>ModelForm</code> contém o mesmo campo que nossa <code>RenewBookForm</code> original, como mostrado abaixo. Tudo que você precisa fazer para criar o formulário é adicionar <code>class Meta</code> com o <code>model</code> (<code>BookInstance</code>) associado e uma lista dos <code>fields</code> do modelo a serem incluídos no formulário (você pode incluir todos os campos usando <code>fields = '__all__'</code>, ou pode usar <code>exclude</code> (em vez de <code>fields</code>) para especificar os campos do modelo a não incluir).</p> + +<pre class="brush: python">from django.forms import ModelForm + +from catalog.models import BookInstance + +class RenewBookModelForm(ModelForm): +<strong> class Meta: + model = BookInstance + fields = ['due_back']</strong> +</pre> + +<div class="note"> +<p><strong>Nota</strong>: Isso pode não parecer muito mais simples do que apenas usar um <code>Form</code> (e não é nesse caso, porque temos apenas um campo). No entanto, se você tiver muitos campos, isso pode reduzir a quantidade de código significativamente!</p> +</div> + +<p>O restante das informações vem das definições de campo do modelo (ex. rótulos, <em>widgets</em>, texdo de ajuda, mensagens de erro). Se isso não for suficiente, então podemos substituí-los em nossa <code>class Meta</code>, especificando um dicionário contendo o campo para mudar e seu novo valor. Por exemplo, neste formulário podemos querer um rótulo para nosso campo de "<em>Renewal date</em>" (em vez do padrão baseado no padrão com base no nome do campo: <em>Due Back</em>), e também queremos que nosso campo de ajuda seja específico para esse caso de uso. A <code>Meta</code> abaixo mostra como substituir esses campos, e você pode definir <code>widgets</code> and <code>error_messages</code> da mesma forma, se os padrões não forem suficientes.</p> + +<pre class="brush: python">class Meta: + model = BookInstance + fields = ['due_back'] +<strong> labels = {'due_back': _('New renewal date')} + help_texts = {'due_back</strong><strong>': _('Enter a date between now and 4 weeks (default 3).')} </strong> +</pre> + +<p>Para adicionar validação você pode usar a mesma abordagem como uma <code>Form</code> normal — você define uma função chamada <code>clean_<em>field_name</em>()</code> e <em>raise</em> a exceção <code>ValidationError</code> para valores inválidos. A única diferença em relação ao nosso <em>form </em>original é que o campo do modelo é chamdo <code>due_back</code> e não "<code>renewal_date</code>". Essa mudança é necessária pois o campo correspondente em <code>BookInstance</code> é chamado <code>due_back</code>. </p> + +<pre class="brush: python">from django.forms import ModelForm + +from catalog.models import BookInstance + +class RenewBookModelForm(ModelForm): +<strong> def clean_due_back(self): + data = self.cleaned_data['due_back</strong><strong>'] + + # Check if a date is not in the past. + if data < datetime.date.today(): + raise ValidationError(_('Invalid date - renewal in past')) + + <strong># Check if a date is in the allowed range (+4 weeks from today).</strong> + if data > datetime.date.today() + datetime.timedelta(weeks=4): + raise ValidationError(_('Invalid date - renewal more than 4 weeks ahead')) + + # Remember to always return the cleaned data. + return data +</strong> + class Meta: + model = BookInstance + fields = ['due_back'] + labels = {'due_back': _('Renewal date')} + help_texts = {'due_back': _('Enter a date between now and 4 weeks (default 3).')} +</pre> + +<p>A classe <code>RenewBookModelForm</code> acima agora é funcionalmente equivalente a nossa original <code>RenewBookForm</code>. Você poderia importar e usar onde quer que você use <code>RenewBookForm</code> desde que você também atualize o nome da variável do formulário correspondente de <code>renewal_date</code> para <code>due_back</code> como na segunda declaração do formulário: <code>RenewBookModelForm(initial={'due_back': proposed_renewal_date}</code>.</p> + +<h2 id="Views_genéricas_de_edição">Views genéricas de edição</h2> + +<p>O algoritmo de manipulação de formulários que usamos em nosso exemplo de função <em>view</em> acima, representa um padrão extremamente comum nas <em>views</em> de edição de formulário. Django abstrai grande parte desse "<em>boilerplate</em>" (trabalho repetitivo) para você, criando <a href="https://docs.djangoproject.com/en/2.1/ref/class-based-views/generic-editing/">views genéricas de edição</a> para views de criação, edição e exclusão baseadas em modelos. Não apenas lidam com o comportamento de visualização, mas também criam automaticamente para você a classe de formulário (uma <code>ModelForm</code>) a partir do modelo.</p> + +<div class="note"> +<p><strong>Nota: </strong>Além das <em>views</em> de edição descritas aqui, há também uma classe <a href="https://docs.djangoproject.com/en/2.1/ref/class-based-views/generic-editing/#formview">FormView</a>, que fica em algum lugar entre nossa função <em>view</em> e outra <em>view</em> genérica em termos de "flexibilidade" vs "esforço de codificação". Usando <code>FormView</code>, você ainda precisa criar seu <code>Form</code>, mas não precisa implementar todos os padrões de manipulação de formulário. Em vez disso, você tem apenas que fornecer uma implementação da função que será chamada assim que o envio for válido.</p> +</div> + +<p>Nessa seção vamos usar <em>views</em> genericas de edição para criar páginas para adicionar funcionalidades para criar, editar e excluir registros de <code>Author</code> da nossa biblioteca — fornecendo efetivamente uma reimplementação básica de parte do site <em>Admin</em> (isso poderá ser útil se você precisa oferecer funcionalidades de administrador de uma maneira mais flexível que possa ser fornecida pelo dite <em>Admin</em>).</p> + +<h3 id="Views"><em>Views</em></h3> + +<p>Abra o arquivo das <em>views</em> (<strong>locallibrary/catalog/views.py</strong>) e acrescente o seguinte bloco de código na parte inferior:</p> + +<pre class="brush: python">from django.views.generic.edit import CreateView, UpdateView, DeleteView +from django.urls import reverse_lazy + +from catalog.models import Author + +class AuthorCreate(CreateView): + model = Author + fields = '__all__' + initial = {'date_of_death': '05/01/2018'} + +class AuthorUpdate(UpdateView): + model = Author + fields = ['first_name', 'last_name', 'date_of_birth', 'date_of_death'] + +class AuthorDelete(DeleteView): + model = Author + success_url = reverse_lazy('authors')</pre> + +<p>Como você pode ver, para criar, atualizar e excluir as <em>views</em>, você precisa derivar de <code>CreateView</code>, <code>UpdateView</code>, e <code>DeleteView</code> (respectivamente) e então definir o modelo associado.</p> + +<p>Para os casos "criar" e "atualizar" você também precisa especificar os campos para mostrar no formulário (usando a mesma sintaxe que para <code>ModelForm</code>). Nesse caso, nós mostramos ambas as sintaxes para mostrar todos (<em>"all"</em>) campos e como você pode listar eles individualmente. Você também pode especificar valores iniciais para cada campo usando um dicionário com pares nome_campo/valor (aqui, arbitrariamente, definimos a data de morte para fins de demonstração — talvez você queira remover isso!). Por padrão, essas <em>views</em> irão redirecionar, se houver sucesso, para uma página mostrando o item do modelo recentemente criado/editado, que no nosso caso será a página de visualização de detalhes do autor que criamos em um tutorial anterior. Você pode especificar ums local de redirecionamento alternativo, declarando explicitamente o parâmetro <code>success_url</code> (como feito na classe <code>AuthorDelete</code>).</p> + +<p>A classe <code>AuthorDelete</code> não precisa mostrar nenhum dos campos, então eles não precisam ser especificados. No entanto, você precisa especificar a <code>success_url</code>, porque não há um valor padrão óbvio para o Django usar. Nesse caso, usamos a função <code><a href="https://docs.djangoproject.com/en/2.1/ref/urlresolvers/#reverse-lazy">reverse_lazy()</a></code> para redirecioanr para nossa lista de autores depois que um autor é excluido — <code>reverse_lazy()</code> é uma versão executada "preguiçosamente" de <code>reverse()</code>, usada aqui porque estamos fornecendo uma URL para um atributo baseado em classe de <em>view</em>.</p> + +<h3 id="Templates"><em>Templates</em></h3> + +<p>As <em>views</em> "<em>create</em>" e "<em>update</em>" usam o mesmo <em>template</em> por padrão, que serão nomeadas seguindo o modelo: <em>model_name</em><strong>_form.html</strong> (você pode mudar o sufixo para algo diferente de <strong>_form</strong> usando o campo <code>template_name_suffix</code> em sua <em>view</em>, ex. <code>template_name_suffix = '_other_suffix'</code>)</p> + +<p>Crie o arquivo de <em>template </em><strong>locallibrary/catalog/templates/catalog/author_form.html</strong> e copie o texto abaixo.</p> + +<pre class="brush: html">{% extends "base_generic.html" %} + +{% block content %} + <form action="" method="post"> + {% csrf_token %} + <table> + \{{ form.as_table }} + </table> + <input type="submit" value="Submit"> + </form> +{% endblock %}</pre> + +<p>Isso é semelhante aos nossos formulários anteriores e renderiza os campos usando uma tabela. Note também como novamente declaramos o <code>{% csrf_token %}</code> para garantir que nossos formulários são resistentes a ataques CSRF.</p> + +<p>A <em>view</em> "delete" espera encontrar um <em>template</em> nomeado com o formato <em>model_name</em><strong>_confirm_delete.html</strong> (novamente, você pode mudar o sufixo usando <code>template_name_suffix</code> em sua <em>view</em>). Crie o arquivo de <em>template</em> <strong>locallibrary/catalog/templates/catalog/author_confirm_delete</strong><strong>.html</strong> e copie o texto abaixo.</p> + +<pre class="brush: html">{% extends "base_generic.html" %} + +{% block content %} + +<h1>Delete Author</h1> + +<p>Are you sure you want to delete the author: \{{ author }}?</p> + +<form action="" method="POST"> + {% csrf_token %} + <input type="submit" value="Yes, delete."> +</form> + +{% endblock %} +</pre> + +<h3 id="URL_configurations">URL configurations</h3> + +<p>Abra seu arquivo de configuração de URL (<strong>locallibrary/catalog/urls.py</strong>) e adicione a seguinte configuração no final do arquivo:</p> + +<pre class="brush: python">urlpatterns += [ + path('author/create/', views.AuthorCreate.as_view(), name='author_create'), + path('author/<int:pk>/update/', views.AuthorUpdate.as_view(), name='author_update'), + path('author/<int:pk>/delete/', views.AuthorDelete.as_view(), name='author_delete'), +]</pre> + +<p>Não há nada particularmente novo aqui! Você pode ver que as <em>views</em> são classes, e portanto devem ser chamadas via <code>.as_view()</code>, e você deve poder reconhecer os padrões URL em cada caso. Devemos usar <code>pk</code> como o nome para nosso valor capturado de chave primária (<em>primary key</em>), como esse é o nome do parâmetro esperado pelas classes <em>view</em>.</p> + +<p>As páginas de criação, atualização e remoção de autor agora estão prontas para teste (neste caso, não nos incomodaremos em conectá-las a barra lateral do site, embora você possa fazer se desejar).</p> + +<div class="note"> +<p><strong>Nota</strong>: Usuários observadores devem ter notado que não fizemos nada para previnir que usuários não autorizadosde acessem as páginas! Deixamos isso como um exercício para você (dica: você pode usar <code>PermissionRequiredMixin</code> e criar uma nova permissão ou reutilizar nossa permissão <code>can_mark_returned</code>).</p> +</div> + +<h3 id="Testando_a_página_2">Testando a página</h3> + +<p>Primeiro, efetue login no site com uma conta que possua as permissões que você decidiu que são necessárias para acessar a página de edição de autor.</p> + +<p>Então navegue para a página de criação de autor: <a href="http://127.0.0.1:8000/catalog/author/create/">http://127.0.0.1:8000/catalog/author/create/</a>, que deve parecer como a captura de tela abaixo.</p> + +<p><img alt="Form Example: Create Author" src="https://mdn.mozillademos.org/files/14223/forms_example_create_author.png" style="border-style: solid; border-width: 1px; display: block; height: 184px; margin: 0px auto; width: 645px;"></p> + +<p>Entre com valores para os campos e então pressione <strong>Submit</strong> para dalvar o registro de autor. Você agora deve ser direcionado para uma visualização detalhada para o seu novo autor, com uma URL de algo como <em>http://127.0.0.1:8000/catalog/author/10</em>.</p> + +<p>Você pode testar edição de registros enexando <em>/update/</em> ao final da URL da página de detalhe (ex. <em>http://127.0.0.1:8000/catalog/author/10/update/</em>) — não mostramos uma captura de tela, porque se parace com a página de criação</p> + +<p>Finalmente, podemos excluir a página anexando <em>delete</em> ao final da URL da visualização detalhada do autor (ex. <em>http://127.0.0.1:8000/catalog/author/10/delete/</em>). Django deve exibir a página de exclusão mostrada abaixo. Pressione <strong>Yes, delete.</strong> para remover o registro e ser levado para a lista de todos os autores.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14221/forms_example_delete_author.png" style="border-style: solid; border-width: 1px; display: block; height: 194px; margin: 0px auto; width: 561px;"></p> + +<h2 id="Desafie-se">Desafie-se</h2> + +<p>Crie alguns <em>forms</em> para criar, editar e excluir registros de <code>Book</code>. Você pode utilizar exatamente a mesma estrutura que a de <code>Authors</code>. Se seu <em>template</em> <strong>book_form.html</strong> é apenas uma cópia renomeada de <strong>author_form.html</strong> , então a nova página "criar livro" será semelhante a captura de tela abaixo:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14225/forms_example_create_book.png" style="border-style: solid; border-width: 1px; display: block; height: 521px; margin: 0px auto; width: 595px;"></p> + +<ul> +</ul> + +<h2 id="Resumo">Resumo</h2> + +<p>Criar e manipular formulários pode ser um processo complicado! Django torna muito mais fácil fornecendo mecanismos programáticos para declarar, renderizar e validar formulários. Além disso, Django fornece <em>views</em> genéricas de edição de formulário, isso pode fazes quase todo trabalho para definir páginas que podem criar, editar e excluir registros associados com uma única instância de <em>model.</em></p> + +<p>Há muito mais que pode ser feito com formulários (confira abaixo nossa lista Veja também), mas agora você deve entender como adicionar formulários básicos e o código de manipulação de formulários para seus próprios websites.</p> + +<h2 id="Veja_também">Veja também</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.1/topics/forms/">Trabalhando com formulários</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.1/intro/tutorial04/#write-a-simple-form">Escrevendo seu primeiro <em>app</em> Django, parte 4 > Escrevendo um formulário simples</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/forms/api/">A API <em>Forms</em></a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/forms/fields/">Form fields</a> (Django docs) </li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/forms/validation/">Formulários e validação de campos</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.1/topics/class-based-views/generic-editing/">Manipulação de formulários com <em>views</em> baseadas em classe</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.1/topics/forms/modelforms/">Criando formulários com <em>models</em></a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/class-based-views/generic-editing/">Views genéricas de edição</a> (Django docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/authentication_and_sessions", "Learn/Server-side/Django/Testing", "Learn/Server-side/Django")}}</p> + +<h2 id="Neste_módulo">Neste módulo</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Introdução ao Django</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Configurando um ambiente de desenvolvimento Django</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django: </a><a rel="nofollow" title="A página ainda não foi criada.">Website de uma Biblioteca Local</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial</a> <a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Parte 2: </a><a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/skeleton_website">Criando a base do website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial</a> <a href="/en-US/docs/Learn/Server-side/Django/Models">Django Parte 3: Usando <em>models</em></a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial</a> <a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Parte 4: Django admin site</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial</a> <a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Parte 5: Criando nossa página principal</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial</a> <a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Parte 6: </a><a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/Generic_views">Lista genérica e <em>detail views</em></a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial</a> <a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Parte 7: </a><a rel="nofollow" title="A página ainda não foi criada.">Framework de Sessões</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial</a> <a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Parte 8: </a><a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/Authentication">Autenticação de Usuário e permissões</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial</a> <a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Parte 9: </a><a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/Forms">Trabalhando com formulários</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial</a> <a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Parte 10: </a><a rel="nofollow" title="A página ainda não foi criada.">Testando uma aplicação web Django</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial</a> <a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Parte 11: </a><a rel="nofollow" title="A página ainda não foi criada.">Implantando Django em produção</a></li> + <li><a rel="nofollow" title="A página ainda não foi criada.">Segurança de aplicações web Django</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> diff --git a/files/pt-br/learn/server-side/django/generic_views/index.html b/files/pt-br/learn/server-side/django/generic_views/index.html new file mode 100644 index 0000000000..f5a176b192 --- /dev/null +++ b/files/pt-br/learn/server-side/django/generic_views/index.html @@ -0,0 +1,617 @@ +--- +title: 'Tutorial Django Parte 6: Lista genérica e detail views' +slug: Learn/Server-side/Django/Generic_views +translation_of: Learn/Server-side/Django/Generic_views +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Home_page", "Learn/Server-side/Django/Sessions", "Learn/Server-side/Django")}}</div> + +<p class="summary">Este tutorial estende nosso website <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a>, adicionando páginas de lista e detalhes para livros e autores. Aqui, aprenderemos sobre visualizações genéricas baseadas em classe e mostraremos como elas podem reduzir a quantidade de código que você precisa escrever para casos de uso comuns. Também abordaremos o tratamento de URLs em mais detalhes, mostrando como executar a correspondência básica de padrões.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré-requisitos:</th> + <td>Conclua todos os tópicos do tutorial anterior, incluindo <a href="/pt-br/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a>.</td> + </tr> + <tr> + <th scope="row">Objetivo:</th> + <td>Para entender onde e como usar modos de exibição genéricos baseados em classe e como extrair padrões de URLs e passar as informações para modos de exibição.</td> + </tr> + </tbody> +</table> + +<h2 id="Visão_global">Visão global</h2> + +<p>Neste tutorial, vamos concluir a primeira versão do website <a href="https://developer.mozilla.org/pt-br/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> adicionando páginas de lista e detalhes de livros e autores (ou, para ser mais preciso, mostraremos como implementar as páginas do livro e você mesmo irá criar as páginas dos autores!)</p> + +<p>O processo é semelhante à criação da página index, que mostramos no tutorial anterior. Ainda precisamos criar mapas de URL, views e templates. A principal diferença é que, para as páginas de detalhes, teremos o desafio adicional de extrair informações de padrões no URL e passá-las para a visualização. Para essas páginas, demonstraremos um tipo de exibição completamente diferente: lista genérica baseada em classe e exibições detalhadas. Isso pode reduzir significativamente a quantidade de código de visualização necessária, facilitando a gravação e a manutenção.</p> + +<p>A parte final do tutorial demonstrará como paginar seus dados ao usar visualizações de lista genéricas baseadas em classe.</p> + +<h2 id="Book_list_page">Book list page</h2> + +<p>A página da lista de livros exibirá uma lista de todos os registros de livros disponíveis na página, acessados usando o URL: <code>catalog/books/</code>. A página exibirá um título e um autor para cada registro, com o título sendo um hiperlink para a página de detalhes do livro associada. A página terá a mesma estrutura e navegação que todas as outras páginas do site e, portanto, podemos estender o modelo base (<strong>base_generic.html</strong>) que criamos no tutorial anterior.</p> + +<h3 id="URL_mapping">URL mapping</h3> + +<p>Abra <strong>/catalog/urls.py</strong> e copie na linha mostrada em negrito abaixo. Quanto à página index, a função <code>path()</code> define um padrão para corresponder ao URL (<strong>'books/'</strong>), a função view que será chamado se o URL corresponder (<code>views.BookListView.as_view()</code>), e um nome para esse mapeamento específico.</p> + +<pre class="brush: python notranslate">urlpatterns = [ + path('', views.index, name='index'), +<strong> </strong>path<strong>('books/', views.BookListView.as_view(), name='books'),</strong> +]</pre> + +<p>Conforme discutido no tutorial anterior, o URL já deve ter correspondencia <code>/catalog</code>, então a visualização será realmente chamada para o URL: <code>/catalog/books/</code>.</p> + +<p>A função view tem um formato diferente do que antes - é porque essa view será realmente implementada como uma classe. Herdaremos de uma função view genérica existente que já faz a maior parte do que queremos que essa função view faça, em vez de escrever a nossa a partir do zero.</p> + +<p>Para as class-based views do Django, acessamos uma função de visualização apropriada chamando o método de classe <code>as_view()</code>. Isso faz todo o trabalho de criar uma instância da classe e garantir que os métodos do manipulador certo sejam chamados para solicitações HTTP recebidas.</p> + +<h3 id="View_class-based">View (class-based)</h3> + +<p>Poderíamos escrever com facilidade a view da lista de livros como uma função regular (assim como a view index anterior), que consultaria todos os livros no banco de dados e depois chamaria <code>render()</code> para passar a lista para um modelo especificado. No entanto, usaremos uma view de lista genérica class-based (<code>ListView</code>) — uma classe que herda de uma view existente. Como a view genérica já implementa a maioria das funcionalidades necessárias e segue as práticas recomendadas do Django, poderemos criar uma exibição de lista mais robusta com menos código, menos repetições e, finalmente, menos manutenção.</p> + +<p>Abra <strong>catalog/views.py</strong>, e copie o seguinte código na parte inferior do arquivo:</p> + +<pre class="brush: python notranslate">from django.views import generic + +class BookListView(generic.ListView): + model = Book</pre> + +<p>É isso aí! A view genérica consultará o banco de dados para obter todos os registros para o modelo especificado (<code>Book</code>) em seguida, renderize um template localizado em <strong>/locallibrary/catalog/templates/catalog/book_list.html</strong> (que criaremos abaixo). Dentro do template, você pode acessar a lista de livros com a variável de template denominada <code>object_list</code> OU <code>book_list</code> (i.e. genericamente "<code><em>the_model_name</em>_list</code>").</p> + +<div class="note"> +<p><strong>Nota</strong>: Esse caminho estranho para a localização do template não é um erro de impressão - as visualizações genéricas procuram modelos em <code>/<em>application_name</em>/<em>the_model_name</em>_list.html</code> (<code>catalog/book_list.html</code> nesse caso) dentro do aplicativo <code>/<em>application_name</em>/templates/</code> diretório (<code>/catalog/templates/)</code>.</p> +</div> + +<p>Você pode adicionar atributos para alterar o comportamento padrão acima. Por exemplo, você pode especificar outro arquivo do template se precisar ter várias visualizações que usem esse mesmo modelo ou se desejar usar um nome de variável de template diferente se <code>book_list</code> não é intuitivo para o seu caso de uso de template específico. Possivelmente, a variação mais útil é alterar/filtrar o subconjunto de resultados retornados - portanto, em vez de listar todos os livros, você pode listar os cinco principais livros que foram lidos por outros usuários.</p> + +<pre class="brush: python notranslate">class BookListView(generic.ListView): + model = Book + context_object_name = 'my_book_list' # your own name for the list as a template variable + queryset = Book.objects.filter(title__icontains='war')[:5] # Get 5 books containing the title war + template_name = 'books/my_arbitrary_template_name_list.html' # Specify your own template name/location</pre> + +<h4 id="Substituindo_métodos_em_class-based_views">Substituindo métodos em class-based views</h4> + +<p>Embora não precisemos fazer isso aqui, você também pode substituir alguns dos métodos da classe.</p> + +<p>Por exemplo, podemos substituir o método <code>get_queryset()</code> para alterar a lista de registros retornados. Isso é mais flexível do que apenas definir o atributo <code>queryset</code> como fizemos no fragmento de código anterior (embora não haja nenhum benefício real neste caso):</p> + +<pre class="brush: python notranslate">class BookListView(generic.ListView): + model = Book + + def get_queryset(self): + return Book.objects.filter(title__icontains='war')[:5] # Get 5 books containing the title war +</pre> + +<p>Também podemos substituir <code>get_context_data()</code> para passar variáveis de contexto adicionais para o template (por exemplo, a lista de livros é passada por padrão). O fragmento abaixo mostra como adicionar uma variável chamada "<code>some_data</code>" para o contexto (estaria disponível como uma variável de template).</p> + +<pre class="brush: python notranslate">class BookListView(generic.ListView): + model = Book + + def get_context_data(self, **kwargs): + # Call the base implementation first to get the context + context = super(BookListView, self).get_context_data(**kwargs) + # Create any data and add it to the context + context['some_data'] = 'This is just some data' + return context</pre> + +<p>Ao fazer isso, é importante seguir o padrão usado acima:</p> + +<ul> + <li>Primeiro obtenha o contexto existente da nossa superclasse.</li> + <li>Em seguida, adicione as novas informações de contexto.</li> + <li>Em seguida, retorne o novo contexto (atualizado).</li> +</ul> + +<div class="note"> +<p><strong>Nota</strong>: Confira <a href="https://docs.djangoproject.com/pt-br/2.1/topics/class-based-views/generic-display/">Built-in class-based generic views</a> (Django docs) para muitos mais exemplos do que você pode fazer.</p> +</div> + +<h3 id="Criando_o_template_List_View">Criando o template List View</h3> + +<p>Crie o arquivo HTML <strong>/locallibrary/catalog/templates/catalog/book_list.html</strong> e copie o texto abaixo. Como discutido acima, este é o arquivo de template padrão esperado pela list view genérica da class-based view (para um modelo chamado <code>Book</code> em um aplicativo chamado <code>catalog</code>).</p> + +<p>Os templates para visualizações genéricas são como qualquer outro template (<em>embora</em>, é claro, o contexto/informações passadas para o template possam ser diferentes). Assim como em nosso template <em>index</em>, estendemos nosso template base na primeira linha e substituímos o bloco denominado <code>content</code>.</p> + +<pre class="brush: html notranslate">{% extends "base_generic.html" %} + +{% block content %} + <h1>Book List</h1> + <strong>{% if book_list %}</strong> + <ul> + {% for book in book_list %} + <li> + <a href="\{{ book.get_absolute_url }}">\{{ book.title }}</a> (\{{book.author}}) + </li> + {% endfor %} + </ul> + <strong>{% else %}</strong> + <p>There are no books in the library.</p> + <strong>{% endif %} </strong> +{% endblock %}</pre> + +<p>A view passa o contexto (lista de livros), por padrão, um <code>object_list</code> e <code>book_list</code> aliases; qualquer um funcionará.</p> + +<h4 id="Execução_conditional">Execução conditional</h4> + +<p>Nós usamos o <code><a href="https://docs.djangoproject.com/en/2.1/ref/templates/builtins/#if">if</a></code>, <code>else</code>, e <code>endif</code> template tags para verificar se o <code>book_list</code> foi definido e não está vazio. E se <code>book_list</code> está vazio, então a cláusula <code>else</code> exibe o texto explicando que não há livros para listar. E se <code>book_list</code> não estiver vazio, percorreremos a lista de livros.</p> + +<pre class="brush: html notranslate"><strong>{% if book_list %}</strong> + <!-- code here to list the books --> +<strong>{% else %}</strong> + <p>There are no books in the library.</p> +<strong>{% endif %}</strong> +</pre> + +<p>A condição acima verifica apenas um caso, mas você pode testar em condições adicionais usando a template tag <code>elif</code> (e.g. <code>{% elif var2 %}</code>). Para obter mais informações sobre operadores condicionais, consulte: <a href="https://docs.djangoproject.com/pt-br/2.1/ref/templates/builtins/#if">if</a>, <a href="https://docs.djangoproject.com/pt-br/2.1/ref/templates/builtins/#ifequal-and-ifnotequal">ifequal/ifnotequal</a>, e <a href="https://docs.djangoproject.com/pt-br/2.1/ref/templates/builtins/#ifchanged">ifchanged</a> em <a href="https://docs.djangoproject.com/pt-br/2.1/ref/templates/builtins">Built-in template tags and filters</a> (Django Docs).</p> + +<h4 id="For_loops">For loops</h4> + +<p>O template usa as template tags <a href="https://docs.djangoproject.com/pt-br/2.1/ref/templates/builtins/#for">for</a> e <code>endfor</code> para percorrer a lista de livros, como mostrado abaixo. Cada iteração preenche a variável de template <code>book</code> com informações para o item da lista atual.</p> + +<pre class="brush: html notranslate">{% for <strong>book</strong> in book_list %} + <li> <!-- code here get information from each <strong>book</strong> item --> </li> +{% endfor %} +</pre> + +<p>Embora não seja usado aqui, dentro do loop, o Django também criará outras variáveis que você pode usar para rastrear a iteração. Por exemplo, você pode testar a variável <code>forloop.last</code> para executar o processamento condicional na última vez em que o loop é executado.</p> + +<h4 id="Acessando_variáveis">Acessando variáveis</h4> + +<p>O código dentro do loop cria um item de lista para cada livro que mostra o título (como um link para a exibição de detalhes ainda a ser criada) e o autor.</p> + +<pre class="brush: html notranslate"><a href="\{{ book.get_absolute_url }}">\{{ book.title }}</a> (\{{book.author}}) +</pre> + +<p>Acessamos os <em>campos </em>do registro de livro associado usando a "notação de ponto" (e.g. <code>book.title</code> e <code>book.author</code>), onde o texto após o item <code>book</code> é o nome do campo (conforme definido no modelo).</p> + +<p>Também podemos chamar <em>funções </em>no modelo de dentro do nosso template - nesse caso, chamamos <code>Book.get_absolute_url()</code> para obter um URL que você pode usar para exibir o registro de detalhe associado. Isso funciona desde que a função não tenha argumentos (não há como passar argumentos!)</p> + +<div class="note"> +<p><strong>Nota</strong>: Temos que ter um pouco de cuidado com os "efeitos colaterais" ao chamar funções em templates. Aqui apenas exibimos um URL, mas uma função pode fazer praticamente qualquer coisa - não queremos excluir nosso banco de dados (por exemplo) apenas renderizando nosso template!</p> +</div> + +<h4 id="Atualize_o_template_base">Atualize o template base</h4> + +<p>Abra o template base (<strong>/locallibrary/catalog/templates/<em>base_generic.html</em></strong>) e insira <strong>{% url 'books' %} </strong>no link da URL para <strong>All books</strong>,como mostrado abaixo. Isso habilitará o link em todas as páginas (podemos colocá-lo em prática agora que criamos o mapeador de URL "books").</p> + +<pre class="brush: python notranslate"><li><a href="{% url 'index' %}">Home</a></li> +<strong><li><a href="{% url 'books' %}">All books</a></li></strong> +<li><a href="">All authors</a></li></pre> + +<h3 id="Com_o_que_se_parece">Com o que se parece?</h3> + +<p>Ainda não será possível criar a lista de livros, porque ainda falta uma dependência - o mapa de URL para as páginas de detalhes do livro, necessário para criar hiperlinks para livros individuais. Mostraremos as visualizações de lista e de detalhes após a próxima seção.</p> + +<h2 id="Pagina_Book_detail">Pagina Book detail</h2> + +<p>A página book detail exibirá informações sobre um livro específico, acessado usando o URL <code>catalog/book/<em><id></em></code> (onde <code><em><id></em></code> é a chave primária do livro). Além dos campos no model <code>Book</code> (author, summary, ISBN, language, e genre), também listaremos os detalhes das cópias disponíveis (<code>BookInstances</code>) incluindo o status, data prevista de retorno, impressão e ID. Isso permitirá que nossos leitores não apenas saibam sobre o livro, mas também confirmem se/quando ele está disponível.</p> + +<h3 id="URL_mapping_2">URL mapping</h3> + +<p>Abra <strong>/catalog/urls.py</strong> e adicione a URL '<strong>book-detail</strong>' mostrado em negrito abaixo. Esta função <code>path()</code> define um padrão, exibição de detalhes genérica associada à classe associada e um nome.</p> + +<pre class="brush: python notranslate">urlpatterns = [ + path('', views.index, name='index'), + path('books/', views.BookListView.as_view(), name='books'), +<strong> path('book/<int:pk>', views.BookDetailView.as_view(), name='book-detail'),</strong> +]</pre> + +<p>Para o path <em>book-detail</em> o padrão de URL usa uma sintaxe especial para capturar o ID específico do livro que queremos ver. A sintaxe é muito simples: colchetes angulares definem a parte da URL a ser capturada, incluindo o nome da variável que a view pode usar para acessar os dados capturados. Por exemplo, <strong><something></strong> , capturará o padrão marcado e passará o valor para a visualização como uma variável "alguma coisa". Opcionalmente, você pode preceder o nome da variável com um <a href="https://docs.djangoproject.com/pt-br/2.1/topics/http/urls/#path-converters">converter specification</a> que define o tipo de dados (int, str, slug, uuid, path).</p> + +<p>Neste caso, usamos <code>'<int:pk>'</code><strong> </strong>para capturar o ID do livro, que deve ser uma sequência especialmente formatada e passá-la para a view como um parâmetro chamado <code>pk</code> (abreviatura de primary key). Esta é a id que está sendo usado para armazenar o livro exclusivamente no banco de dados, conforme definido no Book Model.</p> + +<div class="note"> +<p><strong>Nota</strong>: Como discutido anteriormente, nosso URL correspondente é realmente <code>catalog/book/<digits></code> (porque estamos no aplicativo de <strong>catalog</strong>, <code>/catalog/</code> é assumido).</p> +</div> + +<div class="warning"> +<p><strong>Importante</strong>: A view de detalhes genérica class-based <em>espera </em>receber um parâmetro chamado <strong>pk</strong>. Se você estiver escrevendo sua própria função view, poderá usar o nome de qualquer parâmetro que desejar, ou mesmo transmitir as informações em um argumento sem nome.</p> +</div> + +<h4 id="Correspondência_avançada_de_caminhosiniciador_de_expressão_regular">Correspondência avançada de caminhos/iniciador de expressão regular</h4> + +<div class="note"> +<p><strong>Nota</strong>: Você não precisará desta seção para concluir o tutorial! Nós fornecemos isso porque conhecer essa opção provavelmente será útil no seu futuro centrado no Django.</p> +</div> + +<p>The pattern matching provided by <code>path()</code> is simple and useful for the (very common) cases where you just want to capture <em>any</em> string or integer. If you need more refined filtering (for example, to filter only strings that have a certain number of characters) then you can use the <a href="https://docs.djangoproject.com/en/2.1/ref/urls/#django.urls.re_path">re_path()</a> method.</p> + +<p>This method is used just like <code>path()</code> except that it allows you to specify a pattern using a <a href="https://docs.python.org/3/library/re.html">Regular expression</a>. For example, the previous path could have been written as shown below:</p> + +<pre class="brush: python notranslate"><strong>re_path(r'^book/(?P<pk>\d+)$', views.BookDetailView.as_view(), name='book-detail'),</strong> +</pre> + +<p><em>Regular expressions</em> are an incredibly powerful pattern mapping tool. They are, frankly, quite unintuitive and scary for beginners. Below is a very short primer!</p> + +<p>The first thing to know is that regular expressions should usually be declared using the raw string literal syntax (i.e. they are enclosed as shown: <strong>r'<your regular expression text goes here>'</strong>).</p> + +<p>The main parts of the syntax you will need to know for declaring the pattern matches are:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Symbol</th> + <th scope="col">Meaning</th> + </tr> + </thead> + <tbody> + <tr> + <td>^</td> + <td>Match the beginning of the text</td> + </tr> + <tr> + <td>$</td> + <td>Match the end of the text</td> + </tr> + <tr> + <td>\d</td> + <td>Match a digit (0, 1, 2, ... 9)</td> + </tr> + <tr> + <td>\w</td> + <td>Match a word character, e.g. any upper- or lower-case character in the alphabet, digit or the underscore character (_)</td> + </tr> + <tr> + <td>+</td> + <td>Match one or more of the preceding character. For example, to match one or more digits you would use <code>\d+</code>. To match one or more "a" characters, you could use <code>a+</code></td> + </tr> + <tr> + <td>*</td> + <td>Match zero or more of the preceding character. For example, to match nothing or a word you could use <code>\w*</code></td> + </tr> + <tr> + <td>( )</td> + <td>Capture the part of the pattern inside the brackets. Any captured values will be passed to the view as unnamed parameters (if multiple patterns are captured, the associated parameters will be supplied in the order that the captures were declared).</td> + </tr> + <tr> + <td>(?P<<em>name</em>>...)</td> + <td>Capture the pattern (indicated by ...) as a named variable (in this case "name"). The captured values are passed to the view with the name specified. Your view must therefore declare an argument with the same name!</td> + </tr> + <tr> + <td>[ ]</td> + <td>Match against one character in the set. For example, [abc] will match on 'a' or 'b' or 'c'. [-\w] will match on the '-' character or any word character.</td> + </tr> + </tbody> +</table> + +<p>Most other characters can be taken literally!</p> + +<p>Let's consider a few real examples of patterns:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Pattern</th> + <th scope="col">Description</th> + </tr> + </thead> + <tbody> + <tr> + <td><strong>r'^book/(?P<pk>\d+)$'</strong></td> + <td> + <p>This is the RE used in our URL mapper. It matches a string that has <code>book/</code> at the start of the line (<strong>^book/</strong>), then has one or more digits (<code>\d+</code>), and then ends (with no non-digit characters before the end of line marker).</p> + + <p>It also captures all the digits <strong>(?P<pk>\d+)</strong> and passes them to the view in a parameter named 'pk'. <strong>The captured values are always passed as a string!</strong></p> + + <p>For example, this would match <code>book/1234</code> , and send a variable <code>pk='1234'</code> to the view.</p> + </td> + </tr> + <tr> + <td><strong>r'^book/(\d+)$'</strong></td> + <td>This matches the same URLs as the preceding case. The captured information would be sent as an unnamed argument to the view.</td> + </tr> + <tr> + <td><strong>r'^book/(?P<stub>[-\w]+)$'</strong></td> + <td> + <p>This matches a string that has <code>book/</code> at the start of the line (<strong>^book/</strong>), then has one or more characters that are <em>either</em> a '-' or a word character (<strong>[-\w]+</strong>), and then ends. It also captures this set of characters and passes them to the view in a parameter named 'stub'.</p> + + <p>This is a fairly typical pattern for a "stub". Stubs are URL-friendly word-based primary keys for data. You might use a stub if you wanted your book URL to be more informative. For example <code>/catalog/book/the-secret-garden</code> rather than <code>/catalog/book/33</code>.</p> + </td> + </tr> + </tbody> +</table> + +<p>You can capture multiple patterns in the one match, and hence encode lots of different information in a URL.</p> + +<div class="note"> +<p><strong>Nota</strong>: Como desafio, considere como você pode codificar um URL para listar todos os livros lançados em um determinado ano, mês, dia e o RE que poderia ser usado para correspondê-lo.</p> +</div> + +<h4 id="Passando_opções_adicionais_em_seus_mapas_de_URL">Passando opções adicionais em seus mapas de URL</h4> + +<p>Um recurso que não usamos aqui, mas que você pode achar valioso, é que você pode declarar e passar <a href="https://docs.djangoproject.com/pt-br/2.1/topics/http/urls/#views-extra-options">opções adicionais</a> para a view. As opções são declaradas como um dicionário que você passa como o terceiro argumento sem nome para a função <code>path()</code>. Essa abordagem pode ser útil se você desejar usar a mesma visualização para vários recursos e transmitir dados para configurar seu comportamento em cada caso (abaixo, fornecemos um modelo diferente em cada caso).</p> + +<pre class="brush: python notranslate">path('url/', views.my_reused_view, <strong>{'my_template_name': 'some_path'}</strong>, name='aurl'), +path('anotherurl/', views.my_reused_view, <strong>{'my_template_name': 'another_path'}</strong>, name='anotherurl'), +</pre> + +<div class="note"> +<p><strong>Nota:</strong> As opções extras e os padrões capturados nomeados são passados para a view como argumentos <em>nomeados</em>. Se você usar o <strong>mesmo nome</strong> para um padrão capturado e uma opção extra, somente o valor do padrão capturado será enviado para a visualização (o valor especificado na opção adicional será descartado).</p> +</div> + +<h3 id="View_class-based_2">View (class-based)</h3> + +<p>Abra <strong>catalog/views.py</strong>, e copie o seguinte código na parte inferior do arquivo:</p> + +<pre class="brush: python notranslate">class BookDetailView(generic.DetailView): + model = Book</pre> + +<p>É isso aí! Tudo o que você precisa fazer agora é criar um modelo chamado <strong>/locallibrary/catalog/templates/catalog/book_detail.html</strong>, e a visualização passará as informações do banco de dados para o registro <code>Book</code> extraído pelo mapeador de URL. Dentro do modelo, você pode acessar a lista de livros com a variável de modelo denominada <code>object</code> ou <code>book</code> (i.e. genericamente "<code><em>the_model_name</em></code>").</p> + +<p>Se necessário, você pode alterar o template usado e o nome do objeto de contexto usado para referenciar o livro no template. Você também pode substituir métodos para, por exemplo, adicionar informações adicionais ao contexto.</p> + +<h4 id="O_que_acontece_se_o_registro_não_existir">O que acontece se o registro não existir?</h4> + +<p>Se um registro solicitado não existir, a view de detalhes genérica class-based levantará uma exceção <code>Http404</code> para você automaticamente — em produção, isso exibirá automaticamente uma página apropriada de "resource not found", que você pode personalizar se desejar.</p> + +<p>Apenas para lhe dar uma idéia de como isso funciona, o fragmento de código abaixo demonstra como você implementaria a exibição baseada em classe como uma função se você não estivesse usando a view de detalhe genérica class-based.</p> + +<pre class="brush: python notranslate">def book_detail_view(request, primary_key): + try: + book = Book.objects.get(pk=primary_key) + except Book.DoesNotExist: + raise Http404('Book does not exist') + + return render(request, 'catalog/book_detail.html', context={'book': book}) +</pre> + +<p>A view tenta primeiro obter o registro de livro específico do modelo. Se isso falhar, a view deve gerar uma exceção <code>Http404</code> para indicar que o livro "não foi encontrado". A etapa final é, como sempre, chamar <code>render()</code> com o nome do template e os dados do livro no parâmetro <code>context</code> (como um dicionário).</p> + +<p>Como alternativa, podemos usar a função <code>get_object_or_404()</code> como um atalho para levantar uma exceção <code>Http404</code> se o registro não for encontrado.</p> + +<pre class="brush: python notranslate">from django.shortcuts import get_object_or_404 + +def book_detail_view(request, primary_key): + book = get_object_or_404(Book, pk=primary_key) + return render(request, 'catalog/book_detail.html', context={'book': book})</pre> + +<h3 id="Criando_o_template_Detail_View">Criando o template Detail View</h3> + +<p>Crie o arquivo HTML <strong>/locallibrary/catalog/templates/catalog/book_detail.html</strong> e forneça o conteúdo abaixo. Conforme discutido acima, este é o nome do arquivo de template padrão esperado pela view de <em>detalhes </em>genérica class-based (para um modelo chamado <code>Book</code> no aplicativo chamado <code>catalog</code>).</p> + +<pre class="brush: html notranslate">{% extends "base_generic.html" %} + +{% block content %} + <h1>Title: \{{ book.title }}</h1> + + <p><strong>Author:</strong> <a href="">\{{ book.author }}</a></p> <!-- author detail link not yet defined --> + <p><strong>Summary:</strong> \{{ book.summary }}</p> + <p><strong>ISBN:</strong> \{{ book.isbn }}</p> + <p><strong>Language:</strong> \{{ book.language }}</p> + <p><strong>Genre:</strong> {% for genre in book.genre.all %} \{{ genre }}{% if not forloop.last %}, {% endif %}{% endfor %}</p> + + <div style="margin-left:20px;margin-top:20px"> + <h4>Copies</h4> + + {% for copy in book.bookinstance_set.all %} + <hr> + <p class="{% if copy.status == 'a' %}text-success{% elif copy.status == 'm' %}text-danger{% else %}text-warning{% endif %}">\{{ copy.get_status_display }}</p> + {% if copy.status != 'a' %} + <p><strong>Due to be returned:</strong> \{{copy.due_back}}</p> + {% endif %} + <p><strong>Imprint:</strong> \{{copy.imprint}}</p> + <p class="text-muted"><strong>Id:</strong> \{{copy.id}}</p> + {% endfor %} + </div> +{% endblock %}</pre> + +<ul> +</ul> + +<div class="note"> +<p>O link do autor no template acima tem um URL vazio porque ainda não criamos uma página de detalhes do autor. Uma vez que isso exista, você deve atualizar o URL assim:</p> + +<pre class="notranslate"><a href="<strong>{% url 'author-detail' book.author.pk %}</strong>">\{{ book.author }}</a> +</pre> +</div> + +<p>Embora um pouco maior, quase tudo neste template foi descrito anteriormente:</p> + +<ul> + <li>Estendemos nosso modelo básico e substituímos o bloco "content".</li> + <li>Usamos o processamento condicional para determinar se deve ou não exibir conteúdo específico.</li> + <li>Usamos <code>for</code> loops para percorrer as listas de objetos.</li> + <li>Acessamos os campos de contexto usando a notação de ponto (porque usamos a exibição genérica detalhada, o contexto é chamado <code>book</code>; também poderíamos usar "<code>object</code>")</li> +</ul> + +<p>A única coisa interessante que não vimos antes é a função <code>book.bookinstance_set.all()</code>. Este método é "automagicamente" construído pelo Django para retornar o conjunto de registros <code>BookInstance</code> associados com um <code>Book</code> em particular.</p> + +<pre class="brush: python notranslate">{% for copy in book.bookinstance_set.all %} + <!-- code to iterate across each copy/instance of a book --> +{% endfor %}</pre> + +<p>Este método é necessário porque você declara um campo <code>ForeignKey</code> (um-para-muitos) somente no lado "um" do relacionamento. Como você não faz nada para declarar o relacionamento nos outros modelos ("muitos"), ele não possui nenhum campo para obter o conjunto de registros associados. Para superar esse problema, o Django constrói uma função "pesquisa reversa" chamada de forma apropriada, que você pode usar. O nome da função é construído com letras minúsculas no nome do modelo em que o <code>ForeignKey</code> foi declarado, seguido por <code>_set</code> (i.e. então a função criada em <code>Book</code> é <code>bookinstance_set()</code>).</p> + +<div class="note"> +<p><strong>Nota</strong>: Aqui usamos <code>all()</code> para obter todos os registros (o padrão). Enquanto você pode usar o método <code>filter()</code> para obter um subconjunto de registros no código, não é possível fazer isso diretamente nos modelos, porque não é possível especificar argumentos para funções.</p> + +<p>Observe também que, se você não definir um pedido (na sua class-based view ou modelo), também verá erros do servidor de desenvolvimento como este:</p> + +<pre class="notranslate">[29/May/2017 18:37:53] "GET /catalog/books/?page=1 HTTP/1.1" 200 1637 +/foo/local_library/venv/lib/python3.5/site-packages/django/views/generic/list.py:99: UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list: <QuerySet [<Author: Ortiz, David>, <Author: H. McRaven, William>, <Author: Leigh, Melinda>]> + allow_empty_first_page=allow_empty_first_page, **kwargs) +</pre> + +<p>Isso acontece porque o <a href="https://docs.djangoproject.com/pt-br/2.1/topics/pagination/#paginator-objects">objeto paginator</a> espera ver algum ORDER BY sendo executado no seu banco de dados subjacente. Sem ele, não é possível garantir que os registros que estão sendo retornados estejam na ordem certa!<strong> </strong></p> + +<p>Este tutorial não atingiu a <strong>Paginação </strong>(ainda, mas em breve), mas como você não pode usar <code>sort_by()</code> e passar um parâmetro (o mesmo com <code>filter()</code> descrito acima), você terá que escolher entre três opções:</p> + +<ol> + <li>Adicione um <code>ordering</code> dentro de uma declaração <code>class Meta</code> no seu model.</li> + <li>Adicione um atributo <code>queryset</code> na sua class-based view, especificando um <code>order_by()</code>.</li> + <li>Adicione um método <code>get_queryset</code> à sua class-based view personalisada e também especifique o <code>order_by()</code>.</li> +</ol> + +<p>Se você decidir ir com uma <code>class Meta</code> no model <code>Author</code> (provavelmente não tão flexível quanto personalizar o class-based view, mas fácil o suficiente), você terminará com algo assim:</p> + +<pre class="notranslate">class Author(models.Model): + first_name = models.CharField(max_length=100) + last_name = models.CharField(max_length=100) + date_of_birth = models.DateField(null=True, blank=True) + date_of_death = models.DateField('Died', null=True, blank=True) + + def get_absolute_url(self): + return reverse('author-detail', args=[str(self.id)]) + + def __str__(self): + return f'{self.last_name}, {self.first_name}' + +<strong> class Meta: + ordering = ['last_name']</strong></pre> + +<p>Obviamente, o campo não precisa ser <code>last_name</code>: poderia ser qualquer outro.</p> + +<p>E por último, mas não menos importante, você deve classificar por um atributo/coluna que realmente tenha um índice (exclusivo ou não) em seu banco de dados para evitar problemas de desempenho. Obviamente, isso não será necessário aqui (e provavelmente estamos nos adiantando muito) com tão poucos livros (e usuários!), Mas é algo a ser lembrado em projetos futuros.</p> +</div> + +<h2 id="Com_o_que_se_parece_agora">Com o que se parece agora?</h2> + +<p>Nesse ponto, deveríamos ter criado tudo o necessário para exibir a lista de livros e as páginas de detalhes do livro. Execute o servidor (<code>python3 manage.py runserver</code>) e abra no seu navegador <a href="http://127.0.0.1:8000/">http://127.0.0.1:8000/</a>.</p> + +<div class="warning"> +<p><strong>Aviso:</strong> Não clique em nenhum autor ou link de detalhes do autor ainda - você os criará no desafio!</p> +</div> + +<p>Clique no link <strong>All books</strong> para exibir a lista de livros.</p> + +<p><img alt="Book List Page" src="https://mdn.mozillademos.org/files/14049/book_list_page_no_pagination.png" style="border-style: solid; border-width: 1px; display: block; height: 216px; margin: 0px auto; width: 823px;"></p> + +<p>Em seguida, clique no link de um dos seus livros. Se tudo estiver configurado corretamente, você deverá ver algo como a seguinte captura de tela.</p> + +<p><img alt="Book Detail Page" src="https://mdn.mozillademos.org/files/14051/book_detail_page_no_pagination.png" style="border-style: solid; border-width: 1px; display: block; height: 783px; margin: 0px auto; width: 926px;"></p> + +<h2 id="Paginação">Paginação</h2> + +<p>Se você tiver apenas alguns registros, nossa página da lista de livros ficará bem. No entanto, à medida que você entra nas dezenas ou centenas de registros, a página levará progressivamente mais tempo para carregar (e terá muito conteúdo para navegar com sensatez). A solução para esse problema é adicionar paginação às exibições de lista, reduzindo o número de itens exibidos em cada página.</p> + +<p>O Django possui excelente suporte embutido para paginação. Melhor ainda, isso é incorporado às exibições de lista genéricas baseadas em classes, para que você não precise fazer muito para habilitá-lo!</p> + +<h3 id="Views">Views</h3> + +<p>Abra <strong>catalog/views.py</strong>, e adicionea linha <code>paginate_by</code> mostrado em negrito abaixo.</p> + +<pre class="brush: python notranslate">class BookListView(generic.ListView): + model = Book + <strong>paginate_by = 10</strong></pre> + +<p>Com essa adição, assim que você tiver mais de 10 registros, a visualização começará a paginar os dados que envia para o modelo. As diferentes páginas são acessadas usando os parâmetros GET - para acessar a página 2, você usaria o URL: <code>/catalog/books/<strong>?page=2</strong></code>.</p> + +<h3 id="Templates">Templates</h3> + +<p>Agora que os dados estão paginados, precisamos adicionar suporte ao modelo para rolar pelo conjunto de resultados. Como podemos fazer isso em todas as visualizações de lista, faremos isso de uma maneira que possa ser adicionada ao modelo base. </p> + +<p>Abra <strong>/locallibrary/catalog/templates/<em>base_generic.html</em></strong> e copie no seguinte bloco de paginação, abaixo do nosso bloco de conteúdo (destacado abaixo em negrito). O código primeiro verifica se a paginação está ativada na página atual. Nesse caso, adiciona os links seguintes e anteriores, conforme apropriado (e o número da página atual).</p> + +<pre class="brush: python notranslate">{% block content %}{% endblock %} + +<strong> {% block pagination %} + {% if is_paginated %} + <div class="pagination"> + <span class="page-links"> + {% if page_obj.has_previous %} + <a href="\{{ request.path }}?page=\{{ page_obj.previous_page_number }}">previous</a> + {% endif %} + <span class="page-current"> + Page \{{ page_obj.number }} of \{{ page_obj.paginator.num_pages }}. + </span> + {% if page_obj.has_next %} + <a href="\{{ request.path }}?page=\{{ page_obj.next_page_number }}">next</a> + {% endif %} + </span> + </div> + {% endif %} + {% endblock %} </strong></pre> + +<p>O <code>page_obj</code> é um objeto de <a href="https://docs.djangoproject.com/pt-br/2.1/topics/pagination/#paginator-objects">Paginator</a> que existirá se a paginação estiver sendo usada na página atual. Permite obter todas as informações sobre a página atual, as páginas anteriores, quantas páginas existem, etc.</p> + +<p>Usamos <code>\{{ request.path }}</code> para obter o URL da página atual para criar os links de paginação. Isso é útil porque é independente do objeto que estamos paginando.</p> + +<p>É isso aí!</p> + +<h3 id="Com_o_que_se_parece_agora_2">Com o que se parece agora?</h3> + +<p>A captura de tela abaixo mostra a aparência da paginação - se você não inseriu mais de 10 títulos no banco de dados, pode testá-lo com mais facilidade, abaixando o número especificado na linha <code>paginate_by</code> no seu arquivo <strong>catalog/views.py</strong>. Para obter o resultado abaixo, alteramos para <code>paginate_by = 2</code>.</p> + +<p>Os links de paginação são exibidos na parte inferior, com os links seguinte/anterior, dependendo da página em que você está.</p> + +<p><img alt="Book List Page - paginated" src="https://mdn.mozillademos.org/files/14057/book_list_paginated.png" style="border-style: solid; border-width: 1px; display: block; height: 216px; margin: 0px auto; width: 924px;"></p> + +<h2 id="Challenge_yourself">Challenge yourself</h2> + +<p>The challenge in this article is to create the author detail and list views required to complete the project. These should be made available at the following URLs:</p> + +<ul> + <li><code>catalog/authors/</code> — The list of all authors.</li> + <li><code>catalog/author/<em><id></em></code><em> </em>— The detail view for the specific author with a primary key field named <em><code><id></code></em></li> +</ul> + +<p>The code required for the URL mappers and the views should be virtually identical to the <code>Book</code> list and detail views we created above. The templates will be different but will share similar behaviour.</p> + +<div class="note"> +<p><strong>Note</strong>:</p> + +<ul> + <li>Once you've created the URL mapper for the author list page you will also need to update the <strong>All authors</strong> link in the base template. Follow the <a href="#Update_the_base_template">same process</a> as we did when we updated the <strong>All books</strong> link.</li> + <li>Once you've created the URL mapper for the author detail page, you should also update the <a href="#Creating_the_Detail_View_template">book detail view template</a> (<strong>/locallibrary/catalog/templates/catalog/book_detail.html</strong>) so that the author link points to your new author detail page (rather than being an empty URL). The line will change to add the template tag shown in bold below. + <pre class="brush: html notranslate"><p><strong>Author:</strong> <a href="<strong>{% url 'author-detail' book.author.pk %}</strong>">\{{ book.author }}</a></p> +</pre> + </li> +</ul> +</div> + +<p>When you are finished, your pages should look something like the screenshots below.</p> + +<p><img alt="Author List Page" src="https://mdn.mozillademos.org/files/14053/author_list_page_no_pagination.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<ul> +</ul> + +<p><img alt="Author Detail Page" src="https://mdn.mozillademos.org/files/14055/author_detail_page_no_pagination.png" style="border-style: solid; border-width: 1px; display: block; height: 358px; margin: 0px auto; width: 825px;"></p> + +<ul> +</ul> + +<h2 id="Summary">Summary</h2> + +<p>Congratulations, our basic library functionality is now complete! </p> + +<p>In this article, we've learned how to use the generic class-based list and detail views and used them to create pages to view our books and authors. Along the way we've learned about pattern matching with regular expressions, and how you can pass data from URLs to your views. We've also learned a few more tricks for using templates. Last of all we've shown how to paginate list views so that our lists are manageable even when we have many records.</p> + +<p>In our next articles, we'll extend this library to support user accounts, and thereby demonstrate user authentication, permissons, sessions, and forms.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.1/topics/class-based-views/generic-display/">Built-in class-based generic views</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/class-based-views/generic-display/">Generic display views</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.1/topics/class-based-views/intro/">Introduction to class-based views</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/templates/builtins">Built-in template tags and filters</a> (Django docs).</li> + <li><a href="https://docs.djangoproject.com/en/2.1/topics/pagination/">Pagination</a> (Django docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Home_page", "Learn/Server-side/Django/Sessions", "Learn/Server-side/Django")}}</p> + +<h2 id="Neste_módulo">Neste módulo</h2> + +<ul> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Introduction">Introdução ao Django</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/development_environment">Configurando um ambiente de desenvolvimento Django</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django: Website de uma Biblioteca Local</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/skeleton_website">Tutorial Django Parte 2: Criando a base do website</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Models">Tutorial Django Parte 3: Usando models</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Admin_site">Tutorial Django Parte 4: Django admin site</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Home_page">Tutorial Django Parte 5: Criando nossa página principal</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Generic_views">Tutorial Django Parte 6: Lista genérica e detail views</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Sessions">Tutorial Django Parte 7: Framework de Sessões</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Authentication">Tutorial Django Parte 8: Autenticação de Usuário e permissões</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Forms">Tutorial Django Parte 9: Trabalhando com formulários</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Testing">Tutorial Django Parte 10: Testando uma aplicação web Django</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Deployment">Tutorial Django Parte 11: Implantando Django em produção</a></li> + <li><a rel="nofollow" title="A página ainda não foi criada.">Segurança de aplicações web Django</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> diff --git a/files/pt-br/learn/server-side/django/home_page/index.html b/files/pt-br/learn/server-side/django/home_page/index.html new file mode 100644 index 0000000000..3c7783c352 --- /dev/null +++ b/files/pt-br/learn/server-side/django/home_page/index.html @@ -0,0 +1,420 @@ +--- +title: 'Django Tutorial Parte 5: Criando nossa home page' +slug: Learn/Server-side/Django/Home_page +tags: + - Aprender + - Artigo + - Codificação + - Iniciante + - Tutorial + - django + - django templates + - django views + - lado servidor (server-side) +translation_of: Learn/Server-side/Django/Home_page +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django")}}</div> + +<p class="summary">Agora estamos prontos para adicionar o código que exibe nossa primeira página completa - uma home page do site <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a>. A página inicial mostrará o número de registros que temos para cada tipo de modelo e fornecerá links de navegação na barra lateral para nossas outras páginas. Ao longo do caminho, obteremos experiência prática ao escrever mapas e visualizações básicos de URL, obter registros do banco de dados e usar modelos.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré-requisitos:</th> + <td>Leia a <a href="/en-US/docs/Learn/Server-side/Django/Introduction">Introdução ao Django</a>. Conclua os tópicos do tutorial anterior (incluindo <a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a>).</td> + </tr> + <tr> + <th scope="row">Objetivo:</th> + <td>Aprender a criar mapas e visualizações de URL simples (onde nenhum dado é codificado no URL), obtenha dados de modelos e crie modelos.</td> + </tr> + </tbody> +</table> + +<h2 id="Visão_Global">Visão Global</h2> + +<p>Depois de definirmos nossos modelos e criarmos alguns registros iniciais da biblioteca para trabalhar, é hora de escrever o código que apresenta essas informações aos usuários. A primeira coisa que precisamos fazer é determinar quais informações queremos exibir em nossas páginas e definir os URLs a serem usados para retornar esses recursos. Em seguida, criaremos um mapeador de URLs, visualizações e modelos para exibir as páginas.</p> + +<p>O diagrama a seguir descreve o fluxo de dados principal e os componentes necessários ao manipular solicitações e respostas HTTP. Como já implementamos o modelo, os principais componentes que criaremos são:</p> + +<ul> + <li>Mapeadores de URL para encaminhar os URLs suportados (e qualquer informação codificada nos URLs) para as funções de exibição apropriadas.</li> + <li>View functions para obter os dados solicitados dos modelos, crie páginas HTML que exibem os dados e retorne as páginas ao usuário para visualização no navegador.</li> + <li>Templates para usar ao renderizar dados nas visualizações.</li> +</ul> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13931/basic-django.png" style="display: block; margin: 0px auto;"></p> + +<p>Como você verá na próxima seção, temos 5 páginas para exibir, o que é muita informação para documentar em um único artigo. Portanto, este artigo se concentrará em como implementar a página inicial e abordaremos as outras páginas em um artigo subsequente. Isso deve fornecer uma boa compreensão completa de como os mapeadores, visualizações e modelos de URL funcionam na prática.</p> + +<h2 id="Definindo_os_URLs_do_recurso">Definindo os URLs do recurso</h2> + +<p>Como esta versão do <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary </a>é essencialmente somente leitura para usuários finais, precisamos fornecer uma página de destino para o site (uma página inicial) e páginas que exibam visualizações de lista e detalhes de livros e autores.</p> + +<p>As URLs que iremos precisar na nossa página são:</p> + +<ul> + <li><code>catalog/</code> — A página inicial (index).</li> + <li><code>catalog/books/</code> — Uma lista de todos os livros.</li> + <li><code>catalog/authors/</code> — Uma lista de todos os autores.</li> + <li><code>catalog/book/<em><id></em></code> — A exibição de detalhes de um livro específico, com uma chave primária de campo <code><em><id></em></code> (o padrão). Por exemplo, o URL do terceiro livro adicionado à lista será <code>/catalog/book/3</code>.</li> + <li><code>catalog/author/<em><id></em></code><em> </em>— A exibição de detalhes para o autor específico com um campo de chave primária de <em><code><id>. </code></em>Por exemplo, o URL do 11º autor adicionado à lista será <code>/catalog/author/11</code>.</li> +</ul> + +<p>Os três primeiros URLs retornarão a página de índice, a lista de livros e a lista de autores. Esses URLs não codificam nenhuma informação adicional e as consultas que buscam dados no banco de dados sempre serão as mesmas. No entanto, os resultados retornados pelas consultas dependerão do conteúdo do banco de dados.</p> + +<p>Por outro lado, os dois URLs finais exibirão informações detalhadas sobre um livro ou autor específico. Esses URLs codificam a identidade do item a ser exibido (representado por <code><em><id></em></code> acima). O mapeador de URLs extrairá as informações codificadas e as passará para a visualização, e a visualização determinará dinamicamente quais informações serão obtidas do banco de dados. Ao codificar as informações no URL, usaremos um único conjunto de mapeamento de URL, uma visualização e um modelo para lidar com todos os livros (ou autores). </p> + +<div class="note"> +<p><strong>Nota</strong>: Com o Django, você pode construir suas URLs da maneira que desejar - você pode codificar informações no corpo da URL, como mostrado acima, ou incluir <code>GET</code> parâmetros no URL, por exemplo <code>/book/?id=6</code>. Qualquer que seja a abordagem usada, os URLs devem ser mantidos limpos, lógicos e legíveis, conforme <a href="https://www.w3.org/Provider/Style/URI">recomendado pelo W3C</a>.<br> + A documentação do Django recomenda informações de codificação no corpo da URL para obter um melhor design da URL.</p> +</div> + +<p>Conforme mencionado na visão geral, o restante deste artigo descreve como construir a página index.</p> + +<h2 id="Criando_a_página_index">Criando a página index</h2> + +<p>A primeira página que criaremos é a página index (<code>catalog/</code>). A pagina index incluirá algum HTML estático, juntamente com "contagens" geradas de diferentes registros no banco de dados. Para fazer isso funcionar, criaremos um mapeamento de URL, uma visualização e um modelo.</p> + +<div class="note"> +<p><strong>Nota</strong>: Vale a pena prestar um pouco de atenção extra nesta seção. A maioria das informações também se aplica às outras páginas que criaremos.</p> +</div> + +<h3 id="Mapeamento_de_URL">Mapeamento de URL</h3> + +<p>Quando criamos o <a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">esqueleto do website</a>, atualizamos o arquivo <strong>locallibrary/urls.py</strong> para garantir que sempre que um URL que comece com <code>catalog/</code> é recebido, o módulo URLConf <code>catalog.urls</code> processará a substring restante.</p> + +<p>O seguinte snippet de código de <strong>locallibrary/urls.py </strong>inclui o modulo <code>catalog.urls</code>:</p> + +<pre class="notranslate">urlpatterns += [ + path('catalog/', include('catalog.urls')), +] +</pre> + +<div class="note"> +<p><strong>Nota</strong>: Sempre que o Django encontra a função de importação <code><a href="https://docs.djangoproject.com/en/2.1/ref/urls/#django.urls.include" title="django.conf.urls.include">django.urls.include()</a></code>, divide a string da URL no caractere final designado e envia a subsequência restante para o módulo URLconf incluído para processamento adicional.</p> +</div> + +<p>Também criamos um arquivo de espaço reservado para o modulo <em>URLConf</em>, chamado <strong>/catalog/urls.py</strong>. Adicione as seguintes linhas a esse arquivo: </p> + +<pre class="brush: python notranslate">urlpatterns = [ +<strong> path('', views.index, name='index'),</strong> +]</pre> + +<p>A função <code>path()</code> define o seguinte:</p> + +<ul> + <li>Um padrão de URL, que é uma sequência vazia: <code>''</code>. Discutiremos detalhadamente os padrões de URL ao trabalhar em outras visualizações.</li> + <li>A view function that will be called if the URL pattern is detected: <code>views.index</code>, which is the function named <code>index()</code> in the <strong>views.py </strong>file. </li> +</ul> + +<p>A função <code>path()</code> também especifica um parâmetro de nome, que é um identificador exclusivo para esse mapeamento de URL específico. Você pode usar o nome para "reverter" o mapeador, ou seja, para criar dinamicamente um URL que aponte para o recurso que o mapeador foi projetado para manipular. Por exemplo, podemos usar o parâmetro name para vincular à nossa home page a partir de qualquer outra página adicionando o seguinte link em um modelo:</p> + +<pre class="brush: html notranslate"><a href="<strong>{% url 'index' %}</strong>">Home</a>.</pre> + +<div class="note"> +<p><strong>Nota</strong>: Podemos codificar o link como em <code><a href="<strong>/catalog/</strong>">Home</a></code>), mas se alterarmos o padrão da nossa página inicial, por exemplo, para <code>/catalog/index</code>) os modelos não serão mais vinculados corretamente. Usar um mapeamento de URL invertido é muito mais flexível e robusto.</p> +</div> + +<h3 id="View_function-based">View (function-based)</h3> + +<p>Uma view é uma função que processa uma solicitação HTTP, busca os dados necessários no banco de dados, renderiza os dados em uma página HTML usando um modelo HTML e, em seguida, retorna o HTML gerado em uma resposta HTTP para exibir a página ao usuário. A visualização do índice segue esse modelo - ele busca informações sobre o número de <code>Book</code>, <code>BookInstance</code>, disponibilidade de <code>BookInstance</code> e registros de <code>Author</code> que temos no banco de dados e passa essas informações para um modelo para exibição.</p> + +<p>Abra <strong>catalog/views.py</strong> e observe que o arquivo já importa o <a href="https://docs.djangoproject.com/en/2.1/topics/http/shortcuts/#django.shortcuts.render">render()</a> da função shortcuts para gerar arquivo HTML usando um modelo e dados: </p> + +<pre class="brush: python notranslate">from django.shortcuts import render + +# Create your views here. +</pre> + +<p>Cole as seguintes linhas na parte inferior do arquivo:</p> + +<pre class="brush: python notranslate">from catalog.models import Book, Author, BookInstance, Genre + +def index(request): + """View function for home page of site.""" + + # Generate counts of some of the main objects + num_books = Book.objects.all().count() + num_instances = BookInstance.objects.all().count() + + # Available books (status = 'a') + num_instances_available = BookInstance.objects.filter(status__exact='a').count() + + # The 'all()' is implied by default. + num_authors = Author.objects.count() + + context = { + 'num_books': num_books, + 'num_instances': num_instances, + 'num_instances_available': num_instances_available, + 'num_authors': num_authors, + } + + # Render the HTML template index.html with the data in the context variable + return render(request, 'index.html', context=context)</pre> + +<p>A primeira linha importa as classes de models que usaremos para acessar dados em todas as nossas visualizações.</p> + +<p>A primeira parte da função view busca o número de registros usando o atributo <code>objects.all()</code> nas classes de modelo. Também recebe uma lista de objetos de <code>BookInstance</code> que possuem um valor de 'a' (Disponibilidade) no campo status. Você pode encontrar mais informações sobre como acessar os dados do modelo em nosso tutorial anterior <a href="/en-US/docs/Learn/Server-side/Django/Models#Searching_for_records">Django Tutorial Part 3: Using models > Searching for records</a>.</p> + +<p>No final da função view chamamos a função <code>render()</code> para criar uma página HTML e retornar a página como resposta. essa função de atalho envolve várias outras funções para simplificar um caso de uso muito comum. A função <code>render()</code> aceita os seguintes parâmetros:</p> + +<ul> + <li>o objeto <code>request</code> original, que é um <code>HttpRequest</code>.</li> + <li>um modelo HTML com espaços reservados para os dados.</li> + <li>uma variável <code>context</code>, que é um dicionário Python, contendo os dados a serem inseridos nos espaços reservados. </li> +</ul> + +<p>Falaremos mais sobre modelos e variáveis <code>context</code> na próxima seção. Vamos criar nosso template para que possamos exibir algo para o usuário!</p> + +<h3 id="Template">Template</h3> + +<p>Um template é um arquivo de texto que define a estrutura ou o layout de um arquivo (como uma página HTML), usa espaços reservados para representar o conteúdo real.</p> + +<p>Django irá procurar automaticamente templates na pasta chamada '<strong>templates</strong>' em sua aplicação. Por exemplo, na exibição de index que acabamos de adicionar, a função <code>render()</code> espera encontrar o arquivo <em><strong>index.html</strong> em</em><em> </em><strong>/locallibrary/catalog/templates/</strong> e gera um erro se o arquivo não estiver presente.</p> + +<p>Você pode verificar isso salvando as alterações anteriores e acessando <code>127.0.0.1:8000</code> no seu navegador - ele exibirá uma mensagem de erro bastante intuitiva: "<code>TemplateDoesNotExist at /catalog/</code>", e outros detalhes.</p> + +<div class="note"> +<p><strong>Nota</strong>: Com base no arquivo de configurações do seu projeto, o Django procurará templates em vários locais, pesquisando nos aplicativos instalados por padrão. Você pode descobrir mais sobre como o Django encontra templates e quais formatos ele suporta no <a href="https://docs.djangoproject.com/en/2.1/topics/templates/">the Templates section of the Django documentation</a>.</p> +</div> + +<h4 id="Estendendo_templates">Estendendo templates</h4> + +<p>O index template precisará de marcação HTML padrão para head e a body, juntamente com as seções de navegação para criar um link para as outras páginas do site (que ainda não criamos) e para as seções que exibem dados introdutórios de texto e livro.</p> + +<p>Grande parte da estrutura HTML e de navegação será a mesma em todas as páginas do nosso site. Em vez de duplicar o código padrão em todas as páginas, você pode usar a linguagem de modelagem do Django para declarar um modelo base e depois estendê-lo para substituir apenas os bits que são diferentes para cada página específica.</p> + +<p>O seguinte snippet de código é um template base de amostra de um arquivo <strong>base_generic.html</strong>. Em breve, criaremos o modelo para a LocalLibrary. O exemplo abaixo inclui HTML comum com seções para um título, uma barra lateral e o conteúdo principal marcado com as template tags de nome <code>block</code> e <code>endblock</code>, mostrado em negrito. Você pode deixar os blocos vazios ou incluir o conteúdo padrão a ser usado ao renderizar páginas derivadas do modelo.</p> + +<div class="note"> +<p><strong>Nota</strong>: Template <em>tags</em> são funções que você pode usar em um modelo para percorrer as listas, executar operações condicionais com base no valor de uma variável e assim por diante. Além das template tags, a sintaxe template permite que você faça referência a variáveis que são passadas para a template a partir da view e use filtros de template para formatar variáveis (por exemplo, para converter uma sequência em minúscula).</p> +</div> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html lang="en"> +<head> + <strong>{% block title %}</strong><title>Local Library</title><strong>{% endblock %}</strong> +</head> +<body> + <strong>{% block sidebar %}</strong><!-- insert default navigation text for every page --><strong>{% endblock %}</strong> + <strong>{% block content %}</strong><!-- default content text (typically empty) --><strong>{% endblock %}</strong> +</body> +</html> +</pre> + +<p>Ao definir um template para uma visualização específica, primeiro especificamos o template base usando a template tag <code>extends</code> — veja o exemplo de código abaixo. Em seguida, declaramos quais seções do template queremos substituir (se houver), usando seções <code>block</code>/<code>endblock</code> como no template base. </p> + +<p>Por exemplo, o trecho de código abaixo mostra como usar a template tag <code>extends</code> e substituir o block <code>content</code>. O HTML gerado incluirá o código e a estrutura definidos no template base, incluindo o conteúdo padrão que você definiu no block <code>title</code>, mas o novo block <code>content</code> no lugar do padrão.</p> + +<pre class="brush: html notranslate">{% extends "base_generic.html" %} + +{% block content %} + <h1>Local Library Home</h1> + <p>Welcome to LocalLibrary, a website developed by <em>Mozilla Developer Network</em>!</p> +{% endblock %}</pre> + +<h4 id="O_template_base_LocalLibrary">O template base LocalLibrary</h4> + +<p>Usaremos o seguinte snippet de código como modelo básico para o site <em>LocalLibrary</em>. Como você pode ver, ele contém algum código HTML e define blocos para <code>title</code>, <code>sidebar</code>, e <code>content</code>. Temos um título padrão e uma barra lateral padrão com links para listas de todos os livros e autores, ambos colocados em blocos para serem facilmente alterados no futuro.</p> + +<div class="note"> +<p><strong>Nota</strong>: Também introduzimos duas template tags adicionais: <code>url</code> e <code>load static</code>. Essas tags serão explicadas nas próximas seções.</p> +</div> + +<p>Crie um novo arquivo <strong><em>base_generic.html </em></strong>em <strong>/locallibrary/catalog/templates/</strong> e cole o seguinte código no arquivo:</p> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html lang="en"> +<head> + {% block title %}<title>Local Library</title>{% endblock %} + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous"> + <!-- Add additional CSS in static file --> + {% load static %} + <link rel="stylesheet" href="{% static 'css/styles.css' %}"> +</head> +<body> + <div class="container-fluid"> + <div class="row"> + <div class="col-sm-2"> + {% block sidebar %} + <ul class="sidebar-nav"> + <li><a href="{% url 'index' %}">Home</a></li> + <li><a href="">All books</a></li> + <li><a href="">All authors</a></li> + </ul> + {% endblock %} + </div> + <div class="col-sm-10 ">{% block content %}{% endblock %}</div> + </div> + </div> +</body> +</html></pre> + +<p>O template inclui CSS de <a href="http://getbootstrap.com/">Bootstrap</a> para melhorar o layout e a apresentação da página HTML. O uso do Bootstrap (ou outra estrutura da Web do lado do cliente) é uma maneira rápida de criar uma página atraente que é exibida bem em diferentes tamanhos de tela.</p> + +<p>O template base também faz referência a um arquivo css local (<strong>styles.css</strong>) que fornece estilo adicional. Criar um arquivo <strong>styles.css </strong>em<strong> </strong><strong>/locallibrary/catalog/static/css/</strong> e cole o seguinte código no arquivo:</p> + +<pre class="brush: css notranslate">.sidebar-nav { + margin-top: 20px; + padding: 0; + list-style: none; +}</pre> + +<h4 id="O_template_index">O template index</h4> + +<p>Crie um novo arquivo HTML <strong><em>index.html </em></strong>em <strong>/locallibrary/catalog/templates/</strong> e cole o seguinte código no arquivo Esse código estende nosso modelo base na primeira linha e substitui o padrão block <code>content</code> para o template. </p> + +<pre class="brush: html notranslate">{% extends "base_generic.html" %} + +{% block content %} + <h1>Local Library Home</h1> + <p>Welcome to LocalLibrary, a website developed by <em>Mozilla Developer Network</em>!</p> + <h2>Dynamic content</h2> + <p>The library has the following record counts:</p> + <ul> + <li><strong>Books:</strong> <strong>\{{ num_books }}</strong></li> + <li><strong>Copies:</strong> <strong>\{{ num_instances }}</strong></li> + <li><strong>Copies available:</strong> <strong>\{{ num_instances_available }}</strong></li> + <li><strong>Authors:</strong> <strong>\{{ num_authors }}</strong></li> + </ul> +{% endblock %}</pre> + +<p>Na seção <em>Dynamic content</em>, declaramos espaços reservados (<em>variáveis de template</em>) para as informações da exibição que queremos incluir. As variáveis são colocadas entre chaves (guiador), como mostrado em negrito no exemplo de código. </p> + +<div class="note"> +<p><strong>Nota:</strong> Você pode reconhecer facilmente variáveis de template e template tags (funções) - as variáveis são colocadas entre chaves (<code>\{{ num_books }}</code>), e as tags são colocadas em chaves simples com sinais de porcentagem (<code>{% extends "base_generic.html" %}</code>).</p> +</div> + +<p>O importante a ser observado aqui é que as variáveis são nomeadas com as <em>chaves</em> que passamos para o dicionário <code>context</code> na função <code>render()</code> da nossa view (veja a amostra abaixo). As variáveis serão substituídas pelos <em>valores </em>associados quando o modelo for renderizado.</p> + +<pre class="brush: python notranslate">context = { + '<strong>num_books</strong>': num_books, + '<strong>num_instances</strong>': num_instances, + '<strong>num_instances_available</strong>': num_instances_available, + '<strong>num_authors</strong>': num_authors, +} + +return render(request, 'index.html', context=context)</pre> + +<h4 id="Referenciando_arquivos_estáticos_nos_templates">Referenciando arquivos estáticos nos templates</h4> + +<p>É provável que seu projeto use recursos estáticos, incluindo JavaScript, CSS e imagens. Como a localização desses arquivos pode não ser conhecida (ou pode mudar), o Django permite que você especifique a localização em seus modelos em relação a configuração global <code>STATIC_URL</code>. O site padrão do esqueleto define o valor de <code>STATIC_URL</code> para '<code>/static/</code>', mas você pode optar por hospedá-los em uma rede de entrega de conteúdo ou em outro local.</p> + +<p>Dentro do template que você chama primeiro na template tag <code>load</code> especificando "static" para adicionar a biblioteca de modelos, conforme mostrado no exemplo de código abaixo. Você pode então usar a template tag <code>static</code> e especifique o URL relativo ao arquivo necessário.</p> + +<pre class="brush: html notranslate"><!-- Add additional CSS in static file --> +{% load static %} +<link rel="stylesheet" href="{% static 'css/styles.css' %}"></pre> + +<p>Você pode adicionar uma imagem à página de maneira semelhante, por exemplo:</p> + +<pre class="brush: html notranslate">{% load static %} +<img src="{% static 'catalog/images/local_library_model_uml.png' %}" alt="UML diagram" style="width:555px;height:540px;"> +</pre> + +<div class="note"> +<p><strong>Nota</strong>: Os exemplos acima especificam onde os arquivos estão localizados, mas o Django não os serve por padrão. Configuramos o servidor da web de desenvolvimento para exibir arquivos modificando o mapeador de URL global (<strong>/locallibrary/locallibrary/urls.py</strong>) quando <a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">criamos o esqueleto do website</a>, mas ainda precisamos ativar a veiculação de arquivos na produção. Veremos isso mais tarde.</p> +</div> + +<p>Para obter mais informações sobre como <a href="https://docs.djangoproject.com/en/2.1/howto/static-files/">Trabalhar com arquivos estaticos</a>, consulte Gerenciando arquivos estáticos na documentação do Django.</p> + +<h4 id="Vinculando_as_URLs">Vinculando as URLs</h4> + +<p>O template base abaixo introduziu a template tag <code>url</code>.</p> + +<pre class="brush: python notranslate"><li><a href="{% url 'index' %}">Home</a></li> +</pre> + +<p>Essa tag aceita o nome de uma função <code>path()</code> chamado em <strong>urls.py</strong> e os valores para quaisquer argumentos que a view associada receberá dessa função e retorna um URL que você pode usar para vincular ao recurso.</p> + +<h4 id="Configurando_onde_encontrar_os_templates">Configurando onde encontrar os templates</h4> + +<p>Você precisa dizer ao Django para procurar seus templates na pasta de templates. Para fazer isso, adicione o diretório de templates ao objeto TEMPLATES editando o arquivo <strong>settings.py</strong>, como mostrado em negrito, no seguinte exemplo de código:</p> + +<pre class="brush: python notranslate">TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [ +<strong> os.path.join(BASE_DIR, 'templates'), +</strong> ], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +]</pre> + +<h2 id="Com_o_que_se_parece">Com o que se parece?</h2> + +<p>Neste ponto, criamos todos os recursos necessários para exibir a página index. Execute o servidor (<code>python3 manage.py runserver</code>) e abra <a href="http://127.0.0.1:8000/">http://127.0.0.1:8000/</a> no seu navegador. Se tudo estiver configurado corretamente, seu site deverá ter a seguinte captura de tela.</p> + +<p><img alt="Index page for LocalLibrary website" src="https://mdn.mozillademos.org/files/14045/index_page_ok.png" style="border-style: solid; border-width: 1px; display: block; height: 356px; margin: 0px auto; width: 874px;"></p> + +<div class="note"> +<p><strong>Nota:</strong> Os links <strong>All books</strong> e <strong>All authors</strong> ainda não funcionarão porque os caminhos, visualizações e modelos para essas páginas não estão definidos. Acabamos de inserir espaços reservados para esses links no template <code>base_generic.html</code>.</p> +</div> + +<h2 id="Desafie-se">Desafie-se</h2> + +<p>Temos duas tarefas para testar a sua familiaridade com as consultas de modelos, views e templates</p> + +<ol> + <li>O modelo de <a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/Home_page#The_LocalLibrary_base_template">base</a> da BibliotecaLocal inclui um bloco de <code>título</code>. Substitua este bloco no modelo de índice e crie um novo título para a página.</li> + <li> + <div class="note"> + <p><strong>Dica: </strong>A seção<a href="#Extending_templates"> Extendendo Templates</a> explica como criar blocos e extender um bloco em outro template.</p> + </div> + </li> + <li>Modifique a <a href="#View_(function-based)">view</a> para gerar contagens para gêneros e livros que contenham uma palavra específica (case insensitive), e passe o resultado para o <code>contexto.</code> <span class="tlid-translation translation" lang="pt"><span title="">Isso é feito de maneira semelhante à criação e uso de <code>num_books</code> e <code>num_instances_available</code>.</span> <span title="">Em seguida, atualize o template do index para incluir essas variáveis.</span></span></li> +</ol> + +<ul> +</ul> + +<h2 id="Resumo">Resumo</h2> + +<p>Acabamos de criar a página inicial do nosso site - uma página HTML que exibe uma série de registros do banco de dados e links para outras páginas ainda a serem criadas. Ao longo do caminho, aprendemos informações fundamentais sobre mapeadores de url, views, consulta do banco de dados com modelos, passagem de informações para um modelo a partir de uma view e criação e extensão de templates.</p> + +<p>No próximo artigo, continuaremos sobre esse conhecimento para criar as quatro páginas restantes de nosso site.</p> + +<h2 id="Veja_também">Veja também</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/pt-br/3.1/intro/tutorial03/">Escrevendo sua primeira aplicação Django, parte 3: View e Templates</a> (documentação do Django)</li> + <li><a href="https://docs.djangoproject.com/pt-br/3.1/topics/http/urls/">Despachante de URL</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/pt-br/3.1/topics/http/views/">Funções das Views </a> (DJango docs)</li> + <li><a href="https://docs.djangoproject.com/pt-br/3.1/topics/templates/">Templates</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.1/howto/static-files/">Gerenciando arquivos estáticos</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.1/topics/http/shortcuts/#django.shortcuts.render">Funções de atalho do Django</a> (Django docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django")}}</p> + +<h2 id="Nesse_Módulo">Nesse Módulo</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Introdução ao Django</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/development_environment">Configurando um ambiente de desenvolvimento Django</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django: Website de uma Biblioteca Local</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/skeleton_website">Tutorial Django Parte 2: Criando a base do website</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Models">Tutorial Django Parte 3: Utilizando models</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Admin_site">Tutorial Django Parte 4: Django admin site</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Home_page">Tutorial Django Parte 5: Criando nossa página principal</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Generic_views">Tutorial Django Parte 6: Lista genérica e detail views</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Sessions">Tutorial Django Parte 7: Sessões de Framework </a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Forms">Tutorial Django Parte 9: Trabalhando com formulários</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Testing">Tutorial Django Parte 10: Testando uma aplicação web Django</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial Django Parte 11: Implantando Django em produção</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/web_application_security">Segurança de aplicações web Django</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> diff --git a/files/pt-br/learn/server-side/django/hospedagem/index.html b/files/pt-br/learn/server-side/django/hospedagem/index.html new file mode 100644 index 0000000000..baa2217b71 --- /dev/null +++ b/files/pt-br/learn/server-side/django/hospedagem/index.html @@ -0,0 +1,692 @@ +--- +title: 'Tutorial Django Parte 11: Hospedando Django para produção' +slug: Learn/Server-side/Django/Hospedagem +tags: + - Codificação de Scripts + - Deploy do django + - Fazendo deploy + - Iniciante + - django + - servidor web +translation_of: Learn/Server-side/Django/Deployment +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Testing", "Learn/Server-side/Django/web_application_security", "Learn/Server-side/Django")}}</div> + +<p class="summary">Agora que criou (e testou) um fantástico website de Biblioteca Local, vai querer instalá-lo em um servidor web público para que possa ser acessado pelo pessoal da biblioteca e membros através da Internet. Este artigo fornece uma visão geral de como poderá encontrar um servidor de hospedagem para instalar o seu web site, e o que precisa fazer para ter o seu site web pronto para produção.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré-requisitos:</th> + <td> + <p>Completar todos os tópicos do tutorial anterior, incluindo o <a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/Testing">Tutorial Django Parte 10: Testando uma aplicação web Django.</a></p> + </td> + </tr> + <tr> + <th scope="row">Objectivo:</th> + <td>Para saber onde e como se pode hospedar uma aplicação Django na produção.</td> + </tr> + </tbody> +</table> + +<h2 id="Visão_geral">Visão geral</h2> + +<p>Uma vez terminado o seu website (ou terminado "o suficiente" para iniciar testes públicos) vai precisar publicá-lo em um host mais público e acessível do que o seu computador de desenvolvimento pessoal.</p> + +<p>Até agora tem trabalhado em um ambiente de desenvolvimento, utilizando o servidor web de desenvolvimento Django para compartilhar o seu site com o navegador/rede local, e executando o seu site com configurações de desenvolvimento (inseguras) que expõem debug e outras informações privadas. Antes de poder hospedar um website externamente, vai precisar fazer primeiro:</p> + +<ul> + <li>Faça algumas alterações nas configurações do seu projeto.</li> + <li>Escolher um ambiente para hospedar a aplicação Django.</li> + <li>Escolher um ambiente para hospedar qualquer arquivo estático.</li> + <li>Configurar uma infraestrutura de nível de produção para servir seu website.</li> +</ul> + +<p>Este tutorial fornece algumas orientações sobre suas opções para escolher um site de hospedagem, uma breve visão geral do que você precisa fazer para deixar seu aplicativo Django pronto para produção e um exemplo prático de como instalar o site Biblioteca Local no serviço de hospedagem em nuvem do <a href="https://www.heroku.com/">Heroku.</a></p> + +<h2 id="O_que_é_um_ambiente_de_produção">O que é um ambiente de produção?</h2> + +<p>O ambiente de produção é o ambiente fornecido pelo computador/servidor onde você executará seu site para consumo externo. O ambiente inclui:</p> + +<ul> + <li>Hardware de computador no qual o website é executado.</li> + <li>Sistema operacional (por exemplo, Linux, Windows).</li> + <li>Linguagem de programação de tempo de execução e bibliotecas de estrutura sobre as quais seu site é escrito.</li> + <li>Servidor da Web usado para servir páginas e outros conteúdos (por exemplo, Nginx, Apache).</li> + <li>Servidor de aplicativos que passa solicitações "dinâmicas" entre seu site Django e o servidor web.</li> + <li>Bancos de dados dos quais seu site depende.</li> +</ul> + +<div class="note"> +<p><strong>Nota: </strong>Dependendo de como sua produção está configurada, você também pode ter um proxy reverso, load balancer(balanceador de carga), etc.</p> +</div> + +<p>O computador/servidor pode estar localizado em suas instalações e conectado à Internet por um link rápido, mas é muito mais comum usar um computador hospedado "na nuvem". O que isso realmente significa é que seu código é executado em algum computador remoto (ou possivelmente em um computador "virtual") no(s) centro(s) de dados da empresa de hospedagem. O servidor remoto geralmente oferece algum nível garantido de recursos de computação (por exemplo, CPU, RAM, memória de armazenamento, etc.) e conectividade com a Internet por um determinado preço.</p> + +<p>Esse tipo de hardware de computação/rede acessível remotamente é conhecido como <em>Infraestrutura como Serviço</em> (IaaS). Muitos fornecedores de IaaS fornecem opções para pré-instalar um sistema operacional específico, no qual você deve instalar os outros componentes de seu ambiente de produção. Outros fornecedores permitem que você selecione ambientes com mais recursos, talvez incluindo uma configuração completa de Django e servidor web.</p> + +<div class="note"> +<p><strong>Nota:</strong> Ambientes pré-construídos podem tornar a configuração do seu site muito fácil porque reduzem a configuração, mas as opções disponíveis podem limitar você a um servidor desconhecido (ou outros componentes) e podem ser baseadas em uma versão mais antiga do sistema operacional. Freqüentemente, é melhor instalar você mesmo os componentes, para obter os que deseja e, quando precisar atualizar partes do sistema, tenha uma ideia de por onde começar!</p> +</div> + +<p>Outros provedores de hospedagem oferecem suporte a Django como parte de uma oferta de <em>Plataforma como Serviço</em> (PaaS). Nesse tipo de hospedagem, você não precisa se preocupar com a maior parte do seu ambiente de produção (servidor da web, servidor de aplicativos, balanceadores de carga), pois a plataforma host cuida disso para você (junto com a maior parte do que você precisa fazer para para dimensionar seu aplicativo). Isso torna a implantação muito fácil, porque você só precisa se concentrar em seu aplicativo da web e não em toda a outra infraestrutura de servidor.</p> + +<p>Alguns desenvolvedores escolherão a maior flexibilidade fornecida por IaaS em vez de PaaS, enquanto outros apreciarão a sobrecarga de manutenção reduzida e escalonamento mais fácil de PaaS. Quando você está começando, configurar seu site em um sistema PaaS é muito mais fácil e é isso que faremos neste tutorial.</p> + +<div class="note"> +<p><strong>Dica:</strong> Se você escolher um provedor de hospedagem compatível com Python / Django, ele deve fornecer instruções sobre como configurar um site Django usando diferentes configurações de servidor da web, servidor de aplicativos, proxy reverso, etc (isso não será relevante se você escolher um PaaS ) Por exemplo, existem muitos guias passo a passo para várias configurações nos <a href="https://www.digitalocean.com/community/tutorials?q=django">documentos da comunidade Digital Ocean Django.</a></p> +</div> + +<h2 id="Escolhendo_um_provedor_de_hospedagem">Escolhendo um provedor de hospedagem</h2> + +<p>Existem mais de 100 provedores de hospedagem que são conhecidos por oferecer suporte ativo ou funcionar bem com o Django (você pode encontrar uma lista bastante exaustiva em <a href="https://djangofriendly.com/index.html">Djangofriendly hosts</a>). Esses fornecedores oferecem diferentes tipos de ambientes (IaaS, PaaS) e diferentes níveis de recursos de computação e rede a preços diferentes.</p> + +<p>Algumas coisas a serem consideradas ao escolher um host:</p> + +<ul> + <li>O quão ocupado seu site provavelmente estará e o custo dos dados e recursos de computação necessários para atender a essa demanda.</li> + <li>Nível de suporte para escalonamento horizontal (adicionando mais máquinas) e verticalmente (atualizando para máquinas mais potentes) e os custos de fazê-lo.</li> + <li>Onde o fornecedor possui centros de dados e, portanto, onde o acesso provavelmente será mais rápido.</li> + <li>O histórico de tempo de atividade e desempenho do tempo de inatividade do host.</li> + <li>Ferramentas fornecidas para gerenciar o site - são fáceis de usar e seguras (por exemplo, SFTP x FTP).</li> + <li>Estruturas integradas para monitorar seu servidor.</li> + <li>Limitações conhecidas. Alguns hosts bloqueiam deliberadamente certos serviços (por exemplo, e-mail). Outros oferecem apenas um certo número de horas de "tempo de vida" em algumas faixas de preço ou oferecem apenas uma pequena quantidade de armazenamento.</li> + <li>Benefícios adicionais. Alguns provedores oferecem nomes de domínio gratuitos e suporte para certificados SSL que, de outra forma, você teria que pagar.</li> + <li>Se o nível "gratuito" com o qual você está contando expira com o tempo e se o custo de migrar para um nível mais caro significa que você teria ficado melhor usando algum outro serviço em primeiro lugar!</li> +</ul> + +<p>A boa notícia quando você está começando é que existem alguns sites que fornecem ambientes de computação de "avaliação", "desenvolvedor" ou "amador" de graça. Esses são sempre ambientes com recursos limitados / restritos e você precisa estar ciente de que eles podem expirar após um período introdutório. No entanto, eles são ótimos para testar sites de baixo tráfego em um ambiente real e podem fornecer uma migração fácil para pagar por mais recursos quando seu site ficar mais ocupado. As escolhas populares nesta categoria incluem <a href="https://www.heroku.com/">Heroku</a>, <a href="https://www.pythonanywhere.com/">Python Anywhere</a>, <a href="https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/billing-free-tier.html">Amazon Web Services</a>, <a href="https://azure.microsoft.com/en-us/pricing/details/app-service/windows/">Microsoft Azure</a>, etc.</p> + +<p>Muitos provedores também têm uma camada "básica" que fornece níveis mais úteis de capacidade de computação e menos limitações. <a href="https://www.digitalocean.com/">Digital Ocean</a> e <a href="https://www.pythonanywhere.com/">Python Anywhere</a> são exemplos de provedores de hospedagem populares que oferecem uma camada de computação básica relativamente barata (na faixa de US$5 a US$10 por mês).</p> + +<div class="note"> +<p><strong>Nota: </strong>Lembre-se de que o preço não é o único critério de seleção. Se o seu site for bem-sucedido, pode ser que a escalabilidade seja a consideração mais importante.</p> +</div> + +<h2 id="Preparando_seu_site_para_publicação">Preparando seu site para publicação</h2> + +<p>O <a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Server-side/Django/skeleton_website">esqueleto do site do Django</a> criado usando as ferramentas django-admin e manage.py é configurado para tornar o desenvolvimento mais fácil. Muitas das configurações do projeto Django (especificadas em settings.py) devem ser diferentes para produção, por motivos de segurança ou desempenho.</p> + +<div class="note"> +<p><strong>Dica:</strong> É comum ter um arquivo <strong>settings.py</strong> separado para produção e importar configurações confidenciais de um arquivo separado ou de uma variável de ambiente. Este arquivo deve ser protegido, mesmo se o resto do código-fonte estiver disponível em um repositório público.</p> +</div> + +<p>As configurações críticas que você deve verificar são:</p> + +<ul> + <li><code>DEBUG</code>. Isso deve ser definido como <code>False</code> em produção (<code>DEBUG = False</code>). Isso impede que o rastreamento de depuração sensível/confidencial e as informações variáveis sejam exibidas.</li> + <li><code>SECRET_KEY</code>. Este é um grande valor aleatório usado para proteção contra CSRF etc. É importante que a chave usada na produção não esteja no controle de origem ou acessível fora do servidor de produção. Os documentos do Django sugerem que isso pode ser melhor carregado de uma variável de ambiente ou lido de um arquivo somente servidor. + <pre class="brush: python notranslate"># Read SECRET_KEY from an environment variable +import os +SECRET_KEY = os.environ['SECRET_KEY'] + +# OR + +# Read secret key from a file +with open('/etc/secret_key.txt') as f: + SECRET_KEY = f.read().strip()</pre> + </li> +</ul> + +<p>Vamos mudar o aplicativo LocalLibrary para que possamos ler nosso <code>SECRET_KEY</code> e <code>DEBUG</code> variáveis de variáveis de ambiente se forem definidas, mas caso contrário, use os valores padrão no arquivo de configuração.</p> + +<p>Abra <strong>/locallibrary/settings.py</strong>, desative o original <code>SECRET_KEY</code>configuração e adicione as novas linhas conforme mostrado abaixo em <strong>negrito</strong>. Durante o desenvolvimento, nenhuma variável de ambiente será especificada para a chave, então o valor padrão será usado (não importa qual chave você usa aqui, ou se a chave "vaza", porque você não a usará na produção).</p> + +<pre class="brush: python notranslate"># SECURITY WARNING: keep the secret key used in production secret! +# SECRET_KEY = 'cg#p$g+j9tax!#a3cup@1$8obt2_+&k3q+pmu)5%asj6yjpkag' +<strong>import os</strong> +<strong>SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'cg#p$g+j9tax!#a3cup@1$8obt2_+&k3q+pmu)5%asj6yjpkag')</strong> +</pre> + +<p>Em seguida, comente o existente <code>DEBUG</code> configuração e adicione a nova linha mostrada abaixo.</p> + +<pre class="brush: python notranslate"># SECURITY WARNING: don't run with debug turned on in production! +# DEBUG = True +<strong>DEBUG = os.environ.get('DJANGO_DEBUG', '') != 'False'</strong> +</pre> + +<p>O valor do <code>DEBUG</code> será <code>True</code> por padrão, mas será apenas <code>False</code> se o valor do <code>DJANGO_DEBUG</code> variável de ambiente é definida para <code>False</code>. Observe que as variáveis de ambiente são strings e não tipos Python. Portanto, precisamos comparar strings. A única maneira de definir o <code>DEBUG</code> variável para <code>False</code> é realmente configurá-lo para a string <code>False</code></p> + +<p>Você pode definir a variável de ambiente como False, emitindo o seguinte comando:</p> + +<pre class="brush: bash notranslate">export DJANGO_DEBUG=False</pre> + +<p>Uma lista de verificação completa das configurações que você pode querer mudar é fornecida na <a href="https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/">Lista de verificação de implantação</a> (documentos do Django). Você também pode listar vários deles usando o comando de terminal abaixo:</p> + +<pre class="brush: python notranslate">python3 manage.py check --deploy +</pre> + +<h2 id="Exemplo_Instalando_LocalLibrary_no_Heroku">Exemplo: Instalando LocalLibrary no Heroku</h2> + +<p>Esta seção fornece uma demonstração prática de como instalar a LocalLibrary na nuvem <a href="https://www.heroku.com/">Heroku PaaS.</a></p> + +<h3 id="Por_que_Heroku">Por que Heroku?</h3> + +<p>Heroku é um dos mais antigos e populares serviços de PaaS baseados em nuvem. Originalmente, ele suportava apenas aplicativos Ruby, mas agora pode ser usado para hospedar aplicativos de muitos ambientes de programação, incluindo Django!</p> + +<p>Estamos optando por usar o Heroku por vários motivos:</p> + +<ul> + <li>O Heroku tem um <a href="https://www.heroku.com/pricing">nível gratuito</a> que é realmente gratuito (embora com algumas limitações).</li> + <li>Como PaaS, o Heroku cuida de grande parte da infraestrutura web para nós. Isso torna muito mais fácil começar, porque você não se preocupa com servidores, balanceadores de carga, proxies reversos ou qualquer outra infraestrutura web que o Heroku fornece para nós nos bastidores.</li> + <li>Embora tenha algumas limitações, elas não afetarão este aplicativo específico. Por exemplo: + <ul> + <li>O Heroku fornece apenas armazenamento de curta duração, portanto, os arquivos carregados pelo usuário não podem ser armazenados com segurança no próprio Heroku.</li> + <li>O nível gratuito suspenderá um aplicativo da web inativo se não houver solicitações dentro de um período de meia hora. O site pode levar vários segundos para responder quando for ativado.</li> + <li>O nível gratuito limita o tempo de execução do seu site a uma determinada quantidade de horas todos os meses (sem incluir o tempo em que o site fica "adormecido"). Isso é bom para um site de baixo uso/demonstração, mas não será adequado se 100% de tempo de atividade for necessário.</li> + <li>Outras limitações estão listadas em <a href="https://devcenter.heroku.com/articles/limits">Limites</a> (documentos do Heroku).</li> + </ul> + </li> + <li>Na maioria das vezes, ele simplesmente funciona e, se você acabar adorando, dimensionar seu aplicativo é muito fácil.</li> +</ul> + +<p>Embora o Heroku seja perfeito para hospedar esta demonstração, pode não ser perfeito para o seu site real. O Heroku torna as coisas fáceis de configurar e escalar, ao custo de ser menos flexível e potencialmente muito mais caro depois que você sai do nível gratuito.</p> + +<h3 id="How_does_Heroku_work">How does Heroku work?</h3> + +<p>Heroku runs Django websites within one or more "<a href="https://devcenter.heroku.com/articles/dynos">Dynos</a>", which are isolated, virtualized Unix containers that provide the environment required to run an application. The dynos are completely isolated and have an <em>ephemeral</em> file system (a short-lived file system that is cleaned/emptied every time the dyno restarts). The only thing that dynos share by default are application <a href="https://devcenter.heroku.com/articles/config-vars">configuration variables</a>. Heroku internally uses a load balancer to distribute web traffic to all "web" dynos. Since nothing is shared between them, Heroku can scale an app horizontally simply by adding more dynos (though of course you may also need to scale your database to accept additional connections).</p> + +<p>Because the file system is ephemeral you can't install services required by your application directly (e.g. databases, queues, caching systems, storage, email services, etc). Instead Heroku web applications use backing services provided as independent "add-ons" by Heroku or 3rd parties. Once attached to your web application, the dynos access the services using information contained in application configuration variables.</p> + +<p>In order to execute your application Heroku needs to be able to set up the appropriate environment and dependencies, and also understand how it is launched. For Django apps we provide this information in a number of text files:</p> + +<ul> + <li><strong>runtime.txt</strong>:<strong> </strong>the programming language and version to use.</li> + <li><strong>requirements.txt</strong>: the Python component dependencies, including Django.</li> + <li><strong>Procfile</strong>: A list of processes to be executed to start the web application. For Django this will usually be the Gunicorn web application server (with a <code>.wsgi</code> script).</li> + <li><strong>wsgi.py</strong>: <a href="http://wsgi.readthedocs.io/en/latest/what.html">WSGI</a> configuration to call our Django application in the Heroku environment.</li> +</ul> + +<p>Developers interact with Heroku using a special client app/terminal, which is much like a Unix Bash shell. This allows you to upload code that is stored in a git repository, inspect the running processes, see logs, set configuration variables and much more!</p> + +<p>In order to get our application to work on Heroku we'll need to put our Django web application into a git repository, add the files above, integrate with a database add-on, and make changes to properly handle static files.</p> + +<p>Once we've done all that we can set up a Heroku account, get the Heroku client, and use it to install our website.</p> + +<div class="note"> +<p><strong>Note:</strong> The instructions below reflect how to work with Heroku at time of writing. If Heroku significantly change their processes, you may wish to instead check their setup documents: <a href="https://devcenter.heroku.com/articles/getting-started-with-python#introduction">Getting Started on Heroku with Django</a>.</p> +</div> + +<p>That's all the overview you need in order to get started (see <a href="https://devcenter.heroku.com/articles/how-heroku-works">How Heroku works</a> for a more comprehensive guide).</p> + +<h3 id="Creating_an_application_repository_in_Github">Creating an application repository in Github</h3> + +<p>Heroku is closely integrated with the <strong>git</strong> source code version control system, using it to upload/synchronise any changes you make to the live system. It does this by adding a new heroku "remote" repository named <em>heroku</em> pointing to a repository for your source on the Heroku cloud. During development you use git to store changes on your "master" repository. When you want to deploy your site, you sync your changes to the Heroku repository.</p> + +<div class="note"> +<p><strong>Note:</strong> If you're used to following good software development practices you are probably already using git or some other SCM system. If you already have a git repository, then you can skip this step.</p> +</div> + +<p>There are a lot of ways to work with git, but one of the easiest is to first set up an account on <a href="https://github.com/">Github</a>, create the repository there, and then sync to it locally:</p> + +<ol> + <li>Visit <a href="https://github.com/">https://github.com/</a> and create an account.</li> + <li>Once you are logged in, click the <strong>+</strong> link in the top toolbar and select <strong>New repository</strong>.</li> + <li>Fill in all the fields on this form. While these are not compulsory, they are strongly recommended. + <ul> + <li>Enter a new repository name (e.g. <em>django_local_library</em>), and description (e.g. "Local Library website written in Django".</li> + <li>Choose <strong>Python</strong> in the <em>Add .gitignore</em> selection list.</li> + <li>Choose your preferred license in the <em>Add license</em> selection list.</li> + <li>Check <strong>Initialize this repository with a README</strong>.</li> + </ul> + </li> + <li>Press <strong>Create repository</strong>.</li> + <li>Click the green "<strong>Clone or download</strong>" button on your new repo page.</li> + <li>Copy the URL value from the text field inside the dialog box that appears (it should be something like: <strong>https://github.com/<em><your_git_user_id></em>/django_local_library.git</strong>).</li> +</ol> + +<p>Now that the repository ("repo") is created we are going to want to clone it on our local computer:</p> + +<ol> + <li>Install <em>git</em> for your local computer (you can find versions for different platforms <a href="https://git-scm.com/downloads">here</a>).</li> + <li>Open a command prompt/terminal and clone your repository using the URL you copied above: + <pre class="brush: bash notranslate">git clone https://github.com/<strong><em><your_git_user_id></em></strong>/django_local_library.git +</pre> + This will create the repository in a new folder in the current working directory.</li> + <li>Navigate into the new repo. + <pre class="brush: bash notranslate">cd django_local_library</pre> + </li> +</ol> + +<p>The final steps are to copy your application into this local project directory and then add (or "push", in git lingo) the local repository to your remote Github repository:</p> + +<ol> + <li>Copy your Django application into this folder (all the files at the same level as <strong>manage.py</strong> and below, <strong>not</strong> their containing locallibrary folder).</li> + <li>Open the <strong>.gitignore</strong> file, copy the following lines into the bottom of it, and then save (this file is used to identify files that should not be uploaded to git by default). + <pre class="notranslate"># Text backup files +*.bak + +# Database +*.sqlite3</pre> + </li> + <li>Open a command prompt/terminal and use the <code>add</code> command to add all files to git. This adds the files which aren't ignored by the <strong>.gitignore</strong> file to the "staging area". + <pre class="brush: bash notranslate">git add -A +</pre> + </li> + <li>Use the <code>status</code> command to check that all files you are about to <code>commit</code> are correct (you want to include source files, not binaries, temporary files etc.). It should look a bit like the listing below. + <pre class="notranslate">> git status +On branch master +Your branch is up-to-date with 'origin/master'. +Changes to be committed: + (use "git reset HEAD <file>..." to unstage) + + modified: .gitignore + new file: catalog/__init__.py + ... + new file: catalog/migrations/0001_initial.py + ... + new file: templates/registration/password_reset_form.html</pre> + </li> + <li>When you're satisfied, <code>commit</code> the files to your local repository. This is essentially equivalent to signing off on the changes and making them an official part of the local repository. + <pre class="brush: bash notranslate">git commit -m "First version of application moved into github"</pre> + </li> + <li>At this point, the remote repository has not been changed. Synchronise (<code>push</code>) your local repository to the remote Github repository using the following command: + <pre class="notranslate">git push origin master</pre> + </li> +</ol> + +<p>When this operation completes, you should be able to go back to the page on Github where you created your repo, refresh the page, and see that your whole application has now been uploaded. You can continue to update your repository as files change using this add/commit/push cycle.</p> + +<div class="note"> +<p><strong>Tip:</strong> This is a good point to make a backup of your "vanilla" project — while some of the changes we're going to be making in the following sections might be useful for deployment on any platform (or development) others might not.</p> + +<p>The <em>best</em> way to do this is to use <em>git</em> to manage your revisions. With <em>git</em> you can not only go back to a particular old version, but you can maintain this in a separate "branch" from your production changes and cherry-pick any changes to move between production and development branches. <a href="https://help.github.com/articles/good-resources-for-learning-git-and-github/">Learning Git</a> is well worth the effort, but is beyond the scope of this topic.</p> + +<p>The <em>easiest</em> way to do this is to just copy your files into another location. Use whichever approach best matches your knowledge of git!</p> +</div> + +<h3 id="Update_the_app_for_Heroku">Update the app for Heroku</h3> + +<p>This section explains the changes you'll need to make to our <em>LocalLibrary</em> application to get it to work on Heroku. While Heroku's <a href="https://devcenter.heroku.com/articles/getting-started-with-python#introduction">Getting Started on Heroku with Django</a> instructions assume you will use the Heroku client to also run your local development environment, our changes are compatible with the existing Django development server and the workflows we've already learned.</p> + +<h4 id="Procfile">Procfile</h4> + +<p>Create the file <code>Procfile</code> (no extension) in the root of your GitHub repository to declare the application's process types and entry points. Copy the following text into it:</p> + +<pre class="notranslate">web: gunicorn locallibrary.wsgi --log-file -</pre> + +<p>The "<code>web:</code>" tells Heroku that this is a web dyno and can be sent HTTP traffic. The process to start in this dyno is <em>gunicorn</em>, which is a popular web application server that Heroku recommends. We start Gunicorn using the configuration information in the module <code>locallibrary.wsgi</code> (created with our application skeleton: <strong>/locallibrary/wsgi.py</strong>).</p> + +<h4 id="Gunicorn">Gunicorn</h4> + +<p><a href="http://gunicorn.org/">Gunicorn</a> is the recommended HTTP server for use with Django on Heroku (as referenced in the Procfile above). It is a pure-Python HTTP server for WSGI applications that can run multiple Python concurrent processes within a single dyno (see <a href="https://devcenter.heroku.com/articles/python-gunicorn">Deploying Python applications with Gunicorn</a> for more information).</p> + +<p>While we won't need <em>Gunicorn</em> to serve our LocalLibrary application during development, we'll install it so that it becomes part of our <a href="#requirements">requirements</a> for Heroku to set up on the remote server.</p> + +<p>Install <em>Gunicorn</em> locally on the command line using <em>pip</em> (which we installed when <a href="/en-US/docs/Learn/Server-side/Django/development_environment">setting up the development environment</a>):</p> + +<div class="blockIndicator note"> +<p>Note: Make sure that you're in your Python virtual environment (use the <code>workon [name-of-virtual-environment]</code> command) before you install <em>Gunicorn</em> and further modules with <em>pip</em>, or you might experience problems with importing these modules in your <strong>/locallibrary/settings.py</strong> file in the later sections. </p> +</div> + +<pre class="brush: bash notranslate">pip3 install gunicorn +</pre> + +<h4 id="Database_configuration">Database configuration</h4> + +<p>We can't use the default SQLite database on Heroku because it is file-based, and it would be deleted from the <em>ephemeral</em> file system every time the application restarts (typically once a day, and every time the application or its configuration variables are changed).</p> + +<p>The Heroku mechanism for handling this situation is to use a <a href="https://elements.heroku.com/addons#data-stores">database add-on</a> and configure the web application using information from an environment <a href="https://devcenter.heroku.com/articles/config-vars">configuration variable</a>, set by the add-on. There are quite a lot of database options, but we'll use the <a href="https://devcenter.heroku.com/articles/heroku-postgres-plans#plan-tiers">hobby tier</a> of the <em>Heroku postgres</em> database as this is free, supported by Django, and automatically added to our new Heroku apps when using the free hobby dyno plan tier.</p> + +<p>The database connection information is supplied to the web dyno using a configuration variable named <code>DATABASE_URL</code>. Rather than hard-coding this information into Django, Heroku recommends that developers use the <a href="https://warehouse.python.org/project/dj-database-url/">dj-database-url</a> package to parse the <code>DATABASE_URL</code> environment variable and automatically convert it to Django’s desired configuration format. In addition to installing the <em>dj-database-url</em> package we'll also need to install <a href="http://initd.org/psycopg/">psycopg2</a>, as Django needs this to interact with Postgres databases.</p> + +<h5 id="dj-database-url_Django_database_configuration_from_environment_variable">dj-database-url (Django database configuration from environment variable)</h5> + +<p>Install <em>dj-database-url</em> locally so that it becomes part of our <a href="#requirements">requirements</a> for Heroku to set up on the remote server:</p> + +<pre class="notranslate">$ pip3 install dj-database-url +</pre> + +<h5 id="settings.py">settings.py</h5> + +<p>Open <strong>/locallibrary/settings.py</strong> and copy the following configuration into the bottom of the file:</p> + +<pre class="notranslate"># Heroku: Update database configuration from $DATABASE_URL. +import dj_database_url +db_from_env = dj_database_url.config(conn_max_age=500) +DATABASES['default'].update(db_from_env)</pre> + +<div class="note"> +<p><strong>Note:</strong></p> + +<ul> + <li>We'll still be using SQLite during development because the <code>DATABASE_URL</code> environment variable will not be set on our development computer.</li> + <li>The value <code>conn_max_age=500</code> makes the connection persistent, which is far more efficient than recreating the connection on every request cycle. However, this is optional and can be removed if needed.</li> +</ul> +</div> + +<h5 id="psycopg2_Python_Postgres_database_support">psycopg2 (Python Postgres database support)</h5> + +<p>Django needs <em>psycopg2</em> to work with Postgres databases and you will need to add this to the <a href="#requirements">requirements.txt</a> for Heroku to set this up on the remote server (as discussed in the requirements section below).</p> + +<p>Django will use our SQLite database locally by default, because the <code>DATABASE_URL</code> environment variable isn't set in our local environment. If you want to switch to Postgres completely and use our Heroku free tier database for both development and production then you can. For example, to install psycopg2 and its dependencies locally on a Debian-flavoured Linux system you would use the following Bash/terminal commands:</p> + +<pre class="brush: bash notranslate"><code>sudo apt-get install python-pip python-dev libpq-dev postgresql postgresql-contrib</code> +pip3 install psycopg2-binary +</pre> + +<p>Installation instructions for the other platforms can be found on the <a href="http://initd.org/psycopg/docs/install.html">psycopg2 website here</a>.</p> + +<p>However, you don't need to do this — you don't need PostgreSQL active on the local computer, as long as you give it to Heroku as a requirement, in <code>requirements.txt</code> (see below).</p> + +<h4 id="Serving_static_files_in_production">Serving static files in production</h4> + +<p>During development we used Django and the Django development web server to serve our static files (CSS, JavaScript, etc.). In a production environment we instead typically serve static files from a content delivery network (CDN) or the web server.</p> + +<div class="note"> +<p><strong>Note:</strong> Serving static files via Django/web application is inefficient because the requests have to pass through unnecessary additional code (Django) rather than being handled directly by the web server or a completely separate CDN. While this doesn't matter for local use during development, it would have a significant performance impact if we were to use the same approach in production. </p> +</div> + +<p>To make it easy to host static files separately from the Django web application, Django provides the <em>collectstatic</em> tool to collect these files for deployment (there is a settings variable that defines where the files should be collected when <em>collectstatic</em> is run). Django templates refer to the hosting location of the static files relative to a settings variable (<code>STATIC_URL</code>), so that this can be changed if the static files are moved to another host/server.</p> + +<p>The relevant setting variables are:</p> + +<ul> + <li><code>STATIC_URL</code>: This is the base URL location from which static files will be served, for example on a CDN. This is used for the static template variable that is accessed in our base template (see <a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a>).</li> + <li><code>STATIC_ROOT</code>: This is the absolute path to a directory where Django's "collectstatic" tool will gather any static files referenced in our templates. Once collected, these can then be uploaded as a group to wherever the files are to be hosted.</li> + <li><code>STATICFILES_DIRS</code>: This lists additional directories that Django's collectstatic tool should search for static files.</li> +</ul> + +<h5 id="settings.py_2">settings.py</h5> + +<p>Open <strong>/locallibrary/settings.py</strong> and copy the following configuration into the bottom of the file. The <code>BASE_DIR</code> should already have been defined in your file (the <code>STATIC_URL</code> may already have been defined within the file when it was created. While it will cause no harm, you might as well delete the duplicate previous reference).</p> + +<pre class="notranslate"># Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/2.1/howto/static-files/ + +# The absolute path to the directory where collectstatic will collect static files for deployment. +STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') + +# The URL to use when referring to static files (where they will be served from) +STATIC_URL = '/static/' +</pre> + +<p>We'll actually do the file serving using a library called <a href="https://warehouse.python.org/project/whitenoise/">WhiteNoise</a>, which we install and configure in the next section.</p> + +<p>For more information, see <a href="https://devcenter.heroku.com/articles/django-assets">Django and Static Assets</a> (Heroku docs).</p> + +<h4 id="Whitenoise">Whitenoise</h4> + +<p>There are many ways to serve static files in production (we saw the relevant Django settings in the previous sections). Heroku recommends using the <a href="https://warehouse.python.org/project/whitenoise/">WhiteNoise</a> project for serving of static assets directly from Gunicorn in production.</p> + +<div class="note"> +<p><strong>Note: </strong>Heroku automatically calls <em>collectstatic</em> and prepares your static files for use by WhiteNoise after it uploads your application. Check out <a href="https://warehouse.python.org/project/whitenoise/">WhiteNoise</a> documentation for an explanation of how it works and why the implementation is a relatively efficient method for serving these files.</p> +</div> + +<p>The steps to set up <em>WhiteNoise</em> to use with the project are <a href="http://whitenoise.evans.io/en/stable/django.html">given here</a> (and reproduced below):</p> + +<h5 id="WhiteNoise">WhiteNoise</h5> + +<p>Install whitenoise locally using the following command:</p> + +<pre class="notranslate">$ pip3 install whitenoise +</pre> + +<h5 id="settings.py_3">settings.py</h5> + +<p>To install <em>WhiteNoise</em> into your Django application, open <strong>/locallibrary/settings.py</strong>, find the <code>MIDDLEWARE</code> setting and add the <code>WhiteNoiseMiddleware</code> near the top of the list, just below the <code>SecurityMiddleware</code>:</p> + +<pre class="notranslate">MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + <strong>'whitenoise.middleware.WhiteNoiseMiddleware',</strong> + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] +</pre> + +<p>Optionally, you can reduce the size of the static files when they are served (this is more efficient). Just add the following to the bottom of <strong>/locallibrary/settings.py</strong>:</p> + +<pre class="notranslate"># Simplified static file serving. +# https://warehouse.python.org/project/whitenoise/ +STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' +</pre> + +<h4 id="Requirements">Requirements</h4> + +<p>The Python requirements of your web application must be stored in a file <strong>requirements.txt</strong> in the root of your repository. Heroku will then install these automatically when it rebuilds your environment. You can create this file using <em>pip</em> on the command line (run the following in the repo root):</p> + +<pre class="brush: bash notranslate">pip3 freeze > requirements.txt</pre> + +<p>After installing all the different dependencies above, your <strong>requirements.txt</strong> file should have <em>at least</em> these items listed (though the version numbers may be different). Please delete any other dependencies not listed below, unless you've explicitly added them for this application.</p> + +<pre class="notranslate">dj-database-url==0.5.0 +Django==2.1.5 +gunicorn==19.9.0 +<strong>psycopg2-binary==2.7.7</strong> +whitenoise==4.1.2 +</pre> + +<div class="note"> +<p>Make sure that a <strong>psycopg2</strong> line like the one above is present! Even if you didn't install this locally then you should still add it to <strong>requirements.txt</strong>.</p> +</div> + +<h4 id="Runtime">Runtime</h4> + +<p>The <strong>runtime.txt</strong> file, if defined, tells Heroku which programming language to use. Create the file in the root of the repo and add the following text:</p> + +<pre class="notranslate">python-3.7.0</pre> + +<div class="note"> +<p><strong>Note:</strong> Heroku only supports a small number of <a href="https://devcenter.heroku.com/articles/python-support#supported-python-runtimes">Python runtimes</a> (at time of writing, this includes the one above). Heroku will use a supported runtime irrespective of the value specified in this file.</p> +</div> + +<h4 id="Re-test_and_save_changes_to_Github">Re-test and save changes to Github</h4> + +<p>Before we proceed, lets test the site again locally and make sure it wasn't broken by any of our changes above. Run the development web server as usual and then check the site still works as you expect on your browser.</p> + +<pre class="brush: bash notranslate">python3 manage.py runserver</pre> + +<p>Next, lets <code>push</code> our changes to Github. In the terminal (after having navigated to our local repository), enter the following commands:</p> + +<pre class="brush: python notranslate">git add -A +git commit -m "Added files and changes required for deployment to heroku" +git push origin master +</pre> + +<p>We should now be ready to start deploying LocalLibrary on Heroku.</p> + +<h3 id="Get_a_Heroku_account">Get a Heroku account</h3> + +<p>To start using Heroku you will first need to create an account:</p> + +<ul> + <li>Go to <a href="https://www.heroku.com/">www.heroku.com</a> and click the <strong>SIGN UP FOR FREE</strong> button.</li> + <li>Enter your details and then press <strong>CREATE FREE ACCOUNT</strong>. You'll be asked to check your account for a sign-up email.</li> + <li>Click the account activation link in the signup email. You'll be taken back to your account on the web browser.</li> + <li>Enter your password and click <strong>SET PASSWORD AND LOGIN</strong>.</li> + <li>You'll then be logged in and taken to the Heroku dashboard: <a href="https://dashboard.heroku.com/apps">https://dashboard.heroku.com/apps</a>.</li> +</ul> + +<h3 id="Install_the_client">Install the client</h3> + +<p>Download and install the Heroku client by following the <a href="https://devcenter.heroku.com/articles/getting-started-with-python#set-up">instructions on Heroku here</a>.</p> + +<p>After the client is installed you will be able run commands. For example to get help on the client:</p> + +<pre class="brush: bash notranslate">heroku help +</pre> + +<h3 id="Create_and_upload_the_website">Create and upload the website</h3> + +<p>To create the app we run the "create" command in the root directory of our repository. This creates a git remote ("pointer to a remote repository") named <em>heroku</em> in our local git environment.</p> + +<pre class="brush: bash notranslate">heroku create</pre> + +<div class="note"> +<p><strong>Note:</strong> You can name the remote if you like by specifying a value after "create". If you don't then you'll get a random name. The name is used in the default URL.</p> +</div> + +<p>We can then push our app to the Heroku repository as shown below. This will upload the app, package it in a dyno, run collectstatic, and start the site.</p> + +<pre class="brush: bash notranslate">git push heroku master</pre> + +<p>If we're lucky, the app is now "running" on the site, but it won't be working properly because we haven't set up the database tables for use by our application. To do this we need to use the <code>heroku run</code> command and start a "<a href="https://devcenter.heroku.com/articles/deploying-python#one-off-dynos">one off dyno</a>" to perform a migrate operation. Enter the following command in your terminal:</p> + +<pre class="brush: bash notranslate">heroku run python manage.py migrate</pre> + +<p>We're also going to need to be able to add books and authors, so lets also create our administration superuser, again using a one-off dyno:</p> + +<pre class="brush: bash notranslate">heroku run python manage.py createsuperuser</pre> + +<p>Once this is complete, we can look at the site. It should work, although it won't have any books in it yet. To open your browser to the new website, use the command:</p> + +<pre class="brush: bash notranslate">heroku open</pre> + +<p>Create some books in the admin site, and check out whether the site is behaving as you expect.</p> + +<h3 id="Managing_addons">Managing addons</h3> + +<p>You can check out the add-ons to your app using the <code>heroku addons</code> command. This will list all addons, and their price tier and state.</p> + +<pre class="brush: bash notranslate">> heroku addons + +Add-on Plan Price State +───────────────────────────────────────── ───────── ───── ─────── +heroku-postgresql (postgresql-flat-26536) hobby-dev free created + └─ as DATABASE</pre> + +<p>Here we see that we have just one add-on, the postgres SQL database. This is free, and was created automatically when we created the app. You can open a web page to examine the database add-on (or any other add-on) in more detail using the following command:</p> + +<pre class="brush: bash notranslate">heroku addons:open heroku-postgresql +</pre> + +<p>Other commands allow you to create, destroy, upgrade and downgrade addons (using a similar syntax to opening). For more information see <a href="https://devcenter.heroku.com/articles/managing-add-ons">Managing Add-ons</a> (Heroku docs).</p> + +<h3 id="Setting_configuration_variables">Setting configuration variables</h3> + +<p>You can check out the configuration variables for the site using the <code>heroku config</code> command. Below you can see that we have just one variable, the <code>DATABASE_URL</code> used to configure our database.</p> + +<pre class="brush: bash notranslate">> heroku config + +=== locallibrary Config Vars +DATABASE_URL: postgres://uzfnbcyxidzgrl:j2jkUFDF6OGGqxkgg7Hk3ilbZI@ec2-54-243-201-144.compute-1.amazonaws.com:5432/dbftm4qgh3kda3</pre> + +<p>If you recall from the section on <a href="#Getting_your_website_ready_to_publish">getting the website ready to publish</a>, we have to set environment variables for <code>DJANGO_SECRET_KEY</code> and <code>DJANGO_DEBUG</code>. Let's do this now.</p> + +<div class="note"> +<p><strong>Note:</strong> The secret key needs to be really secret! One way to generate a new key is to use the <a href="https://www.miniwebtool.com/django-secret-key-generator/">Django Secret Key Generator</a>.</p> +</div> + +<p>We set <code>DJANGO_SECRET_KEY</code> using the <code>config:set</code> command (as shown below). Remember to use your own secret key!</p> + +<pre class="brush: bash notranslate">> heroku config:set DJANGO_SECRET_KEY='eu09(ilk6@4sfdofb=b_2ht@vad*$ehh9-)3u_83+y%(+phh&=' + +Setting DJANGO_SECRET_KEY and restarting locallibrary... done, v7 +DJANGO_SECRET_KEY: eu09(ilk6@4sfdofb=b_2ht@vad*$ehh9-)3u_83+y%(+phh +</pre> + +<p>We similarly set <code>DJANGO_DEBUG</code>:</p> + +<pre class="brush: bash notranslate">> heroku config:set <code>DJANGO_DEBUG= + +Setting DJANGO_DEBUG and restarting locallibrary... done, v8</code></pre> + +<p>If you visit the site now you'll get a "Bad request" error, because the <a href="https://docs.djangoproject.com/en/2.1/ref/settings/#allowed-hosts">ALLOWED_HOSTS</a> setting is <em>required</em> if you have <code>DEBUG=False</code> (as a security measure). Open <strong>/locallibrary/settings.py</strong> and change the <code>ALLOWED_HOSTS</code> setting to include your base app url (e.g. 'locallibrary1234.herokuapp.com') and the URL you normally use on your local development server.</p> + +<pre class="brush: python notranslate">ALLOWED_HOSTS = ['<your app URL without the https:// prefix>.herokuapp.com','127.0.0.1'] +# For example: +# ALLOWED_HOSTS = ['fathomless-scrubland-30645.herokuapp.com', '127.0.0.1'] +</pre> + +<p>Then save your settings and commit them to your Github repo and to Heroku:</p> + +<pre class="brush: bash notranslate">git add -A +git commit -m 'Update ALLOWED_HOSTS with site and development server URL' +git push origin master +git push heroku master</pre> + +<div class="note"> +<p>After the site update to Heroku completes, enter a URL that does not exist (e.g. <strong>/catalog/doesnotexist/</strong>). Previously this would have displayed a detailed debug page, but now you should just see a simple "Not Found" page.</p> +</div> + +<h3 id="Debugging">Debugging</h3> + +<p>The Heroku client provides a few tools for debugging:</p> + +<pre class="brush: bash notranslate"># Show current logs +heroku logs + +# Show current logs and keep updating with any new results +heroku logs --tail + +# Add additional logging for collectstatic (this tool is run automatically during a build) +heroku config:set DEBUG_COLLECTSTATIC=1 + +# Display dyno status +heroku ps +</pre> + +<p>If you need more information than these can provide you will need to start looking into <a href="https://docs.djangoproject.com/en/2.1/topics/logging/">Django Logging</a>.</p> + +<ul> +</ul> + +<h2 id="Summary">Summary</h2> + +<p>That's the end of this tutorial on setting up Django apps in production, and also the series of tutorials on working with Django. We hope you've found them useful. You can check out a fully worked-through version of the <a href="https://github.com/mdn/django-locallibrary-tutorial">source code on Github here</a>.<br> + <br> + The next step is to read our last few articles, and then complete the assessment task.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.1/howto/deployment/">Deploying Django</a> (Django docs) + + <ul> + <li><a href="https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/">Deployment checklist</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.1/howto/static-files/deployment/">Deploying static files</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/">How to deploy with WSGI</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/modwsgi/">How to use Django with Apache and mod_wsgi</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/gunicorn/">How to use Django with Gunicorn</a> (Django docs)</li> + </ul> + </li> + <li>Heroku + <ul> + <li><a href="https://devcenter.heroku.com/articles/django-app-configuration">Configuring Django apps for Heroku</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/getting-started-with-python#introduction">Getting Started on Heroku with Django</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/django-assets">Django and Static Assets</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/python-concurrency-and-database-connections">Concurrency and Database Connections in Django</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/how-heroku-works">How Heroku works</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/dynos">Dynos and the Dyno Manager</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/config-vars">Configuration and Config Vars</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/limits">Limits</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/python-gunicorn">Deploying Python applications with Gunicorn</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/deploying-python">Deploying Python and Django apps on Heroku</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/search?q=django">Other Heroku Django docs</a></li> + </ul> + </li> + <li>Digital Ocean + <ul> + <li><a href="https://www.digitalocean.com/community/tutorials/how-to-serve-django-applications-with-uwsgi-and-nginx-on-ubuntu-16-04">How To Serve Django Applications with uWSGI and Nginx on Ubuntu 16.04</a></li> + <li><a href="https://www.digitalocean.com/community/tutorials?q=django">Other Digital Ocean Django community docs</a></li> + </ul> + </li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Testing", "Learn/Server-side/Django/web_application_security", "Learn/Server-side/Django")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> diff --git a/files/pt-br/learn/server-side/django/index.html b/files/pt-br/learn/server-side/django/index.html new file mode 100644 index 0000000000..58d0f08a16 --- /dev/null +++ b/files/pt-br/learn/server-side/django/index.html @@ -0,0 +1,75 @@ +--- +title: Django Web Framework (Python) +slug: Learn/Server-side/Django +tags: + - Aprender + - CodingScripting + - Desenvolvimento Web + - Iniciante + - Introdução + - Python + - django + - framework +translation_of: Learn/Server-side/Django +--- +<div>{{LearnSidebar}}</div> + +<p>Django é um framework de web server-side extremamente popular e repleto de características, escrito em Python. O módulo mostra por que o Django é um dos frameworks web mais populares, como configurar um ambiente de desenvolvimento e como começar a usa-lo para criar seus próprios aplicativos da Web.</p> + +<h2 id="Pré-requisitos">Pré-requisitos</h2> + +<p>Antes de iniciar este módulo você não precisa ter nenhum conhecimento de Django. Você precisará entender o que programação server-side e web frameworks são, idealmente lendo os tópicos em nosso módulo <a href="/pt-BR/docs/Learn/Server-side/First_steps">Server-side programação de website primeiros passos</a>.</p> + +<p>Um conhecimento geral de conceitos de programação e Python é recomendado, mas não essenciais para entendimento dos conceitos principais.</p> + +<div class="note"> +<p><strong>Nota</strong>: O Python é uma das linguagens de programação mais fáceis para os iniciantes lerem e entenderem. Dito isto, se você quiser entender melhor este módulo, então existem inúmeros livros e tutoriais gratuitos disponíveis pela Internet (programadores iniciantes podem querer ver a página <a href="https://wiki.python.org/moin/BeginnersGuide/NonProgrammers">Python for não programadores</a> no wiki do python.org)</p> +</div> + +<h2 id="Como_começar">Como começar?</h2> + +<dl> + <dt><a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/Introdu%C3%A7%C3%A3o">Introdução ao Django</a></dt> + <dd> + <p>Neste primeiro artigo sobre Django vamos responder a questão “O que é Django?” e mostrar um resumo sobre o que faz esse web framework ser especial. Nós vamos resumir os recursos principais, <span lang="pt-PT">i</span><span lang="pt-PT">ncluindo algumas das funcionalidades avançadas que não teremos tempo de detalhar neste módulo. Também mostraremos alguns dos principais blocos de construção de um aplicativo Django, para que você tenha uma idéia do que ele pode fazer antes de continuar e configurá-lo e começar a </span><span lang="pt-PT">se divertir</span><span lang="pt-PT">.</span></p> + </dd> + <dt><a href="/pt-BR/docs/Learn/Server-side/Django/development_environment">Configurando um ambiente de desenvolvimento Django</a></dt> + <dd>Agora que você sabe para quê o Django serve, iremos mostrar-lhe como configurar e testar um ambiente de desenvolvimento Django no Windows, Linux (Ubuntu) e Mac OS X - ou qualquer outro sistema operacional que você esteja usando, esse artigo deve ajudá-lo no que precisa para começar a desenvolver aplicações no Django.</dd> + <dt><a href="/pt-BR/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django: Website de uma Biblioteca Local</a></dt> + <dd>O primeiro artigo em nossa série de tutoria prática explica o que você irá aprender, e provê uma visão geral do site de exemplo "biblioteca geral" que estaremos trabalhando e evoluindo nos artigos subsequentes.</dd> +</dl> + +<dl> + <dt><a href="/pt-BR/docs/Learn/Server-side/Django/skeleton_website">Tutorial Django Parte 2: Criando a base do website</a></dt> + <dd>Esse artigo mostra como você pode criar um projeto de site "esqueleto" como base, o qual poderá ser preenchido com configurações, urls, models, views e templates de um site específico.</dd> + <dt><a href="/pt-BR/docs/Learn/Server-side/Django/Models">Tutorial Django Parte 3: Utilizando models</a></dt> + <dd>Este artigo mostra como definir modelos para o site<em> </em><em>BibliotecaLocal</em> - os modelos representam <span id="result_box" lang="pt"><span>as estruturas de dados em que queremos armazenar os dados do aplicativo</span></span>, além de permitirem o Django armazenar dados em banco de dados pela gente (e modificá-los depois). Ele explica o que é um modelo, como declará-lo, e alguns dos principais tipos de campos. Além de brevemente apresentar algumas das principais maneiras de acessar os dados de um modelo.</dd> + <dt><a href="/pt-BR/docs/Learn/Server-side/Django/Admin_site">Tutorial Django Parte 4: Django admin site</a></dt> + <dd>Agora que nós criamos os modelos para o site <em>BibliotecaLocal, </em>iremos usar o site Django Admin para adicionar alguns dados "reais" de livros. Primeiros mostraremos como registrar os modelos com o site admin, e então veremos como fazer login e criar alguns dados. Ao final iremos mostrar algumas maneiras de aprimorar ainda mais a apresentação do site de administração.</dd> + <dt><a href="/pt-BR/docs/Learn/Server-side/Django/Home_page">Tutorial Django Parte 5: Criando nossa página principal</a></dt> + <dd>Agora estamos prontos para adicionar o código para exibir nossa primeira página inteira - uma home page para a BibliotecaLocal que mostra quantos registros temos de cada tipo de modelo e fornece links de navegação da barra lateral para nossas outras páginas. Ao longo do caminho, obteremos experiência prática ao escrever mapas e visualizações de URLs básicos, obtendo registros do banco de dados e usando modelos.</dd> + <dt><a href="/pt-BR/docs/Learn/Server-side/Django/Generic_views">Tutorial Django Parte 6: Lista genérica e detail views</a></dt> + <dd>Este tutorial estende nosso website <em>BibliotecaLocal</em> adicionando páginas de listagem e de detalhes, para livros e autores. Aqui nós vamos aprender sobre visualizações genéricas baseadas em classes e mostrar como elas podem reduzir a quantidade de código que você tem que escrever para casos comuns. Nós também entraremos na manipulação de URL em maiores detalhes, mostrando como realizar correspondências de padrões básicas.</dd> + <dt><a href="/pt-BR/docs/Learn/Server-side/Django/Sessions">Tutorial Django Parte 7: Framework de Sessões</a></dt> + <dd>Este tutorial estende nosso site <em>BibliotecaLocal</em>, adicionando um contador de visitas baseado em sessão à home page. Esse é um exemplo relativamente simples, mas mostra como você pode usar a estrutura da sessão para prover um comportamento persistente para usuários anônimos em seus próprios sites.</dd> + <dt><a href="/pt-br/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: Autenticação de Usuário e permissões</a></dt> + <dd>Neste tutorial, mostraremos como permitir que os usuários façam login em seu site com suas próprias contas e como controlar o que podem fazer e ver com base no fato de estarem ou não logados e de suas permissões. Como parte dessa demonstração, ampliaremos o site da LocalLibrary, adicionando páginas de login e logout e páginas específicas de usuários e funcionários para a visualização de livros que foram emprestados.</dd> + <dt><a href="/pt-BR/docs/Learn/Server-side/Django/Forms">Tutorial Django Parte 9: Trabalhando com formulários</a></dt> + <dd>Neste tutorial iremos mostrar como trabalhar com <a href="/en-US/docs/Web/Guide/HTML/Forms">HTML Forms</a> no Django, e em particular a maneira mais fácil para escrever formulários para criar, atualizar e excluir instâncias do modelo. Como parte desta demonstração ampliaremos o website <em>BibliotecaLocal</em> para que bibliotecários possam renovar livros, e criar, atualizar e excluir autores usando usindo nossos próprios formulários (em vez de usar o aplicativo administrativo).</dd> + <dt><a href="/pt-BR/docs/Learn/Server-side/Django/Testing">Tutorial Django Parte 10: Testando uma aplicação web Django</a></dt> + <dd>Conforme os sites crescem, tornam-se mais difíceis de testar manualmente - não apenas há mais para testar, mas à medida que as interações entre os componentes se tornam mais complexas, uma pequena alteração em uma área pode exigir muitos testes adicionais para verificar seu impacto em outras áreas. Uma forma de mitigar esses problemas é escrever testes automatizados, que podem ser executados de maneira fácil e confiável sempre que você fizer uma alteração. Este tutorial mostra como automatizar <em>o teste de unidade</em> do seu site usando a estrutura de teste do Django.</dd> + <dt><a href="/pt-BR/docs/Learn/Server-side/Django/Deployment">Tutorial Django Parte 11: Implantando Django em produção</a></dt> + <dd>Agora você criou (e testou) um site da LocalLibrary incrível, você vai querer instalá-lo em um servidor web público para que ele possa ser acessado pela equipe da biblioteca e membros pela Internet. Este artigo fornece uma visão geral de como você pode encontrar um host para implantar seu site e o que você precisa fazer para preparar seu site para a produção.</dd> + <dt><a href="/pt-BR/docs/Learn/Server-side/Django/web_application_security">Segurança de aplicações web Django</a></dt> + <dd>Proteger os dados do usuário é uma parte essencial do design de qualquer site. Anteriormente, explicamos algumas das ameaças de segurança mais comuns no artigo <a href="https://developer.mozilla.org/en-US/docs/Web/Security">Web security</a> - este artigo fornece uma demonstração prática de como as proteções internas do Django lidam com essas ameaças.</dd> + <dt></dt> +</dl> + +<h2 id="Assessments">Assessments</h2> + +<p>A avaliação a seguir testará sua compreensão de como criar um site usando o Django, conforme descrito nos guias listados acima.</p> + +<dl> + <dt><a href="/pt-BR/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></dt> + <dd>Nesta avaliação, você usará alguns dos conhecimentos que aprendeu neste módulo para criar seu próprio blog.</dd> +</dl> diff --git a/files/pt-br/learn/server-side/django/introdução/index.html b/files/pt-br/learn/server-side/django/introdução/index.html new file mode 100644 index 0000000000..9258d18dc6 --- /dev/null +++ b/files/pt-br/learn/server-side/django/introdução/index.html @@ -0,0 +1,346 @@ +--- +title: Introdução ao Django +slug: Learn/Server-side/Django/Introdução +tags: + - Aprender + - Codificação + - Iniciante + - Introdução + - Programação do lado do servidor + - Python + - django +translation_of: Learn/Server-side/Django/Introduction +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/Server-side/Django/development_environment", "Learn/Server-side/Django")}}</div> + +<p class="summary">Neste primeiro artigo do Django, respondemos a pergunta "O que é o Django?" e daremos uma visão geral do que torna este framework web especial. Vamos descrever os principais recursos, incluindo algumas das funcionalidades avançadas que não teremos tempo para abordar detalhadamente neste módulo. Também mostraremos alguns dos principais blocos de construção de um aplicativo Django (embora neste momento você ainda não tenha um ambiente de desenvolvimento para testá-lo).</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré-requisitos:</th> + <td> + <p><span id="result_box" lang="pt"><span>Conhecimentos básicos em computação.</span> <span>Um entendimento geral de <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps">programação de websites do lado do servidor</a> e, em particular, a mecânica de <a href="/pt-BR/docs/">interações cliente-servidor em websites</a>.</span></span></p> + </td> + </tr> + <tr> + <th scope="row">Objetivos:</th> + <td>Ganhar familiaridade com o que é o Django, quais funcionalidades ele fornece e os principais blocos de construção de uma aplicação django.</td> + </tr> + </tbody> +</table> + +<h2 id="O_que_é_Django">O que é Django?</h2> + +<p>Django é um framework web Python de alto nível que permite o rápido desenvolvimento de sites seguros e de fácil manutenção. Construido por desenvolvedores experientes, o Django cuida de grande parte do trabalho de desenvolvimento web, para que você possa se concentrar em escrever seu aplicativo sem precisar reinventar a roda. É gratuito e de código aberto, tem uma comunidade próspera e ativa, ótima documentação e muitas opções de suporte gratuito e pago. </p> + +<p>Django ajuda você a escrever programas que são:</p> + +<dl> + <dt>Completo</dt> + <dd>Django segue a filosofia de "baterias incluídas" e fornece quase tudo que desenvolvedores possam querer fazer "fora da caixa". Como tudo o que você precisa é parte de um "produto", tudo funciona perfeitamente junto, seguindo princípios de design consistentes, contando uma extensa e <a href="https://docs.djangoproject.com/pt-br/2.1/">atualizada documentação</a>.</dd> + <dt>Versátil</dt> + <dd>Django pode ser (e tem sido) utilizado para construir quase todo tipo de website - desde sistema de gestão de conteúdo e wikis, passando por redes sociais e sites de notícias. Ele pode trabalhar com qualquer framework do lado do cliente, e pode entregar conteúdo em praticamente qualquer formato (incluindo HTML, feeds RSS, JSON, XML, etc). Esse site que você está lendo agora é baseado em Django.</dd> + <dd>À medida em que, internamente, fornece opções para quase todo tipo de funcionalidade que você possa querer (por exemplo: vários banco de dados que são populares, motores de template, etc), ele pode também ser extendido para utilizar outros componentes, caso seja necessário.</dd> + <dt>Seguro</dt> + <dd>Django ajuda os desenvolvedores a evitar os erros de segurança mais comuns, fornecendo um framework que foi desenhado para "fazer as coisas certas", de modo a proteger o website automaticamente. Por exemplo, Django fornece uma maneira segura de gerenciar as contas dos usuários e suas senhas, evitando erros comuns, tais como colocar informações da sessão em cookies, onde ficam vulneráveis (ao invés disso os cookies contém apenas uma chave e os dados são armazenados no banco de dados), ou armazenar as senhas de forma direta, ao invés de gravar um hash para essas senhas.</dd> + <dd><em>Um hash de senha é um valor fixed-length (tamanho-fixo) criado mandando a senha por uma <a href="https://pt.wikipedia.org/wiki/Fun%C3%A7%C3%A3o_hash_criptogr%C3%A1fica">cryptographic hash function (função hash criptográfica)</a>. Django pode checar se uma senha inserida está correta executando ela pela função hash e comparando a saída com o valor hash armazenado. Porém devido a natureza "one-way" ("um-caminho") da função, mesmo que o valor hash armazenado estiver comprometido, é difcil para uma pessoa comentendo um ataque resolver a senha original.</em></dd> + <dd>O Django ativa a proteção contra muitas vulnerabilidades por padrão, incluindo SQL injection (injeção de SQL), cross-site scripting, cross-site request forgery (Falsificação de solicitação entre sites), e clickjacking ("furto de click") (veja <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps/Website_security">Segurança de sites</a> para mais detalhes de tais ataques).</dd> + <dt>Escalável</dt> + <dd>Django usa uma arquitetura baseada em componentes “<a href="https://en.wikipedia.org/wiki/Shared_nothing_architecture">shared-nothing</a>” ("nada-compartilhado") (cada parte da arquitetura é idependente das outras, e consequentemente podem ser subistituidas ou mudadas caso necessário). Ter uma separação clara entre as partes diferentes significa que pode se escalar para um trágefo aumentado adicionando hardware em qualquer nível: servidores de cache, servidores de banco de dados ou servidores de aplicação. Alguns dos sites mais ocupados escalaram o Django com sucesso para cumprir com as suas demandas (ex: Instagram e Disqus).</dd> + <dt>Sustentável</dt> + <dd>O código do Django é escrito usando princípios de design e padrões que encorajam a criação de codigo sustentável (que facilita a manutenção) e reusável. Em particular, isso utiliza o principio DRY - Don't Repeat Yourself (Não Repita a Si Mesmo) para que não haja duplicações desnecessárias, reduzindo a quantidade de código. O Django também promove o agrupamento de funcionalidades relacionadas para aplicativos reusáveis e, em um nível mais baixo, grupos de código relacionados para modulos (juntamente as linhas do padrão <a href="https://pt.wikipedia.org/wiki/MVC">MVC - Model View Controller</a>).</dd> + <dt>Portável</dt> + <dd>Django é escrito em Python, que executa em muitas plataformas. Isso significa que você não esta preso em nenhuma plataforma de servidor em particular, e pode executar seus aplicativos em muitas distrubuições do Linux, Windows e Mac OS X. Além disso, o Django tem um bom suporte em muitos provedores de servidores de web, que muitas vezes provem infraestrutura especifca e documentação para hospedar sites feitos com Django.</dd> +</dl> + +<h2 id="De_onde_o_Django_veio">De onde o Django veio?</h2> + +<p>Django foi inicialmente desenvolvido entre 2003 e 2005 por um time de web que era responsável por criar e manter sites de jornal. Depois de criar um número de sites, o time começou a fatorar e reutilizar muitos de seus códigos comuns e padrões de design. Esse código comum evoluiu para um framework genérico de desenvolvimento web, que foi lançado como um projeto de código aberto nomeado "Django" em Julho de 2005.</p> + +<p>Django continou a crescer e aprimorar, desde seu lançamento (1.0) em Setembro de 2008 até a versão recentemente lançada 2.0 em 2017. Cada lançamento adicionou novas funcionalidades e consertou falhas, variando entre suportar novos tipos de banco de dados, mecanismos de template e caches, até a adição de funções view "genéricas" e classes (que reduzem a quantidade de código que os desenvolvedores tem que escrever para um número de tarefas de programação).</p> + +<div class="note"> +<p><strong>Nota</strong>: Cheque as <span style="line-height: 1.5;"><a href="https://docs.djangoproject.com/pt-br/2.1/releases/">notas de lançamento</a> no site do Django para ver o que mudou nas versões mais recentes, e quanto trabalho esta sendo feito para tornar o Django melhor.</span></p> +</div> + +<p>Django é um projeto de código aberto, colaborativo e próspero, com milhares de usuários contribuindo. Embora ainda tenha alguns recursos que refletem sua origem, Django evoluiu para um framework versátil que é capaz de desenvovler qualquer tipo de website.</p> + +<h2 id="Quão_popular_é_o_Django">Quão popular é o Django?</h2> + +<p>Não há nenhum método disponível e definitivo para medir a popularidade dos framework server-side (lado do servidor) (apesar de sites como <a href="http://hotframeworks.com/">Hot Frameworks</a> tentam acessar a popularidade usando mecanismos como contar o numero de projetos no GitHub e perguntas no StackOverflow para cada cada platafroma). Uma questão melhor é se o Django é "popular o suficiente" para evitar problemas de plataformas não populares. Ele continua a evoluir? Você consegue ajuda se precisar? Existem oportunidades para você ganhar dinheiro se voce aprender Django?</p> + +<p>Baseado no número de sites com alto perfil que usam Django, o número de pessoas contribuindo para a base de código, e o número de pessoas provendo ambos suporte gratuito e pago, então sim, Django é um framework popular!</p> + +<p>Alguns sites de alto perfil que usam Django são: Disqus, Instagram, Knight Foundation, MacArthur Foundation, Mozilla, National Geographic, Open Knowledge Foundation, Pinterest, and Open Stack (fonte: <a href="https://www.djangoproject.com/">Página inicial do django</a>).</p> + +<h2 id="O_Django_é_opinativo">O Django é opinativo?</h2> + +<p>Frameworks de web frequentemente referem a si mesmos como "opinativo" e "não opinativo".</p> + +<p>Frameworks opinativos são aqueles com opiniões sobre o "modo correto" de como lidar com uma tarefa em particular. Eles frequentemente auxiliam no desenvolvimento rapido <em>em um domínio em particular</em> (resolvendo problemas de um tipo em particular) porque o modo correto de fazer qualquer coisa normalmente já foi bem compreendido e bem documentado. Porém eles podem ser menos flexíveis para resolver problemas fora de seu principal domínio, e tendem a oferecer menos opções para quais componentes e abordagens eles podem usar.</p> + +<p>Frameworks não opinativos, em contraste, possuem bem menos restrições sobre a melhor maneira de unir os componentes para atingir um objetivo, ou até mesmo quais componentes devem ser usados. Eles tornam mais fácil para os desenvolvedores usar as ferramentas mais adequadas para completar uma tarefa em particular, apesar do custo de você mesmo ter que achar esses componentes.<br> + <br> + Django é "moderadamente opinativo" e, portantanto, oferece o "melhor dos dois mundo". Ele fornece um conjunto de componentes para lidar com a maioria das tarefas de desenvolvimento web, e uma (ou duas) maneiras preferidas de usá-las. No entanto, a arquitetura desacoplada do Django significa que você geralmente pode escolher entre várias opções diferentes, ou adicionar suporte para outras completamente novas, se desejar.</p> + +<h2 id="Com_o_que_o_código_do_Django_parece">Com o que o código do Django parece?</h2> + +<p>Em um site data-driven (orientado a dados) tradicional, um aplicativo web aguarda solicitações HTTP do navegador da web (ou outro cliente). Quando uma solicitação é recebida, o aplicativo calcula o que é necessário com base na URL e possivelmente nas informações dos dados <code>POST</code> ou <code>GET</code>. Dependendo do que for necessário, ele poderá ler ou gravar informações de um banco de dados ou executar outras tarefas necessárias para satisfazer a solicitação. O aplicativo retornará uma resposta para o navegador da web, normalmente criando dinamicamente uma página HTML para o navegador exibir, inserindo os dados recuperados em espaços reservados em um template HTML.</p> + +<p>Aplicativos web feitos com Django geralmente agrupam o código que manipula cada uma dessas etapas em arquivos separados:</p> + +<p><img alt="" src="https://i.postimg.cc/W4yzpVcd/arq.png" style="border-style: solid; border-width: 1px; height: 503px; width: 713px;"></p> + +<ul> + <li><strong>URLs: </strong>Embora seja possível processar solicitações de cada URL por meio de uma única função, é muito mais simples fazer a manutenção do código escrevendo uma função view (vista) separada para manipular cada recurso. Um mapeador de URLs é usado para redirecionar solicitações HTTP para a view apropriada com base na URL da solicitação. O mapeador de URLs também pode corresponder padrões específicos de strings (cadeia de caracteres) ou dígitos que aparecem em um URL e transmiti-los a uma função view como dados.</li> + <li><strong>View (Vista):</strong> Uma view é uma função manipuladora de solicitações, que recebe solicitações HTTP e retorna respostas HTTP. As views acessam os dados necessários para satisfazer solicitações por meio dos <em>models (modelos)</em> e encarregam a formatação da resposta aos <em>templates</em>.</li> + <li><strong>Models (Modelos):</strong> Modelos são objetos em Python que definem a estrutura dos dados de um aplicativo, e fornecem mecanismos para gerenciar (adicionar, modificar e excluir) e consultar registros no banco de dados.</li> + <li><strong>Templates:</strong> Um template é um arquivo de texto que define a estrutura ou o layout de um arquivo (como uma página HTML), com espaços reservados usados para representar o conteúdo real. Uma <em>view</em> pode criar dinamicamente uma página HTML usando um template HTML, preenchendo-a com dados de um <em>model (modelo)</em>. Um template pode ser usado para definir a estrutura de qualquer tipo de arquivo; não precisa ser HTML!</li> +</ul> + +<div class="note"> +<p><strong>Nota</strong>: Django refere a essa organização como uma arquitetura nomeada "Model View Template (MVT)" ("Modelo Vista Template"). Ela tem muitas semelhanças com a familiar arquitetura <a href="https://pt.wikipedia.org/wiki/MVC">Model View Controller (Modelo Vista Controlador)</a>.</p> +</div> + +<ul> +</ul> + +<p>As seções abaixo lhe darão uma idéia de como essas partes principais de um aplicativo do Django se parecerão (nos vamos entrar em mais detalhes mais tarde no curso, assim que configurarmos um ambiente de desenvolvimento).</p> + +<h3 id="Enviando_a_solicitação_para_a_view_correta_urls.py">Enviando a solicitação para a view correta (urls.py)</h3> + +<p>Um mapeador de URLs normalmente é armazenado em um arquivo chamado <strong>urls.py</strong>. No exemplo abaixo, o mapeador (<code>urlpatterns</code>) (<em>padrões de url</em>) define uma lista de mapeamentos entre <em>rotas</em> (<em>padrões</em> específicos de URL) e funções view correspondentes. Se uma solicitação HTTP for recebida com uma URL correspondente a um padrão especificado, a função view associada será chamada e a solicitação/requisição sera transmitida.</p> + +<pre class="notranslate"><code>urlpatterns = [ + <strong>path('admin/', admin.site.urls),</strong> + path('book/<int:id>/', views.book-detail, name='book-detail'), + path('catalog/', include('catalog.urls')), + re_path(r'^([0-9]+)/$', views.best), +] + +# favor utilizar o código acima no seu projeto ao invés do que está abaixo +# urlpatterns = [ +# path('admin/', admin.site.urls), +# path('livro/<int:id>/', views.livro-detalhes, name='livro-detalhes'), +# path('catalogo/', include('catalogo.urls')), +# re_path(r'^([0-9]+)/$', views.melhor), +# ]</code> +</pre> + +<p>O objeto <code>urlpatterns</code> é uma lista de funções <code>path()</code> (caminhos) e/ou <code>re_path()</code> (listas em Python são definidas usando colchetes, onde os itens são separados por vírgulas e podem conter opcionalmente uma vírgula no final. Por exemplo: <strong><code>[item1, item2, item3,]</code></strong>).</p> + +<p>O primeiro argumento para ambos os métodos é uma rota (padrão) que será correspondida. O método <code>path()</code> usa sinais de menor e maior (<, >) para definir partes de uma URL que serão capturadas e passadas para a função view como argumentos nomeados. A função <code>re_path()</code> usa uma abordagem de correspondência de padrões flexível, conhecida como expressão regular. Nós vamos falar sobre isso em um artigo posterior!</p> + +<p>O segundo argumento é outra função que será chamada quando o padrão for correspondido. A notação <code>views.book-detail</code> (<code>views.livro-detalhes</code>) indica que a função é chamada de <code>book-detail()</code> (<code>livro-detalhes()</code>) e pode ser encontrada em um módulo chamado <code>views</code> (ou seja, dentro de um arquivo chamado <code>views.py</code>)</p> + +<h3 id="Manipulando_a_solicitação_views.py">Manipulando a solicitação (views.py)</h3> + +<p>As view são o coração do aplicativo web, recebendo solicitações HTTP de clientes da web e retornando respostas HTTP. No meio disto, eles preparam os outros recursos do framework para acessar bancos de dados, renderizar (exibir) templates, etc.</p> + +<p>O exemplo abaixo mostra uma função view mínima chamada <code>index()</code>, que poderia ter sido chamado pelo nosso mapeador de URLs na seção anterior. Como todas as funções <em>view</em>, ele recebe um objeto <code>HttpRequest</code> como um parâmetro (<code>request</code>) e retorna um objeto <code>HttpResponse</code>. Nesse caso, não fazemos nada com a solicitação, e nossa resposta simplesmente retorna uma string. Mostraremos uma solicitação que faz algo mais interessante em uma seção posterior.</p> + +<pre class="brush: python notranslate">## filename: views.py (Django view functions) + +from django.http import HttpResponse + +def index(request): + # Get an HttpRequest - the request parameter + # perform operations using information from the request. + # Return HttpResponse + return HttpResponse('Hello from Django!') + +<code># favor utilizar o código acima no seu projeto ao invés do que está abaixo</code> +## nome do arquivo: views.py (Onde as funções view ficam) + +from django.http import HttpResponse + +def index(requisito): + # Recebe um HttpRequest - o parametro requisito + # Executar operações usando informações do requisito (solicitação). + # Retornar HttpResponse + return HttpResponse('Um oi do Django!') +</pre> + +<div class="note"> +<p><strong>Nota</strong>: Um pouquinho de Python:</p> + +<ul> + <li><a href="https://docs.python.org/3/tutorial/modules.html">Módulos do Python</a> são "bibliotecas" de funções, armazenadas em arquivos separados, que podemos utilizar em nosso código. Aqui nós importamos apenas o objeto <code>HttpResponse</code> do módulo <code>django.http</code> para que possamos usá-lo em nossa view: <code>from django.http import HttpResponse</code>. Existem outras maneiras de importar alguns ou todos os objetos de um módulo.</li> + <li>As funções em Python são declaradas usando a palavra-chave <code>def</code> como mostrado acima, com parâmetros nomeados listados entre parênteses após o nome da função; a linha inteira termina em dois pontos. Observe como as próximas linhas são todas <strong>recuadas</strong>. O recuo é importante, pois especifica que as linhas de código estão dentro desse bloco específico (a indentação obrigatória é um recurso chave do Python e é um dos motivos pelos quais o código Python é tão fácil de ler).</li> +</ul> +</div> + +<ul> +</ul> + +<p>Views geralmente são armazenadas em um arquivo chamado <strong>views.py</strong>.</p> + +<h3 id="Definindo_o_modelo_dos_dados_models.py">Definindo o modelo dos dados (models.py)</h3> + +<p>Os aplicativos web feitos com Django gerenciam e consultam dados por meio de objetos do Python chamados de modelos. Os modelos definem a estrutura dos dados armazenados, incluindo os <em>tipos </em>do campo e possivelmente também seu tamanho máximo, valores padrão, opções de lista de seleção, texto de ajuda para documentação, texto de etiqueta (label) para formulários etc. A definição do modelo é independente do banco de dados subjacente — você pode escolher um dentre vários como parte das configurações do seu projeto. Uma vez que você escolheu qual banco de dados você quer usar, você não precisa se comunicar diretamente com ele — você apenas escreve a estrutura dos seus modelos e qualquer outro código, e o Django lida com todo o trabalho de se comunicar com o banco de dados para você.</p> + +<p>O trecho de código abaixo mostra um modelo simples do Django para um objeto <code>Team</code> (Time). A classe <code>Team</code> é derivada da classe do Django <code>models.Model</code>. Ela define o nome e o nível da equipe como campos de caractere e especifica um número máximo de caracteres a serem armazenados para cada registro. O <code>team_level</code> (time_nivel) pode ser um de vários valores, portanto, o definimos como um campo de opção e fornecemos um mapeamento entre as opções a serem exibidas e os dados a serem armazenados, junto com um valor padrão.</p> + +<pre class="brush: python notranslate">## filename: models.py + +from django.db import models + +class Team(models.Model): + team_name = models.CharField(max_length=40) + + TEAM_LEVELS = ( + ('U09', 'Under 09s'), + ('U10', 'Under 10s'), + ('U11', 'Under 11s'), + ... #list other team levels + ) + + team_level = models.CharField(max_length=3,choices=TEAM_LEVELS,default='U11') + +<code># favor utilizar o código acima no seu projeto ao invés do que está abaixo</code> +## nome do arquivo: models.py + +from django.db import models + +class Time(models.Model): + # models.CharField define um campo de caractere no banco de dados e max_length define o tamanho maximo permitido + time_nome = models.CharField(max_length=40) + + TIME_NIVEIS = ( + ('A09', 'Abaixo de 09'), + ('A10', 'Abaixo de 10'), + ('A11', 'Abaixo de 11'), + ... #list other team levels + ) + + time_nivel = models.CharField(max_length=3,choices=TIME_NIVEIS,default='A11') # choices-opções / default-padrão +</pre> + +<div class="note"> +<p><strong>Nota</strong>: Um pouquinho de Python:</p> + +<ul> + <li>O Python suporta "programação orientada a objetos", um estilo de programação onde organizamos nosso código em objetos, que incluem dados e funções relacionadas para operar nesses dados. Os objetos também podem herdar/estender/derivar de outros objetos, permitindo que um comportamento comum entre objetos relacionados seja compartilhado. Em Python, usamos a palavra-chave <code>class</code> (classe) para definir o "blueprint" (modelo/planta/plano) de um objeto. Podemos criar várias <em>instâncias</em> específicas do tipo de objeto com base no modelo da classe.<br> + <br> + Por exemplo, aqui temos uma classe <code>Team</code> (Time), que deriva da classe <code>Model</code>. Isso significa que é um modelo e conterá todos os métodos de um modelo, mas também podemos fornecer recursos especializados próprios. Em nosso modelo, definimos os campos que nosso banco de dados precisará para armazenar nossos dados, dando-lhes nomes específicos. O Django usa essas definições, incluindo os nomes dos campos, para criar o banco de dados subjacente.</li> +</ul> +</div> + +<h3 id="Consultando_dados_views.py">Consultando dados (views.py)</h3> + +<p>O modelo Django fornece uma query API simples para buscas no banco de dados. Isto pode combinar com um grande número de campos ao mesmo tempo utilizando diversos critérios (ex.: exato, maiúsculas e minúsculas (case-sensitive), maior que, etc.), e pode suportar definições complexas (por exemplo, você pode especificar a busca por times U11 que tem os nomes começando com 'Fr" ou terminando com "al").</p> + +<p>O trecho de código mostra uma função da View (manipulador de recursos) para exibir todos os nossos times U09. A linha em negrito mostra como podemos usar a API modelo de consulta para filtrar todos os registros em que o campo <code>team_level</code> possui exatamente o texto 'U09' (observe como esse critério é passado para a função <code>filter()</code> com o argumento no campo de nome e o tipo de busca de correspondência (<strong>exact</strong>) separado por um sublinhado duplo: <strong>(team_level__exact</strong>).</p> + +<pre class="brush: python notranslate">## filename: views.py + +from django.shortcuts import render +from .models import Team + +def index(request): + <strong>list_teams = Team.objects.filter(team_level__exact="U09")</strong> + context = {'youngest_teams': list_teams} + return render(request, '/best/index.html', context) + +# favor utilizar o código acima no seu projeto ao invés do código abaixo +## nome do arquivo: views.py + +from django.shortcuts import render +from .models import Team + +def index(request): + <strong>lista_times =</strong> <strong>Team.objects.filter(team_level__exact="U09")</strong> + contexto = {'times_jovens': lista_times} + return render(request, '/best/index.html', contexto) +</pre> + +<dl> +</dl> + +<p>A função <code>index()</code> usa a função <code>render()</code> para criar o <code>HttpResponse</code> que é enviado de volta para o navegador. Essa função é um atalho, ela cria um arquivo HTML combinando um modelo HTML específico com alguns dados (fornecidos pela variável denominada "<code>context</code>"). Na próxima seção, mostramos como os dados são inseridos no modelo para criar HTML.</p> + +<h3 id="Renderizando_dados_Modelos_HTML">Renderizando dados (Modelos HTML)</h3> + +<p>O sistema de modelo permite especificar a estrutura de um documento de saída, usando espaços reservados para dados que serão preenchidos quando uma página for gerada. Os modelos geralmente são usados para criar HTML, mas também podem criar outros tipos de documentos. O Django suporta o sistema de modelos nativo e outra biblioteca Python popular chamada Jinja2 pronta para uso (também pode ser feita para suportar outros sistemas, se necessário).</p> + +<p>O trecho de código mostra a aparência do modelo HTML chamado pela função <code>render()</code> na seção anterior. Este modelo foi escrito sob a premissa de que ele terá acesso a uma variável do tipo lista chamada <code>youngest_teams</code> quando for renderizada (contida na variável <code>context</code> dentro da função <code>render()</code> acima). Dentro do esqueleto HTML, temos um a expressão que primeiro verifica se a variável <code>youngest_teams</code> existe e a itera em um loop <code>for</code>. Em cada iteração, o modelo exibe o valor <code>team_name</code> de cada equipe em um elemento {{htmlelement("li")}}.</p> + +<pre class="brush: python notranslate">## filename: best/templates/best/index.html + +<!DOCTYPE html> +<html lang="en"> +<body> + + {% if youngest_teams %} + <ul> + {% for team in youngest_teams %} + <li>\{\{ team.team_name \}\}</li> + {% endfor %} + </ul> +{% else %} + <p>No teams are available.</p> +{% endif %} + +</body> +</html> + +#favor utilizar o código acima no seu projeto ao invés do código abaixo +## nome do arquivo: best/templates/best/index.html + +<!DOCTYPE html> +<html lang="pt"> +<body> + + {% if youngest_teams %} + <ul> + {% for team in youngest_teams %} + <li>\{\{ team.team_name \}\}</li> + {% endfor %} </ul> {% else %} + <p>Nenhum time disponível.</p> + {% endif %} + </body> + </html> +</pre> + +<h2 id="O_que_mais_você_pode_fazer">O que mais você pode fazer?</h2> + +<p>As seções anteriores mostram os principais recursos que você usará na maioria dos aplicativos Web: mapeamento de URL, views, moldes e modelos. O Django também fornece outras coisas, como:</p> + +<ul> + <li><strong>Formulários (Forms)</strong>: Os formulários HTML são usados para coletar dados do usuário para processamento no servidor. Django simplifica a criação, validação e processamento de formulários.</li> + <li><strong>Autenticação de usuário e permissões</strong>: Django inclui um sistema robusto de autenticção e permissão de usuário, construído com a segurança em mente.</li> + <li><strong>Caching</strong>: Criar conteúdo dinamicamente é muito mais pesado (e lento) computacionalmente do que exibir conteúdo estático. O Django fornece armazenamento em cache flexível para que você possa armazenar toda ou parte de uma página pronta para que ela não seja renderizada novamente, exceto quando necessário.</li> + <li><strong>Site de administração</strong>: O site de administração do Django é incluído por padrão quando você cria um aplicativo usando o esqueleto básico. Ele facilita o fornecimento de uma página de administração para os administradores do site criarem, editarem e exibirem quaisquer modelos de dados em seu site</li> + <li><strong>Serializando dados</strong>: O Django facilita a serialização e a veiculação de dados como XML ou JSON. Isso pode ser útil ap criar um serviço Web (um site que serve apenas para que dados sejam consumidos por outros aplicativos ou sites e não exibe nada por si só), ou ao criar um site no qual o código do lado do cliente lida com todas as renderizações.</li> +</ul> + +<h2 id="Resumo">Resumo</h2> + +<p>Parabéns, você completou o primeiro passo em sua jornada no Django! Agora você deve entender os principais benefícios do Django, um pouco sobre sua história e aproximadamente como podem ser as partes principais de um aplicativo Django. Você também deve ter aprendido algumas coisas sobre a linguagem de programação Python, incluindo a sintaxe para listas, funções e classes.</p> + +<p>Você já viu algum código real do Django acima, mas, diferentemente do código do lado do cliente, você precisa configurar um ambiente de desenvolvimento para executá-lo. Esse é o nosso próximo passo.</p> + +<div>{{NextMenu("Learn/Server-side/Django/development_environment", "Learn/Server-side/Django")}}</div> + +<h2 id="Neste_módulo">Neste módulo</h2> + +<ul> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Introdução">Introdução ao Django</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Configurando um ambiente de desenvolvimento</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django</a><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website"> Parte 2: Criando um esqueleto de site</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django</a><a href="/en-US/docs/Learn/Server-side/Django/Models"> Parte 3: Usando moldes</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django</a><a href="/en-US/docs/Learn/Server-side/Django/Admin_site"> Parte 4: Site administrador do Django</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django</a><a href="/en-US/docs/Learn/Server-side/Django/Home_page"> Parte 5: Criando nossa página principal</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django</a><a href="/en-US/docs/Learn/Server-side/Django/Generic_views"> Parte 6: Generic list and detail views</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django</a><a href="/en-US/docs/Learn/Server-side/Django/Sessions"> Parte 7: Sessions framework</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django</a><a href="/en-US/docs/Learn/Server-side/Django/Authentication"> Parte 8: Autenticação de usuário e permissões</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django</a><a href="/en-US/docs/Learn/Server-side/Django/Forms"> Parte 9: Trabalhando com formulários</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django</a><a href="/en-US/docs/Learn/Server-side/Django/Testing"> Parte 10: Testando uma aplicação web Django</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django</a><a href="/en-US/docs/Learn/Server-side/Django/Deployment"> Parte 11: Implantando o Django na produção</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Segurança da aplicação web Django</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">Criando um mini blog Django</a></li> +</ul> diff --git a/files/pt-br/learn/server-side/django/models/index.html b/files/pt-br/learn/server-side/django/models/index.html new file mode 100644 index 0000000000..f0a5a3ca28 --- /dev/null +++ b/files/pt-br/learn/server-side/django/models/index.html @@ -0,0 +1,459 @@ +--- +title: 'Tutorial Django Parte 3: Usando models' +slug: Learn/Server-side/Django/Models +translation_of: Learn/Server-side/Django/Models +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django")}}</div> + +<p class="summary">Este artigo mostra como definir os modelos para o website <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a>. Ele explica o que é um modelo, como ele é declarado e mostra algum dos principais tipos de campo. Ele também mostra brevemente algumas das principais formas pelas quais você pode acessar dados do modelo.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré-requisitos:</th> + <td><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Criar um esqueleto de um site</a>.</td> + </tr> + <tr> + <th scope="row">Objetivo:</th> + <td>Ser capaz de projetar e criar seus próprios modelos, escolhendo os campos de forma apropriada.</td> + </tr> + </tbody> +</table> + +<h2 id="Visão_Geral">Visão Geral</h2> + +<p>Aplicativos Django acessam e gerenciam dados através de objetos Python chamados de modelos (models). Modelos definem a <em>estrutura</em> dos dados armazenados, incluindo os tipos de campos e possivelmente também o seu tamanho máximo, valores default, opções de listas de seleção, texto de ajuda para documentação, texto de labels para formulários, etc. A definição do modelo é independente do banco de dados - você pode escolher um tipo de banco como parte das configurações do seu projeto. Uma vez que você tenha escolhido qual banco será utilizado você precisa conversar diretamente com ele - você somente escreve a estrutura do seu modelo e outros códigos, e o Django faz todo o trabalho sujo de comunicação com o banco para você.</p> + +<p>Este tutorial mostra como definir e acessar os modelos para o website <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary website</a>.</p> + +<h2 id="Projetando_os_modelos_para_o_website_LocalLibrary">Projetando os modelos para o website <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a></h2> + +<p>Antes de começarmos a criar nossos modelos, vale a pena perder alguns minutos pensando sobre os dados que iremos guardar e as relações entre os diferentes modelos que serão criados.</p> + +<p>Sabemos que precisamos armazenar informação sobre os livros (título, resumo, autor, idioma, gênero, ISBN) e também que existem várias cópias do mesmo livro na biblioteca (com um id único, status de disponibilidade, etc.). Talvez queiramos armazenar mais informações sobre o autor além de somente seu nome, até porque existem vários autores com o mesmo nome, ou com nomes parecidos. Queremos ordernar a busca dos livros por título, autor, idioma e gênero.</p> + +<p>Quando estamos projetando nossos modelos, faz sentido criar modelos separados para cada "objeto". Em nosso caso de estudo, os "objetos" são os livros (a informação de cada livro, não a cópia em si), as cópias dos livros (um livro pode ter mais de uma cópia) e os autores.</p> + +<p>Você pode também utilizar modelos para representar opções em uma lista de seleção (por exemplo numa lista suspensa), o que é melhor do que trabalhar com opções predefinidas — isso é recomendado quando nem todas as opções são conhecidas ou podem mudar de acordo com um filtro. Obviamente, para nosso tutorial, modelos candidatos para esse caso são o gênero e o idioma.</p> + +<p>Após decidirmos nossos modelos e campos, precisamos pensar no relacionamento dessas informações. Django permite que você defina relações que são um pra um (<code>OneToOneField</code>), um pra muitos (<code>ForeignKey</code>) e muitos pra muitos (<code>ManyToManyField</code>).</p> + +<p>Com isso em mente, os diagramas UML de associação, mostram abaixo os modelos que definiremos nesse caso (como caixas).</p> + +<p><img alt="LocalLibrary Model UML" src="https://mdn.mozillademos.org/files/15646/local_library_model_uml.png" style="height: 660px; width: 977px;"></p> + +<p><span lang="pt">Como acima, criamos modelos para <code>Book </code>(que contém os detalhes genéricos do livro),<br> + <code>BookInstance</code> (contém os status das cópias físicas e específicas dos livros disponíveis no sistema) e <code>Author.</code> Também decidimos ter um modelo para o gênero (<code>Genre</code>), para que os valores possam ser criados/selecionados através da interface administrativa. Decidimos não ter um modelo para o <code>BookInstance: status</code> - pois, codificamos os valores em (<code>LOAN_STATUS</code>) porque não esperamos que isso mude. Dentro de cada uma das caixas você pode ver o nome do modelo, os campos nomes e tipos e também os métodos e seus tipos de retorno.</span></p> + +<p><span lang="pt">O diagrama também mostra as relações entre os modelos, incluindo suas multiplicidades. As multiplicidades são os números no diagrama que mostram as quantidades (máxima e mínima) que cada modelo pode estar presente nos relacionamentos. Por exemplo, a linha que conecta as caixas mostra que <code>Book</code> e um <code>Genre</code> estão relacionados. Os números próximos ao modelo <code>Genre</code> mostram que um livro deve ter um ou mais gêneros (ou quantos você quiser), enquanto os números do outro lado da linha, ao lado do modelo <code>Book</code> mostram que um gênero pode ter zero ou muitos livros associados.</span></p> + +<div class="note"> +<p><strong>Nota</strong>: A próxima seção fornece uma explicação básica sobre como os modelos são definidos e usados. Ao ler sobre isso, considere como vamos construir cada um dos modelos conforme o diagrama acima.</p> +</div> + +<h2 id="Model_primer">Model primer</h2> + +<p>Esta seção fornece uma breve visão sobre como um modelo é definido e alguns dos mais importantes campos e argumentos dos campos.</p> + +<h3 id="Definição_do_Modelo">Definição do Modelo</h3> + +<p>Modelos são geralmente definidos no arquivo <strong>models.py</strong> em uma aplicação. Eles são implementados como subclasse de <code>django.db.models.Model</code>, e podem incluir campos, métodos e metadados. O fragmento de código abaixo, mostra um modelo "típico", chamado <code>MyModelName</code>:</p> + +<pre class="notranslate">from django.db import models + +class MyModelName(models.Model): + """Uma típica classe definindo um modelo, derivada da classe Model.""" + + # Campos + my_field_name = models.CharField(max_length=20, help_text='Enter field documentation') + ... + + # Metadados + class Meta: + ordering = ['-my_field_name'] + + # Métodos + def get_absolute_url(self): + """Retorna a url para acessar uma instancia específica de MyModelName.""" + return reverse('model-detail-view', args=[str(self.id)]) + + def __str__(self): + """ String para representar o objeto MyModelName (no site Admin).""" + return self.my_field_name</pre> + +<p>Nas seções abaixa, exploraremos detalhadamente cada um dos recursos dentro do modelo:</p> + +<h4 id="Campos_Fields">Campos (Fields)</h4> + +<p>Um modelo pode ter um número árbitrário de campos, de qualquer tipo -- cada um representa uma coluna de dados que queremos armazenar em uma de nossas tabelas de banco de dados. Cada registro do banco de dados (row - linha) consitirá em um valor de cada campo. Vamos ver o exemplo visto acima:</p> + +<pre class="brush: js notranslate">my_field_name = models.CharField(max_length=20, help_text='Enter field documentation')</pre> + +<div class="tw-swapa"> +<div class="DHcWmd"><span lang="pt">Nosso exemplo acima tem um único campo chamado <code>my_field_name</code>, do tipo <code>models.CharField</code> - o que significa que este campo conterá strings de caracteres alfanuméricos. Os tipos de cada campo são atribuídos usando classes específicas, que determinam o tipo de registro usado para armazenar os dados no banco de dados, juntamente com os critérios de validação a serem usados quando os valores são recebidos de um formulário HTML (ou seja, o que constitui um valor válido). Os tipos de cada campo também podem receber argumentos que especifiquem como o campo é armazenado ou pode ser usado. Neste caso, estamos dando ao nosso campo dois argumentos:</span></div> + +<div class="DHcWmd"></div> +</div> + +<ul> + <li><code>max_length=20</code> — Afima que o valor máximo do comprimento desse campo é de 20 caracteres.</li> + <li><code>help_text='Enter field documentation'</code> — <span class="tlid-translation translation" lang="pt"><span title="">fornece um rótulo de texto para exibir uma ajuda para os usuários saberem qual valor fornecer, quando esse valor é inserido por um usuário por meio de um formulário HTML.</span></span></li> +</ul> + +<p><span class="tlid-translation translation" lang="pt"><span title="">O nome do campo é usado para se referir a ele em consultas e modelos.</span> <span title="">Os campos também têm um rótulo, que é especificado como um argumento <code>(verbose_name)</code> ou inferido ao capitalizar a primeira letra do nome da variável do campo e substituindo quaisquer sublinhados por um espaço (por exemplo,<code> my_field_name</code> teria um rótulo padrão de <code>My field name</code>).</span></span></p> + +<p><span class="tlid-translation translation" lang="pt"><span title="">A ordem em que os campos são declarados afetará sua ordem padrão, se um modelo for representado em um formulário (por exemplo, no site Admin), embora isso possa ser substituído.</span></span></p> + +<h5 id="Argumentos_comuns_de_um_campo">Argumentos comuns de um campo</h5> + +<p>Os seguintes argumentos são comuns e podem ser usados quando declaramos muitos ou a maioria dos diferentes tipos de campos:</p> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/models/fields/#help-text">help_text</a>: <span class="tlid-translation translation" lang="pt"><span title="">Fornece um rótulo de texto para formulários HTML (por exemplo, no site admin), conforme descrito acima.</span></span></li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/models/fields/#verbose-name">verbose_name</a>: <span class="tlid-translation translation" lang="pt"><span title="">Um nome legível para o campo usado nos rótulos de campo.</span> <span title="">Se não for especificado, o Django irá inferir o nome detalhado do campo <code>name</code>.</span></span></li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/models/fields/#default">default</a>: <span class="tlid-translation translation" lang="pt"><span title="">O valor padrão para o campo.</span> <span title="">Isso pode ser um valor ou um objeto que pode ser chamado. Cada vez que o objeto for chamado será criado um novo registro.</span></span></li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/models/fields/#null">null</a>: <span class="tlid-translation translation" lang="pt"><span title="">Se for <code>True</code>, o Django armazenará valores em branco como <code>NULL</code> no banco de dados, para campos onde isso é apropriado (um <code>CharField </code>irá armazenar uma string vazia).</span> <span title="">O padrão é <code>False</code></span></span>.</li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/models/fields/#blank">blank</a>:<span class="tlid-translation translation" lang="pt"><span title="">Se for <code>True</code>, o campo poderá ficar em branco nos seus formulários.</span> <span title="">O padrão é <code>False</code>, o que significa que a validação de formulário do Django forçará você a inserir um valor.</span> <span title="">Isso é frequentemente usado com <code>null = True</code>, porque se você permitir valores em branco, também desejará que o banco de dados possa representá-los adequadamente.</span></span></li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/models/fields/#choices">choices</a>: <span class="tlid-translation translation" lang="pt"><span title="">Um grupo de escolhas para este campo.</span> <span title="">Se isso for fornecido, o padrão widget de formulário correspondente será uma caixa de seleção com essas opções, em vez do campo de texto padrão.</span></span></li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/models/fields/#primary-key">primary_key</a>:<span class="tlid-translation translation" lang="pt"><span title="">Se <code>True,</code> define o campo atual como a chave primária do modelo (uma chave primária é uma coluna especial do banco de dados, designada para identificar exclusivamente as diferentes tabelas) .</span> <span title="">Se nenhum campo for especificado como a chave primária, o Django adicionará automaticamente um campo para essa finalidade.</span></span></li> +</ul> + +<p><span class="tlid-translation translation" lang="pt"><span title="">Existem muitas outras opções - você pode ver</span></span> <a href="https://docs.djangoproject.com/en/2.1/ref/models/fields/#field-options">a lista completa de opções aqui</a>.</p> + +<h5 id="Tipos_comuns_de_um_campo">Tipos comuns de um campo</h5> + +<p>A lista a seguir descreve alguns dos tipos de campos mais usados.</p> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/models/fields/#django.db.models.CharField">CharField</a> é usado para definir um tamanho fixo (médio a curto) para a string. Você deve especificar o <code>max_length (tamanho máximo) para o dado que será armazenado.</code></li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/models/fields/#django.db.models.TextField">TextField</a> é usado para grandes strings de comprimento variado. Você pode especificar um <code>max_length</code> (tamanho máximo) para o campo, mas isso é usado somente quando o campo é exibido em formulários (forms) (ele não é imposto no nível do banco de dados).</li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/models/fields/#django.db.models.IntegerField" title="django.db.models.IntegerField">IntegerField</a> é um campo para armazenar números inteiros e para validar valores inseridos como números inteiros em formulários.</li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/models/fields/#datefield">DateField</a> e <a href="https://docs.djangoproject.com/en/2.1/ref/models/fields/#datetimefield">DateTimeField</a> são usados para armazenar / representar datas e informações de data / hora (como os objetos Python <code>datetime.date</code> in e <code>datetime.datetime</code>, respectivamente). Esses campos também podem declarar os parâmetros (mutuamente exclusivos) <code>auto_now = True</code> (para definir o campo para a data atual toda vez que o modelo é salvo), <code>auto_now_add</code> (para definir a data em que o primeiro modelo foi criado) e <code>default</code> (para definir uma data padrão que pode ser substituída pelo usuário).</li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/models/fields/#emailfield">EmailField</a> é usada para armazenara e validar em endereço de email.</li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/models/fields/#filefield">FileField</a> e <a href="https://docs.djangoproject.com/en/2.1/ref/models/fields/#imagefield">ImageField</a> são usados para carregar arquivos e imagens respectivamente, (o <code>ImageField</code> simplesmente valida de forma adicional que o arquivo enviado é uma imagem). Eles têm parâmetros para definir como e onde os arquivos enviados são armazenados.</li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/models/fields/#autofield">AutoField</a> é um tipo especial de <code>IntegerField</code> que é incrementada automaticamente. Uma chave primária desse tipo é adicionada de forma automatica ao seu modelo, se você não especificar explicitamente um.</li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/models/fields/#foreignkey">ForeignKey</a> é usado para especificar um relacionamento um-para-muitos com outro modelo do banco de dados (por exemplo, um carro tem um fabricante, mas um fabricante pode fazer muitos carros). O lado "um" do relacionamento é o modelo que contém a "chave" (os modelos que contêm uma "chave estrangeira" referem-se a essa "chave" e estão no lado "muitos" de tal relacionamento).</li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/models/fields/#manytomanyfield">ManyToManyField</a> é usado para especificar um relacionamento muitos-para-muitos (por exemplo, um livro pode ter vários gêneros e cada gênero pode conter vários livros). Em nosso aplicativo de biblioteca, usaremos isso de maneira muito semelhante às <code>ForeignKeys</code>, mas elas podem ser usadas de maneiras mais complicadas para descrever as relações entre os grupos. Eles têm o parâmetro <code>on_delete</code> para definir o que acontece quando o registro associado é excluído (por exemplo, um valor de <code>models.SET_NULL</code> simplesmente definiria o valor como <code>NULL</code>).</li> +</ul> + +<p>Existem muitos outros tipos de campos, incluindo campos para diferentes tipos de números (big integers, small integers, floats), booleanos, URLs, slugs, unique ids e outras informações "relacionadas ao tempo" (duração, tempo, etc.) . Você pode ver a <a href="https://docs.djangoproject.com/en/2.1/ref/models/fields/#field-types">lista completa AQUI</a>.</p> + +<h4 id="Metadados_metadada">Metadados (metadada)</h4> + +<p>Você pode declarar o nível de modelo para os metadados declarando <code>class Meta</code>, como mostrado.</p> + +<pre class="brush: python notranslate">class Meta: + ordering = ['-my_field_name'] +</pre> + +<p>Um dos recursos mais úteis desses metadados é controlar a ordem padrão dos registros retornados, quando você consulta o tipo de modelo. Você faz isso especificando a ordem de correspondência em uma lista de nomes para ordenar (<code>ordering</code>) o atributo , conforme mostrado acima. A ordem dependerá do tipo de campo (os campos de caractere são classificados em ordem alfabética, enquanto os campos de data são classificados em ordem cronológica). Como mostrado acima, você pode prefixar o nome do campo com um símbolo de menos (-) para inverter a ordem de classificação.</p> + +<p>Então, como exemplo, se optássemos por ordenar livros como este por padrão:</p> + +<pre class="brush: python notranslate">ordering = ['title', '-pubdate']</pre> + +<p>Os livros seriam classificados em ordem alfabética por título, de A-Z e depois por data de publicação dentro de cada título, do mais recente ao mais antigo.</p> + +<p>Outro atributo comum é <code>verbose_name</code>, um nome detalhado para a classe no singular e plural:</p> + +<pre class="brush: python notranslate">verbose_name = 'BetterName'</pre> + +<p>Outros atributos úteis permitem que você crie e aplique novas "permissões de acesso" para o modelo (as permissões padrão são aplicadas automaticamente), permitem a ordenação com base em outro campo ou declarar que a classe é "abstrata" (uma classe base que você não pode criar registros, e em vez disso, serão derivadas para criar outros modelos).</p> + +<p>Muitas das outras opções de metadados controlam qual banco de dados deve ser usado para o modelo e como os dados são armazenados (eles são realmente úteis somente se você precisar mapear um modelo para um banco de dados existente).</p> + +<p>A lista completa de opções de metadados pode ser encontrada aqui: <a href="https://docs.djangoproject.com/en/2.1/ref/models/options/">Opções de modelos de metadados</a> (Django docs).</p> + +<h4 id="Métodos">Métodos</h4> + +<p>Um modelo também pode ter métodos.</p> + +<p><strong>Minimamente, em cada modelo você deve definir o método de classe padrão do Python <code>__str__()</code> para retornar uma string legível para cada objeto.</strong> Essa sequência é usada para representar registros individuais no site de administração (e em qualquer outro lugar que você precise se referir a uma instância de modelo). Muitas vezes isso retornará um campo de título ou nome do modelo.</p> + +<pre class="brush: python notranslate">def __str__(self): + return self.field_name</pre> + +<p>Outro método comum a incluir nos modelos do Django é o <code>get_absolute_url()</code>, que retorna uma URL para exibir registros de modelos individuais no site (se você definir esse método, o Django adicionará automaticamente um botão "View on Site" às telas de edição de registros do modelo o site Admin). Um padrão típico para <code>get_absolute_url ()</code> é mostrado abaixo.</p> + +<pre class="brush: python notranslate">def get_absolute_url(self): + """Retorna o URL para acessar uma instância específica do modelo.""" + return reverse('model-detail-view', args=[str(self.id)]) +</pre> + +<div class="note"> +<p><strong>Nota: </strong>Supondo que você usará URLs como <code>/ myapplication / mymodelname / 2</code> para exibir registros individuais para seu modelo (onde "2" é o <code>id</code> para um registro específico), você precisará criar um mapeador de URL para passar a resposta e id para uma "vista detalhada do modelo" (que fará o trabalho necessário para exibir o registro). A função <code>reverse ()</code> acima é capaz de "inverter" seu mapeador de url (no caso acima chamado 'model-detail-view') para criar uma URL do formato correto.</p> + +<p>Claro que para fazer este trabalho você ainda tem que escrever o mapeamento de URL, visão e modelo!</p> +</div> + +<p>Você também pode definir outros métodos que desejar e chamá-los de seu código ou modelos (desde que eles não utilizem nenhum parâmetro).</p> + +<h3 id="Gestão_de_modelos">Gestão de modelos</h3> + +<p>Depois de definir suas classes de modelo, você pode usá-las para criar, atualizar ou excluir registros e executar consultas para obter todos os registros ou subconjuntos específicos de registros. Mostraremos como fazer isso no tutorial quando definirmos nossas visualizações, mas aqui está um breve resumo.</p> + +<h4 id="Criando_e_modificando_registros">Criando e modificando registros</h4> + +<p>Para criar um registro, você pode definir uma instância do modelo e, em seguida, chamar <code>save ()</code>.</p> + +<pre class="brush: python notranslate"># Crie um novo registro usando o construtor do modelo. +record = MyModelName(my_field_name="Instance #1") + +# Salve o objeto no banco de dados. +record.save() +</pre> + +<div class="note"> +<p><strong>Nota:</strong> Se você não tiver declarado qualquer campo como primary_key, o novo registro receberá um automaticamente, com o ID do nome do campo. Você poderia consultar este campo depois de salvar o registro acima e ele teria um valor de 1.</p> +</div> + +<p>Você pode acessar os campos nesse novo registro usando a sintaxe de ponto e alterar os valores. Você precisa chamar <code>save ()</code> para armazenar valores modificados no banco de dados.</p> + +<pre class="brush: python notranslate"># Acessar valores de campo de modelo usando atributos do Python. +print(record.id) # should return 1 for the first record. +print(record.my_field_name) # should print 'Instance #1' + +# Altere o registro modificando os campos e, em seguida, chamando save (). +record.my_field_name = "New Instance Name" +record.save()</pre> + +<h4 id="Procurando_por_registros">Procurando por registros</h4> + +<p>Você pode procurar registros que correspondam a um determinado critério usando o atributo de objetos do modelo (fornecido pela classe base).</p> + +<div class="note"> +<p><strong>Nota: </strong>Explicar como procurar registros usando nomes de campos e modelos "abstratos" pode ser um pouco confuso. Na discussão abaixo, vamos nos referir a um modelo de livro com campos de título e gênero, onde o gênero também é um modelo com um único <code>nome</code> de campo.</p> +</div> + +<p>Podemos obter todos os registros para um modelo como um <code>QuerySet</code>, usando<code> objects.all ()</code>. O <code>QuerySet</code> é um objeto iterável, o que significa que ele contém um número de objetos que podemos iterar / percorrer.</p> + +<pre class="brush: python notranslate">all_books = Book.objects.all() +</pre> + +<p>O método <code>filter ()</code> do Django nos permite filtrar o <code>QuerySet</code> retornado para corresponder a um campo especificado de <strong>texto</strong> ou <strong>numérico</strong> em relação a um critério específico. Por exemplo, para filtrar por livros que contenham "wild" no título e, em seguida, contá-los, poderíamos fazer o seguinte.</p> + +<pre class="brush: python notranslate">wild_books = Book.objects.filter(title__contains='wild') +number_wild_books = Book.objects.filter(title__contains='wild').count() +</pre> + +<p>Os campos a serem correspondidos e o tipo de correspondência são definidos no nome do parâmetro de filtro, usando o formato: field_name__match_type (observe o sublinhado duplo entre título e contém acima). Acima, estamos filtrando o título com uma correspondência de maiúsculas e minúsculas. Existem muitos outros tipos de correspondência que você pode fazer: icontains (insensitivo a maiúsculas e minúsculas), iexact (correspondência exata que não diferencia maiúsculas e minúsculas), exata (correspondência exata diferencia maiúsculas de minúsculas), gt (maior que), startswith, etc. é <a href="https://docs.djangoproject.com/en/2.1/ref/models/querysets/#field-lookups">aqui</a>.</p> + +<p>Em alguns casos, você precisará filtrar um campo que defina um relacionamento um-para-muitos com outro modelo (por exemplo, uma <code>ForeignKey</code>). Nesse caso, você pode "indexar" campos no modelo relacionado com sublinhados duplos adicionais. Por exemplo, para filtrar livros com um padrão de gênero específico, você terá que indexar o <code>nome</code> por meio do campo de <code>gênero</code>, conforme mostrado abaixo:</p> + +<pre class="brush: python notranslate"># Combinará em: ficção, ficção científica, não-ficção etc. +books_containing_genre = Book.objects.filter(genre<strong>__</strong>name<strong>__</strong>icontains='fiction') +</pre> + +<div class="note"> +<p><strong>Nota:</strong> Você pode usar sublinhados (__) para navegar quantos níveis de relacionamentos (<code>ForeignKey / ManyToManyField</code>) desejar. Por exemplo, um <code>Livro</code> que tinha tipos diferentes, definidos usando um relacionamento "cover" adicional, pode ter um nome de parâmetro: <code>type__cover__name__exact = 'hard'</code>.</p> +</div> + +<p>Há muito mais que você pode fazer com as consultas, incluindo pesquisas para trás de modelos relacionados, encadeando filtros, retornando um conjunto menor de valores, etc. Para obter mais informações, consulte <a href="https://docs.djangoproject.com/en/2.1/topics/db/queries/">Fazendo consultas</a> (Django Docs).</p> + +<h2 id="Definindo_os_modelos_LocalLibrary">Definindo os modelos LocalLibrary</h2> + +<p>Nesta seção, começaremos a definir os modelos para a biblioteca. Abra models.py (em / locallibrary / catalog /). O código na parte superior da página importa o módulo de models, que contém os modelos da classe base do models. Modelo do qual nossos models herdarão.</p> + +<pre class="brush: python notranslate">from django.db import models + +# Create your models here.</pre> + +<h3 id="Genre_model">Genre model</h3> + +<p>Copie o código do model <code>Genre</code> , que aparece a baixo, e cole no seu arquivo <code>models.py</code> , abaixo do código de importação. Esse model guarda informaçoes sobre a categoria do livro — por exemplo se é ficção ou não ficção, romance ou história, etc. Como mencionado acima, criamos o genero como um model em vez de um campo de texto ou um lista de seleção para que os possíveis generos criados possam ser gerenciados pelo banco de dados, em vez de serem codificados.</p> + +<pre class="syntaxbox notranslate">class Genre(models.Model): + """Model representing a book genre.""" + name = models.CharField(max_length=200, help_text='Enter a book genre (e.g. Science Fiction)') + + def __str__(self): + """String for representing the Model object.""" + return self.name</pre> + +<p class="syntaxbox">O model tem apenas um campo do tipo <code>CharField</code> (<code>name</code>), que é usado para descrever o genero (esse campo é limitado a 200 caracteres e tem um <code>help_text</code>). No final da classe Genre declaramos o metodo <code>__str__()</code> que retorna o nome do genero definido por um registro especifico. Não foi definido um argumento <code>verbose_name</code> , assim o campo será referenciado como <code>Name</code> nos forms.</p> + +<h3 id="Book_model">Book model</h3> + +<p>Copie o model Book abaixo e cole novamente ao final do seu arquivo. O model Book representa todas as informações disponíveis sobre um livro de maneira geral, mas não incluí detalhes sobre o formato do encadernamento ou disponibilidade para empréstimo. O model usa um <code>CharField</code> para representar o <code>title</code> (tílutlo) do livro e o <code>isbn</code> (veja que o <code>isbn</code> recebe um rótulo como "ISBN", usando o primeiro parâmetro não nomeado, porque, de outra forma, o rótulo ficaria "Isbn"). O model usa <code>TextField</code> para o campo <code>summary</code> porque ele precisa ser um tanto longo.</p> + +<pre class="notranslate">from django.urls import reverse # Used to generate URLs by reversing the URL patterns + +class Book(models.Model): + """Model representing a book (but not a specific copy of a book).""" + title = models.CharField(max_length=200) + + # Foreign Key used because book can only have one author, but authors can have multiple books + # Author as a string rather than object because it hasn't been declared yet in the file + author = models.ForeignKey('Author', on_delete=models.SET_NULL, null=True) + + summary = models.TextField(max_length=1000, help_text='Enter a brief description of the book') + isbn = models.CharField('ISBN', max_length=13, help_text='13 Character <a href="https://www.isbn-international.org/content/what-isbn">ISBN number</a>') + + # ManyToManyField used because genre can contain many books. Books can cover many genres. + # Genre class has already been defined so we can specify the object above. + genre = models.ManyToManyField(Genre, help_text='Select a genre for this book') + + def __str__(self): + """String for representing the Model object.""" + return self.title + + def get_absolute_url(self): + """Returns the url to access a detail record for this book.""" + return reverse('book-detail', args=[str(self.id)])</pre> + +<p>Genre é um campo <code>ManyToManyField</code>, de forma que um livro pode ter múltiplos gêneros e um gênero pode ter muitos livros. O campor Author é declarado como um <code>ForeignKey</code>, logo, cada livro terá somente um autor, mas um autor por der muitos livros (na prática, um livro pode ter múltiplos autores, mas não nesta implementação!)</p> + +<p>Em ambos tipos de campo, a classe model relacionada é declarada como primeiro campo não nomeado usando a classe model ou contendo o nome do modelo relacionado. Você deve usar o nome do model como uma string se a classe associada ainda não tiver sido definida no arquivo, antes de referenciá-la. Outro parâmetro de interesse no campo <code>author</code> é <code>null=True</code>, o qual permite ao banco de dados armazer um valor <code>Null</code> se nenhum autor for selecionado, e, <code>on_delete=models.SET_NULL</code>, o qual definirá o valor <code>author</code> como <code>Null</code> se o registro do autor associado for excluído.</p> + +<p>O mode também defini <code>__str__()</code>, usando o <code>title</code> do livro para representar o registro do <code>Book</code>. O método final, <code>get_absolute_url()</code>, retorna a URL que pode ser usada para acessar o registro detalhado deste modelo (para que isto funcione, teremos que definir um mapa de URL com o nome <code>book-detail</code> e associá-la a uma view e a um template.).</p> + +<h3 id="BookInstance_model">BookInstance model</h3> + +<p>Em seguida, copie o modelo <code>BookInstance</code> (exibido a abaixo) depois dos outros modelos. O <code>BookInstance</code> representa um exemplar específico do livro que pode ser emprestado, indica se ela está disponível ou a data programada de restituição, "imprint" ou detalhes da versão, e, um id único do livro na biblioteca.</p> + +<p>Alguns dos campos e métodos serão familiares agora. O model usa</p> + +<ul> + <li><code>ForeignKey</code> para identificar o <code>Book</code> associado (cada livro pode ter muitos exemplares, porém uma cópia pode ter sometne um <code>Book</code>).</li> + <li><code>CharField</code> para representar o imprint (edição específica) do livro.</li> +</ul> + +<pre class="brush: python notranslate">import uuid # Required for unique book instances + +class BookInstance(models.Model): + """Model representing a specific copy of a book (i.e. that can be borrowed from the library).""" + id = models.UUIDField(primary_key=True, default=uuid.uuid4, help_text='Unique ID for this particular book across whole library') + book = models.ForeignKey('Book', on_delete=models.SET_NULL, null=True) + imprint = models.CharField(max_length=200) + due_back = models.DateField(null=True, blank=True) + + LOAN_STATUS = ( + ('m', 'Maintenance'), + ('o', 'On loan'), + ('a', 'Available'), + ('r', 'Reserved'), + ) + + status = models.CharField( + max_length=1, + choices=LOAN_STATUS, + blank=True, + default='m', + help_text='Book availability', + ) + + class Meta: + ordering = ['due_back'] + + def __str__(self): + """String for representing the Model object.""" + return f'{self.id} ({self.book.title})'</pre> + +<p>Nós declaramos adicionalmente alguns tipos novos de campos:</p> + +<ul> + <li><code>UUIDField</code> é usado no campo <code>id</code> para definí-lo como <code>primary_key</code> deste model. Este tipo de campo aloca um valor único global para cada instância (um para cada livro encontrado na biblioteca).</li> + <li><code>DateField</code> é usado para a data <code>due_back</code> (na qual o livro deve retonar e ficar disponível após um empréstimo ou uma manutenção). O valor pode ser <code>blank</code> ou <code>null</code> (para quando o livro estiver disponível). O model metadata (<code>Class Meta</code>) usa este campo para ordenar os registros quando eles são retornados em uma query.</li> + <li><code>status</code> é um <code>CharField</code> que define uma lista de opção/seleção. Como pode ser visto, nós definimos uma dupla contendo pares de valores-chave e a passamos no argumento da opção. O valor do par valor-chave é um valor que o usuário pode selecionar, enquanto que a chave é o valor que realmetne será salvo se a opção for selecionada. Nós também definimos um valor default como "m" (maintenance), uma vez que os livros serão inicialmente criados como indisponíveis até que eles sejam disponibilizados nas prateleiras.</li> +</ul> + +<p>O model <code>__str__()</code> representa o objeto <code>BookInstance</code> usando a combinação do seu id único e o título do <code>Book</code> associado.</p> + +<div class="note"> +<p><strong>Nota</strong>: Um pouco sobre Python:</p> + +<ul> + <li>Começando com Python 3.6, pode ser usada a sintaxe de interpolação (também conhecida como f-strings): <code>f'{self.id} ({self.book.title})'</code>.</li> + <li>Em versões anteriores deste tutorial, nós estávamos usando a sintaxe de <a href="https://www.python.org/dev/peps/pep-3101/">formatted string</a>, a qual também é uma maneira válida de formatar strings em Python (e.g. <code>'{0} ({1})'.format(self.id,self.book.title)</code>).</li> +</ul> +</div> + +<h3 id="Author_model">Author model</h3> + +<p>Copie o model <code>Author</code> (exibido abaixo) na sequência do código existente em <strong>models.py</strong>.</p> + +<p>Todos os campos/métodos já devem ser familiares agora. O model define um autor como tendo um nome, sobrenome, data de nascimento e data de morte (opcionalmente). Ele especifica que <code>__str__()</code> retorna por default sobrenome e nome, nesta ordem. O método <code>get_absolute_url()</code> reverte o mapaeamento da URL <code>author-detail</code> para obter a URL de display individual author.</p> + +<pre class="brush: python notranslate">class Author(models.Model): + """Model representing an author.""" + first_name = models.CharField(max_length=100) + last_name = models.CharField(max_length=100) + date_of_birth = models.DateField(null=True, blank=True) + date_of_death = models.DateField('Died', null=True, blank=True) + + class Meta: + ordering = ['last_name', 'first_name'] + + def get_absolute_url(self): + """Returns the url to access a particular author instance.""" + return reverse('author-detail', args=[str(self.id)]) + + def __str__(self): + """String for representing the Model object.""" + return f'{self.last_name}, {self.first_name}' + +</pre> + +<h2 id="Rode_novamente_a_migração_do_banco_de_dados">Rode novamente a migração do banco de dados</h2> + +<p>Todos os modelos foram criados. Agora rode a migração do banco de dados para adicioná-los ao seu banco de dados.</p> + +<pre class="notranslate"><code>python3 manage.py makemigrations +python3 manage.py migrate</code></pre> + +<h2 id="Language_model_—_desafio">Language model — desafio</h2> + +<p>Considere que um benfeitor local doe uma quantidade de livros escritos em outro idioma (digamos, Farsi). O desafio é desenvolver como eles seriam melhor representados no website da nossa biblioteca, e, então, adicioná-lo no models.</p> + +<p>Algumas coisas a considerar:</p> + +<ul> + <li>O idioma seria associado ao <code>Book</code>, <code>BookInstance</code>, ou algum outro objeto?</li> + <li>Os diferentes idiomas seriam representados usando model, como campo de texto livre ou codificado como uma lista de seleção?</li> +</ul> + +<p>Depois de decidido, adicione o campo. Pode ser visto o que decidimos no Github <a href="https://github.com/mdn/django-locallibrary-tutorial/blob/master/catalog/models.py">aqui</a>.</p> + +<ul> +</ul> + +<ul> +</ul> + +<h2 id="Resumo">Resumo</h2> + +<p>Neste artículo vimos como os models são definidos, e, então, usamos esta informação para desenhar e implementar modelos apropriados para o website <em>LocalLibrary</em>.</p> + +<p>Neste ponto faremos um rápido desvio da criação do site para ver o <em>Django Administration site</em>. Este site nos permitirá adicionar alguns dados à biblioteca, os quais podemos então exibir usando nossos próprios views e templates (ainda não criados).</p> + +<h2 id="Veja_também">Veja também</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.1/intro/tutorial02/">Escrevendo nossa primeira app Django, parte 2</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.1/topics/db/queries/">Fazendo queries</a> (Django Docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/models/querysets/">Referência a QuerySet API</a> (Django Docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django")}}</p> + +<h2 id="Neste_módulo">Neste módulo</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Introdução ao Django</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Configurando um ambiente de desenvolvimento Django</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django: Website de uma biblioteca local</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Tutorial Django Parte 2: Criando o escopo do website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial </a><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Parte 3: Utilizando models</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial </a><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Parte 4: Django admin site</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial </a><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Parte 5: Criando nossa página principal</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial </a><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Parte 6: Lista genérica e detail views</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial </a><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Parte 7: Framework de Sessões</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial </a><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Parte 8: Autenticação de Usuário e permissões</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial </a><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Parte 9: Trabalhando com formulários</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial </a><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Parte 10: Testando uma aplicação web Django</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial Django Parte 11: Implantando Django em produção</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Segurança de aplicações Django</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> diff --git a/files/pt-br/learn/server-side/django/sessões/index.html b/files/pt-br/learn/server-side/django/sessões/index.html new file mode 100644 index 0000000000..f2f16b521f --- /dev/null +++ b/files/pt-br/learn/server-side/django/sessões/index.html @@ -0,0 +1,205 @@ +--- +title: 'Tutorial Django Parte 7: Sessões' +slug: Learn/Server-side/Django/Sessões +tags: + - Artigo + - Iniciante + - Programação + - Python + - Script + - Servidor + - Tutorial + - aprenda + - django + - django português + - server-side + - sessões django +translation_of: Learn/Server-side/Django/Sessions +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django/authentication_and_sessions", "Learn/Server-side/Django")}}</div> + +<div>Esse tutorial estende nosso site <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a>, adicionando um contador de visitas baseado em sessões à página inicial. Esse é um exemplo relativamente simples, mas, capaz de mostrar como você pode usar a estrutura de sessão do framework para providenciar um comportamento persistente para usuários anônimos em seu próprio site.</div> + +<div></div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré-requisitos:</th> + <td>Completar todos os tópicos anteriores do tutorial, incluindo <a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></td> + </tr> + <tr> + <th scope="row">Objetivo:</th> + <td>Entender como as sessões são usadas.</td> + </tr> + </tbody> +</table> + +<h2 id="Visão_Geral">Visão Geral</h2> + +<p>O site <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> que criamos nos tutoriais anteriores permite que os usuarios busquem por livros e autores no catálogo. Enquanto o conteúdo é dinamicamente gerado a partir da base de dados, todos os usuários terão acessos às mesmas páginas e às mesmas informações quando acessarem o site.</p> + +<p><span class="tlid-translation translation"><span title="">Em uma biblioteca "real", você pode querer fornecer uma experiência personalizada para cada usuário, com base no uso anterior do site, nas preferências, etc. Por exemplo, você pode ocultar mensagens de aviso que o usuário reconheceu anteriormente na próxima visita deles ao</span> <span title="">site ou armazenar e respeitar suas preferências (por exemplo, o número de resultados de pesquisa que eles querem exibir em cada página).</span></span></p> + +<div class="text-wrap tlid-copy-target"> +<div class="result-shield-container tlid-copy-target"><span class="tlid-translation translation"><span title="">A estrutura da sessão permite implementar esse tipo de comportamento, permitindo que você armazene e recupere dados arbitrários baseados em cada visitante do site.</span></span></div> +</div> + +<h2 id="O_que_são_sessões">O que são sessões?</h2> + +<p>Toda a comunicação entre os navegadores web e os servidores é feita via protocolo HTTP, qual é <em>stateless</em> (sem estados). O fato do protocolo ser stateless significa que as mensagenns entre o cliente e o servidor são completamente independentes uma da outra — não há uma noção de "sequência" ou comportamento diferente baseado nas mensagens anteriores. <span class="tlid-translation translation"><span title="">Como resultado, se você quiser ter um site que monitore os relacionamentos contínuos com um cliente, é necessário implementá-lo por conta própria.</span></span></p> + +<p>Sessões são o mecanismo usado pelo Django (e muitos outros na Internet) para monitorar o "estado" entre o site e um navegador web em particular. Sessões permitem que você armazene dados arbitrários por navegador web, e têm esse dado disponível no site sempre que o navegador conectar. Dados de itens individuais associados com a sessão são referenciados por uma "chave", que é usada para armazenar e recuperar os dados.</p> + +<p>O Django usa um cookie contendo um <em>identificador</em> especial de sessão para identificar cada navegador e associar com o site. Os dados da sessão atual são armazenados na base de dados do site por padrão (é mais seguro do que armazenar os dados em cookie, onde é mais vulnerável aos usuários perigisos). Você pode configurar o Django para armazenar os dados da sessão em outros lugares (cache, arquivos, cookies "seguros"), mas o local padrão é uma opção boa e relativamente "segura".</p> + +<h2 id="Habilitando_as_Sessões">Habilitando as Sessões</h2> + +<p>As sessões foram ativadas automaticamente quando <a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">criamos o esqueleto do site</a> (no tutorial 2).</p> + +<p>A configuração e feita nas seções <code>INSTALLED_APPS</code> e <code>MIDDLEWARE</code> do arquivo (<strong>locallibrary/locallibrary/settings.py</strong>), exibidas a seguir:</p> + +<pre class="brush: python">INSTALLED_APPS = [ + ... +<strong> 'django.contrib.sessions',</strong> + .... + +MIDDLEWARE = [ + ... +<strong> 'django.contrib.sessions.middleware.SessionMiddleware',</strong> + ....</pre> + +<h2 id="Usando_Sessões">Usando Sessões</h2> + +<p>Você pode acessar o atributo <code>session</code> na view a partir do parâmetro <code>request</code> (um <code>HttpRequest</code> passado como primeiro argumento na view). Esse atributo de sessão representa a conexão atual específica com um usuário<span class="tlid-translation translation"><span title=""> (ou, para ser mais preciso, a conexão com o navegador atual, conforme identificado pelo id da sessão no cookie do navegador para este site)</span></span>.</p> + +<p>O atributo <code>session</code> é como um objeto dicionário que você pode ler e escrever quantas vezes você quiser na sua view, modificando-o como desejar. Você pode fazer todas as operações normais de um dicionário, incluindo limpar todos os dados, testar se uma chave está presente, loop em torno dos dados, etc. Na maior parte do tempo, você usará apenas a API padrão "dictionary" para obter e setar valores.</p> + +<p>O fragmento de código abaixo mostra como você pode obter, setar e deletar qualquer dado com com a chave "<code>my_car</code>", associada com a sessão atual (navegador).</p> + +<div class="note"> +<p><strong>Nota</strong>: Uma das coisas boas sobre o Django é que você não precisa pensar sobre os mecanismos que vinculam a sessão atual à requisição em sua view. Se nós usarmos os fragmentos abaixo em nossa view, saberemos que as informações sobre <code>my_car</code> estão associadas apenas com o navegador que enviou a requisição atual.</p> +</div> + +<pre class="brush: python"># Pega um valor de sessão baseado na sua chave (ex.:'my_car'), disparando um KeyError se a chave não for encontrada. +my_car = request.session['my_car'] + +# Pega o valor da sessão, seta o valor padrão ('mini') se a chave não estiver presente. +my_car = request.session.get('my_car', 'mini') + +# Seta o valor da sessão +request.session['my_car'] = 'mini' + +# Deleta o valor da sessão +del request.session['my_car'] +</pre> + +<p>A API também oferece um número de outros métodos que são muito usados para gerenciar a os cookies da sessão associada. Por exemplo, há metodos para testar se cookies são suportados no navegador do cliente, para setar e checar a data de validade do cookie, e para limpar sessões expiradas do armazenamento de dados. Você pode encontrar sobre a API completa em <a href="https://docs.djangoproject.com/en/2.1/topics/http/sessions/">How to use sessions</a> (documentação do Django).</p> + +<h2 id="Salvando_os_dados_da_sessão">Salvando os dados da sessão</h2> + +<p>Por padrão, o Django só salva na base de dados da sessão e envia o cookie da sessão para o cliente quando a sessão é <em>modificada </em>(atribuida) ou <em>deletada</em>. Se você está atualizando alguns dados utilizando sua chave de sessão, como mostrado na seção anterior, então você não precisa se preocupar com isso! Por exemplo:</p> + +<pre class="brush: python"># This is detected as an update to the session, so session data is saved. +request.session['my_car'] = 'mini'</pre> + +<p>Se você está atualizando algumas informações <em>dentro </em>dos dados da sessão, então o Django não reconhecerá que você fez uma alteração nos dados da sessão e não salvará os dados (por exemplo, se você alterasse os dados de "<code>wheels</code>" dentro dos dados do seu "<code>my_car</code>", como mostrado abaixo). Nesse caso você precisará marcar explicitamente a sessão como tendo sido modificada.</p> + +<pre class="brush: python"># Session object not directly modified, only data within the session. Session changes not saved! +request.session['my_car']['wheels'] = 'alloy' + +# Set session as modified to force data updates/cookie to be saved. +<code>request.session.modified = True</code> +</pre> + +<div class="note"> +<p><strong>Nota</strong>: Você pode mudar o comportamento do site para atualizar a base de dados/enviar cookie em qualquer requisição adicionando <code>SESSION_SAVE_EVERY_REQUEST = True</code> nas configurações (<strong>locallibrary/locallibrary/settings.py</strong>) do seu projeto.</p> +</div> + +<h2 id="Exemplo_simples_-_obtendo_a_contagem_de_visitas">Exemplo simples - obtendo a contagem de visitas</h2> + +<p>Como um exemplo simples do mundo real, atualizaremos nossa biblioteca para informar ao usuário atual quantas vezes ele visitou o site <em>LocalLibrary</em>. </p> + +<p>Abra <strong>/locallibrary/catalog/views.py</strong>, e faça as alterações mostradas em negrito abaixo.</p> + +<pre class="brush: python">def index(request): + ... + + num_authors = Author.objects.count() # The 'all()' is implied by default. + +<strong> # Number of visits to this view, as counted in the session variable. + num_visits = request.session.get('num_visits', 0) + request.session['num_visits'] = num_visits + 1</strong> + +<strong> context = { + 'num_books': num_books, + 'num_instances': num_instances, + 'num_instances_available': num_instances_available, + 'num_authors': num_authors, + 'num_visits': num_visits, + }</strong> + + # Render the HTML template index.html with the data in the context variable. + return render(request, 'index.html', context=context)</pre> + +<p>Aqui primeiro obtemos o valor da <em>session key</em> <code>'num_visits'</code>, setando o valor para 0 se não tiver sido definido anteiormente. Cada vez que uma requisição é recebida, nós então incrementamos o valor e armazenamos novamente na sessão (para a próxima vez que o usuário visitar a página). A variável <code>num_visits</code> é então passada para o <em>template</em> na nossa varável <em>context</em>.</p> + +<div class="note"> +<p><strong>Nota</strong>: Também podemos testar se os cookies são suportados no navegador (veja <a href="https://docs.djangoproject.com/en/2.1/topics/http/sessions/">Como usar sessões</a> para exemplos) ou projetar nossa UI (interface do usuário) para que não se importe se os <em>cookies</em> são ou não suportados.</p> +</div> + +<p>Adicione a linha vista na parte inferior do bloco a seguir ao seu <em>template</em> HTML principal (<strong>/locallibrary/catalog/templates/index.html</strong>) na parte inferior da sessão <em>"Dynamic content"</em>, para exibir a variável <em>context</em>:</p> + +<pre class="brush: html"><h2>Dynamic content</h2> + +<p>The library has the following record counts:</p> +<ul> + <li><strong>Books:</strong> \{{ num_books }}</li> + <li><strong>Copies:</strong> \{{ num_instances }}</li> + <li><strong>Copies available:</strong> \{{ num_instances_available }}</li> + <li><strong>Authors:</strong> \{{ num_authors }}</li> +</ul> + +<strong><p>You have visited this page \{{ num_visits }}{% if num_visits == 1 %} time{% else %} times{% endif %}.</p></strong> +</pre> + +<p>Salve suas alterações e reinicie o servidor de teste. Sempre que você atualiza a página, o número deve ser atualizado.</p> + +<ul> +</ul> + +<h2 id="Resumo">Resumo</h2> + +<p>Agora você sabe como é fácil utilizar sessões para melhorar sua interação com usuários anônimos. </p> + +<p>Em nosso próximo artigo nós iremos explicar a estrutura de autenticação e autorização (permissão), e mostrar como oferecer suporte a contas de usuário.</p> + +<h2 id="Veja_também">Veja também</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.1/topics/http/sessions/">Como usar sessões</a> (Django docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django/Authentication", "Learn/Server-side/Django")}}</p> + +<h2 id="Neste_módulo">Neste módulo</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Introdução ao Django</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Configurando um ambiente de desenvolvimento Django</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django: </a><a rel="nofollow" title="A página ainda não foi criada.">Website de uma Biblioteca Local</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial</a> <a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Parte 2: </a><a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/skeleton_website">Criando a base do website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial</a> <a href="/en-US/docs/Learn/Server-side/Django/Models">Django Parte 3: Usando <em>models</em></a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial</a> <a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Parte 4: Django admin site</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial</a> <a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Parte 5: Criando nossa página principal</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial</a> <a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Parte 6: </a><a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/Generic_views">Lista genérica e <em>detail views</em></a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial</a> <a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Parte 7: </a><a rel="nofollow" title="A página ainda não foi criada.">Framework de Sessões</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial</a> <a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Parte 8: </a><a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/Authentication">Autenticação de Usuário e permissões</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial</a> <a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Parte 9: </a><a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/Forms">Trabalhando com formulários</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial</a> <a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Parte 10: </a><a rel="nofollow" title="A página ainda não foi criada.">Testando uma aplicação web Django</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial</a> <a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Parte 11: </a><a rel="nofollow" title="A página ainda não foi criada.">Implantando Django em produção</a></li> + <li><a rel="nofollow" title="A página ainda não foi criada.">Segurança de aplicações web Django</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> diff --git a/files/pt-br/learn/server-side/django/skeleton_website/index.html b/files/pt-br/learn/server-side/django/skeleton_website/index.html new file mode 100644 index 0000000000..5a453131b2 --- /dev/null +++ b/files/pt-br/learn/server-side/django/skeleton_website/index.html @@ -0,0 +1,393 @@ +--- +title: 'Django Tutorial Parte 2: Criando o "esqueleto" de um site' +slug: Learn/Server-side/Django/skeleton_website +tags: + - Artigo + - Guía + - Iniciante + - Python + - locallibrary +translation_of: Learn/Server-side/Django/skeleton_website +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django/Models", "Learn/Server-side/Django")}}</div> + +<p class="summary">O segundo artigo do tutorial de Django mostra uma forma de criar o "esqueleto" de um website, permitindo que você possa ampliá-lo com caracteristicas especificas do site, caminhos (patchs), modelos (models), visualizações (views) e templates. </p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré-requisitos:</th> + <td><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Configurar um ambiente de desenvolvimento Django</a>. Ter lido <a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django: Website de uma Biblioteca Local</a>.</td> + </tr> + <tr> + <th scope="row">Objetivo:</th> + <td>Ser capaz de usar as ferramentas do Django para começar seus próprios novos projetos de websites.</td> + </tr> + </tbody> +</table> + +<h2 id="Visão_Geral">Visão Geral</h2> + +<p>Este artigo mostra como você pode criar o escopo de um website, permitindo popul-a-lo com características específicas do seu site, tais como configurações, paths, modelos, views e templates (nós os discutiremos em artigos que seguem à frente).</p> + +<p>O processo é direto:</p> + +<ol> + <li><span style="line-height: 1.5;">Use a ferramenta </span><code style="font-style: normal; font-weight: normal; line-height: 1.5;">django-admin</code><span style="line-height: 1.5;"> para criar a pasta do projeto, arquivos de template básicos, e o script de gestão do projeto (</span><strong style="line-height: 1.5;">manage.py</strong><span style="line-height: 1.5;">).</span></li> + <li><span style="line-height: 1.5;">Use o script </span><strong style="line-height: 1.5;">manage.py</strong><span style="line-height: 1.5;"> para criar um ou mais <em>aplicativos</em>.</span> + <div class="note"> + <p><strong>Nota</strong>: Um website pode consistir de uma ou mais áreas, como por exemplo, site, blog, wiki, área de download, etc. Django te encoraja a desenvolver esses componentes como aplicativos separados, que podem então ser reutilizados em diferentes projetos, caso seja necessário.</p> + </div> + </li> + <li><span style="line-height: 1.5;">Registre os novos aplicativos para inclui-los no projeto. </span></li> + <li><span style="line-height: 1.5;">Conecte o mapeador de url/path para cada aplicativo.</span></li> +</ol> + +<p>Para o <a href="/pt-BR/docs/Learn/Server-side/Django/Tutorial_local_library_website">website Biblioteca Local</a> a pasta do website e a pasta do projeto terão, ambas, o nome <em>locallibrary</em>, e nós teremos apenas um aplicativo chamado <em>catalog</em>. O nível hierárquico mais alto da estrutura de pastas ficará assim:</p> + +<pre class="brush: bash notranslate"><em>locallibrary/ # Pasta do website</em> + <strong>manage.py </strong> # Script para executara as ferramentas do Django para este projeto (criado utilizando o django-admin) + <em>locallibrary/ # Pasta do project folder </em>(criado utilizando o django-admin) + <em>catalog/ # Pasta do aplicativo </em>(criado utilizando o django-admin) +</pre> + +<p><span style="line-height: 1.5;">As próximas seções discutem esse processo em detalhes e mostram como você pode testar as mudanças. No final do artigo nós discutiremos algumas das outras configurações do site como um todo, você também pode fazer isso.</span></p> + +<h2 id="Criando_o_projeto">Criando o projeto</h2> + +<p>Primeiro abra o prompt de comando/terminal t(enha certeza que está em seu <a href="/pt-BR/docs/Learn/Server-side/Django/ambiente_de_desenvolvimento">ambiente virtual)</a>, navegue até o diretório que deseja colocar seus aplicativos Django (coloque em um lugar fácil de achar, como dentro da pasta <em>documentos</em>), e crie uma pasta para seu novo website (nesse caso: <em>django_projects</em>). Acesse então a pasta usando o comando cd:</p> + +<pre class="brush: bash notranslate">mkdir locallibrary +cd locallibrary</pre> + +<p>Crie um novo projeto usando o comando <code>django-admin startproject</code>, como mostrado abaixo, e entre nessa pasta.</p> + +<pre class="brush: bash notranslate">django-admin startproject locallibrary +cd locallibrary</pre> + +<p>O comando <code>django-admin</code> cria uma estrutura com pastas e arquivos como a mostrada abaixo:</p> + +<pre class="brush: bash notranslate"><em>locallibrary/</em> + manage.py + <em>locallibrary/</em> + __init__.py + settings.py + urls.py + wsgi.py</pre> + +<p>Nosso diretório de trabalho atual deve parecer com isso:</p> + +<pre class="syntaxbox notranslate">../django_projects/locallibrary/</pre> + +<p> A sub-pasta do projeto <em>locallibrary</em> será a raíz para nosso site:</p> + +<ul> + <li><strong>__init__.py </strong>é um arquivo em branco que instrui o Python a tratar esse diretório como um pacote Python.</li> + <li><strong>settings.py</strong> contém todas as definições do website. É onde nós registramos qualquer aplicação que criarmos, a localização de nossos arquivos estáticos, configurações de banco de dados etc. </li> + <li><strong>urls.py</strong> define os mapeamentos de URL para visualização do site<span style="line-height: 1.5;">. Mesmo que esse</span> arquivo possa conter <em>todo </em>o código para mapeamento de URL, é mais comum delegar apenas o mapeamento para aplicativos específicos, como será visto mais adiante.</li> + <li><strong style="line-height: 1.5;">wsgi.py</strong><span style="line-height: 1.5;"> é usado para ajudar na comunicação entre seu aplicativo Django e o web server. Você pode tratar isso como um boilerplate.</span></li> +</ul> + +<p>O script <strong>manage.py</strong> é usado para criar aplicações, trabalhar com bancos de dados, e iniciar o webserver de desenvolvimento. </p> + +<h2 id="Criando_o_aplicativo_de_catálogo">Criando o aplicativo de catálogo</h2> + +<p>Agora execute o seguinte comando para criar o <em>catálogo</em> da aplicação que fará parte de nosso projeto localibrary (o comando deve ser executado na mesma pasta que está o <strong>manage.py</strong> do seu projeto):</p> + +<pre class="brush: bash notranslate">python3 manage.py startapp catalog</pre> + +<div class="note"> +<p><strong>Nota</strong>: O comando acima é para Linux/macOS X. No windows o comando deve ser: <code>py -3 manage.py startapp catalog</code></p> + +<p>Se você está trabalhando com o Windows, substitua <code>python3</code> por <code>py -3</code> ao longo deste módulo.</p> + +<p>Se você está usando Python 3.7.0, use <code>py manage.py startapp catalog</code></p> +</div> + +<p>A ferramenta cria uma nova pasta e adiciona alguns arquivos para diferentes partes da aplicação (destacado em negrito abaixo). A maior parte dos arquivos é armazenada de acordo com seu propósito (e.g. views devem ser armazenadas em <strong>views.py</strong>, models em <strong>models.py</strong>, testes em <strong>tests.py</strong>, configurações de administração do site em <strong>admin.py</strong>, registro da aplicação em <strong>apps.py</strong>) e contém algum código mínimo para trabalhar com os objetos associados.</p> + +<p>O diretório do projeto atualizado deve parecer com esse:</p> + +<pre class="brush: bash notranslate"><em>locallibrary/</em> + manage.py + <em>locallibrary/ +</em><strong> <em>catalog/</em> + admin.py + apps.py + models.py + tests.py + views.py + __init__.py + <em>migrations/</em></strong> +</pre> + +<p>Além disso, nós temos:</p> + +<ul> + <li>Uma pasta <em>migrations</em>, usada para guardar "<em>migrações</em>" — arquivos que permitem atualizar automaticamente seu banco de dados à medida que você modifica seus models. </li> + <li><strong>__init__.py</strong> — Um arquivo em branco criado de modo que Django/Python reconheça a pasta como um <a href="https://docs.python.org/3/tutorial/modules.html#packages">Python Package</a> e permita que você use seus objetos dentro de outras partes do projeto.</li> +</ul> + +<div class="note"> +<p><strong>Nota</strong>: Você notou o que falta na lista de arquivos acima? Apesar de existir um lugar para suas views e seus models, não há nenhum lugar para colocar seus mapeamentos de URL, templates ou arquivos estáticos. Nós iremos te ensinar como criá-los mais adiante (isso não é necessário em todos websites, mas precisarem em nosso exemplo).</p> +</div> + +<h2 id="Registrando_o_aplicativo_de_catálogo">Registrando o aplicativo de catálogo</h2> + +<p>Agora que a aplicação foi criada, iremos registrá-la com o projeto para que ela seja incluída quando qualquer ferramenta for executada (por exemplo para adicionar models para o banco de dados). Aplicações são registradas adicionando-as à lista <code>INSTALLED_APPS</code> que fica nas configurações do projeto.</p> + +<p>Abra o arquivo de configurações do projeto <strong>locallibrary/locallibrary/settings.py</strong> e encontre a definição para a lista <code>INSTALLED_APPS</code>. Agora adicione uma nova linha no fim da lista, como a mostrada em negrito abaixo.</p> + +<pre class="brush: bash notranslate">INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', +<strong> 'catalog.apps.CatalogConfig', </strong> +]</pre> + +<p>A nova linha especifica o objeto de configuração do aplicativo (<code>CatalogConfig</code>) que foi gerado em <strong>/locallibrary/catalog/apps.py</strong> onde a aplicação foi criada.</p> + +<div class="note"> +<p><strong>Nota</strong>: Você deve ter notado que existem vários outros <code>INSTALLED_APPS</code> (e <code>MIDDLEWARE</code>, pelo final do arquivo de configuração). Eles permitem suporte para o <a href="/en-US/docs/Learn/Server-side/Django/Admin_site">site de administração do Django</a> e, como resultado, várias funcionalidades que ele utiliza (incluindo seções, autenticação etc).</p> +</div> + +<h2 id="Especificando_o_Banco_de_Dados">Especificando o Banco de Dados</h2> + +<p>Tipicamente, esse é o momento em que você também especifica o banco de dados que será usado no projeto— faz mais sentido usar o mesmo banco de dados tanto para desenvolvimento quanto para a produção (quando possível), a fim de evitar pequenas diferenças de comportamento. Você pode encontrar mais sobre as outras opções em <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#databases">Databases</a> (Documentação Django).</p> + +<p>Usaremos o banco de dados SQLite para este exemplo porque não esperamos ter muito acesso simultâneo em um banco de dados para demonstração, e também porque ele não requer trabalho adicional de configuração! Você pode ver como o banco de dados é configurado em <strong>settings.py</strong> (mais informações estão incluidas abaixo).</p> + +<pre class="brush: python notranslate">DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + } +} +</pre> + +<p>Já que nós estamos usando SQLite, nós não precisamos de nenhum outro passo aqui. Vamos ir em frente!</p> + +<h2 id="Outras_configurações_do_projeto">Outras configurações do projeto</h2> + +<p>O arquivo <strong>settings.py</strong> também é usado para configurar várias outras definições, mas por ora você provavelmente quer mudar apenas a <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-TIME_ZONE">TIME_ZONE</a> — deve se utilizar uma string padrão da <a href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones">Lista de tz time zones</a> (a coluna TZ na tabela contém os valores que você precisa). Mude seu valor de <code>TIME_ZONE</code> para uma string relativa ao seu fuso-horário, por exemplo:</p> + +<pre class="brush: python notranslate">TIME_ZONE = 'America/Sao_Paulo'</pre> + +<p>Tem outras duas definições que você não vai mudar agora, mas que deve ficar ciente:</p> + +<ul> + <li><code>SECRET_KEY</code>. É uma chave secreta que é usada como parte da estratégia de segurança dos websites Django. Se você não está protegendo seu código durante o desenvolvimento, você precisará usar um código diferente (que talvez seja lido de uma variável de ambiente ou arquivo) quando colocar no ambiente de produção.</li> + <li><code>DEBUG</code>. Isto habilita a depuração de logs sejam exibidos em um erro ao invés de respostas de status de código HTTP. Isso deve ser definido como <code>False</code> na produção, já que informações de debug são úteis para invasores, mas por enquanto nós manteremos <code>True.</code></li> +</ul> + +<h2 id="Conectando_o_mapeador_de_URL">Conectando o mapeador de URL</h2> + +<p>O website foi criado com um arquivo mapeador de URL (<strong>urls.py</strong>) na pasta do projeto. Embora você possa usar esse arquivo para gerenciar todos seus mapeamentos de URL, é mais comum fazer os mapeamentos diretamente no aplicativo associado.</p> + +<p>Abra <strong>locallibrary/locallibrary/urls.py</strong> e leia o texto que explica alguma formas de usar o mapeador de URL.</p> + +<pre class="brush: python notranslate">"""locallibrary URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/2.0/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path + +urlpatterns = [ + path('admin/', admin.site.urls), +] +</pre> + +<p>Os mapeamentos de URL são gerenciados através da variável <code>urlpatterns</code> que é uma lista Python de funções <code>path()</code>. Cada função <code>path()</code> associa um padrão de URL para uma <em>view específica</em>, que será exibida quando o padrão for correspondido, ou com outra lista de testes de padrões de URL (no segundo caso, o padrão vem da "URL base" para padrões definidos no módulo target). A lista <code>urlpatterns</code> define inicialmente uma função única que mapeia todas URLs com o padrão admin para o módulo <code>admin.site.urls</code>, que contém as próprias definições de mapeamento de URL da área de administração do aplicativo.</p> + +<div class="note"> +<p><strong>Nota:</strong> A rota em <code>path()</code> é uma string que define um padrão de URL para correspondência. Essa string pode incluir um nome de variável (entre tags), e.g. <code>'catalog/<id>/'</code>. Esse padrão corresponderá a uma URL como <strong>/catalog/</strong><em>any_chars</em><strong>/</strong> e passa <em>any_chars</em> para a view como uma string com paramêtros nome <code>id</code>). Nós discutiremos métodos de caminho e padrões de rota ainda mais em tópicos posteriores</p> +</div> + +<p>Adicione as linhas abaixo no fim do arquivo a fim de adicionar um novo item à lista <code>urlpatterns</code>. Esse novo item inclui um <code>path()</code> que encaminha solicitações com o padrão <code>catalog/</code> para o módulo <code>catalog.urls</code> (o arquivo com a URL relativa <strong>/catalog/urls.py</strong>). </p> + +<pre class="brush: python notranslate"># Use include() to add paths from the catalog application +from django.conf.urls import include +from django.urls import path + +urlpatterns += [ + path('catalog/', include('catalog.urls')), +] +</pre> + +<p>Agora iremos mudar a URL raíz de nosso site (i.e. <code>127.0.0.1:8000</code>) para <code>127.0.0.1:8000/catalog/</code>; pois esse é o único app que iremos usar neste projeto. Para isso, usaremos uma função view especial (<code>RedirectView</code>), que leva como primeiro argumento a nova URL relativa para redirecionar para <code>/catalog/</code> quando o padrão URL especificado na função <code>path()</code> for chamado (a URL raíz nesse caso).</p> + +<p>Adicione as linhas abaixo, novamente no fim do arquivo:</p> + +<pre class="brush: python notranslate">#Add URL maps to redirect the base URL to our application +from django.views.generic import RedirectView +urlpatterns += [ + path('', RedirectView.as_view(url='/catalog/')), +]</pre> + +<p>Deixe o primeiro parâmetro da função path vazio, implicando em '/'. Se você escrever o primeiro parâmetro como '/', Django irá te mostar o seguinte aviso assim que iniciar o servidor de desenvolvimento.</p> + +<pre class="brush: python notranslate">System check identified some issues: + +WARNINGS: +?: (urls.W002) Your URL pattern '/' has a route beginning with a '/'. +Remove this slash as it is unnecessary. +If this pattern is targeted in an include(), ensure the include() pattern has a trailing '/'. +</pre> + +<p>Por padrão, Django não "serve" arquivos estáticos como CSS, JavaScript e imagens, mas ele pode ser útil para o servidor web de desenvolvimento enquanto você cria seu site. Como comentário final sobre o mapeador de URL, você pode habilitar a veiculação de arquivos estáticos durante o desenvolvimento adicionando as seguintes linhas.</p> + +<p>Coloque o seguinte bloco no fim do arquivo:</p> + +<pre class="notranslate"><code># Use static() to add url mapping to serve static files during development (only) +from django.conf import settings +from django.conf.urls.static import static + +urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)</code> +</pre> + +<div class="note"> +<p><strong>Nota</strong>: Existem várias maneiras de estender a lista <code>urlpatterns</code> (acima nós acrecentamos uma nova lista de itens usando o operador <code>+=</code> para separar claramente o velho do novo código). Poderiamos ter apenas incluído esse novo padrão de mapeamento na definição da lista original.</p> + +<pre class="brush: python notranslate">urlpatterns = [ + path('admin/', admin.site.urls), + path('catalog/', include('catalog.urls')), + path('', RedirectView.as_view(url='/catalog/', permanent=True)), +] + <code>static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)</code> +</pre> + +<p>Além disso, incluimos a linha para importação (<code>from django.urls import include</code>) com o código que usa-o (que facilita ver o que nós adicionamos), porém, é mais comum incluir todas as linhas de import no topo do arquivo Python.</p> +</div> + +<p>Finalmente, crie um arquivo dentro da pasta catalog e dê o nome <strong>urls.py</strong>, adicione então o seguinte texto para definir um <code>urlpatterns</code> importado (e vazio). É aqui onde você adicionará nossos padrões enquanto desenvolvemos o aplicativo.</p> + +<pre class="brush: python notranslate">from django.urls import path +from catalog import views + + +urlpatterns = [ + +] +</pre> + +<h2 id="Testando_o_framework_do_site">Testando o framework do site</h2> + +<p>Você acabou de criar o escopo do site. Por enquanto o site ainda não faz nada, mas vale a pena testá-lo para garantir que nenhuma de nossas mudanças tenha criado algum problema.</p> + +<p>Antes de começarmos, devemos primeiramente executar uma <em>migração de banco de dados</em>. Isso atualiza nosso banco de dados para incluir qualquer model em nossas aplicações instaladas (e remove avisos da build).</p> + +<h3 id="Migrando_Bancos_de_Dados">Migrando Bancos de Dados</h3> + +<p>Django usa um Object-Relational-Mapper (ORM) que mapeia as definições de Model no código Django para a estrutura do banco de dados subjacente. Como mudamos nossas definições de model, Django localiza as mudanças e cria scripts para migração de banco de dados (em<strong> /locallibrary/catalog/migrations/</strong>) para migrar automaticamente a estrutura de dados subjacente no banco de dados para manter a correnpondência com o model.</p> + +<p>Quando criamos nosso website, Django adicionou automaticamente um número de models para serem usados na área admin do site (que nós veremos depois). Execute os comandos abaixo para definir as tabelas para aqueles models no banco de dados (verifique se você está no diretório que contém o arquivo <strong>manage.py</strong>):</p> + +<pre class="brush: bash notranslate">python3 manage.py makemigrations +python3 manage.py migrate +</pre> + +<div class="warning"> +<p><strong>Importante</strong>: Você precisará executar os comandos acima sempre que alterar seus models de uma forma que afete a estrutura de dados que precisa ser armazenada (incluindo adição e remoção de todos models e campos individuais).</p> +</div> + +<p>O comando <code>makemigrations</code> <em>cria</em> (mas não aplica) as migrações para todos aplicativos instalados em seu projeto (você pode especificar o nome do aplicativo para executar apenas uma migração para um único projeto). Isso te permite checar o código para essas migrações antes delas serem aplicadas — quando você é experiente em Django, você pode escolher ajustá-los um pouco!</p> + +<p>O comando <code>migrate</code> aplica as migrações em seu banco de dados (Django rastreia quais foram adicionados ao banco de dados atual).</p> + +<div class="note"> +<p><strong>Nota</strong>: Leia <a href="https://docs.djangoproject.com/en/2.0/topics/migrations/">Migrations</a> (Documentação Django) para informações adicionais sobre os comandos de migração menos usados.</p> +</div> + +<h3 id="Testando_o_website">Testando o website</h3> + +<p>Durante o desenvolvimento você pode testar o website usando o <em>webserver de desenvolvimento</em>, e vê-lo em seu navegador local.</p> + +<div class="note"> +<p><strong>Nota</strong>: O web server de desenvolvimento não tem performance ou desempenho suficiente para uso em produção, mas é uma maneira bem fácil de atualizar seu website Django e utilizá-lo durante o desenvolvimento para conseguir um teste rápido e conveniente. Por padrão, o site é "hospedado" em seu computador local (<code>http://127.0.0.1:8000/)</code>, mas você também pode especificar que outros computadores da rede acessem-o. Para mais informações acesse <a href="https://docs.djangoproject.com/en/2.0/ref/django-admin/#runserver">django-admin and manage.py: runserver</a> (Documentação Django).</p> +</div> + +<p>Execute o <em>web server de desenvolvimento</em> com o comando <code>runserver</code> (no mesmo diretório de <strong>manage.py</strong>):</p> + +<pre class="brush: bash notranslate">python3 manage.py runserver + + Performing system checks... + + System check identified no issues (0 silenced). + August 15, 2018 - 16:11:26 + Django version 2.1, using settings 'locallibrary.settings' + Starting development server at http://127.0.0.1:8000/ + Quit the server with CTRL-BREAK. +</pre> + +<p>Com o servidor funcionando, você pode ver seu site colocando o endereço <code>http://127.0.0.1:8000/</code> em seu navegador local. Você deve ver uma página de erro como essa:</p> + +<p><img alt="Django Debug page for Django 2.0" src="https://mdn.mozillademos.org/files/15729/django_404_debug_page.png"></p> + +<p>Não se assuste! Essa página de erro é esperada, pois nós não temos nehuma página ou url definida no módulo <code>catalogs.urls</code> (que é para onde somos redirecionados quando usamos a URL para a raíz do site).</p> + +<div class="note"> +<p><strong>Nota</strong>: A página acima demontra um ótimo recurso do Django — o log de depuração automatizado. Uma tela de erro será exibida com informações referentes ao erro sempre que uma página não consiga ser encontrada, ou caso o código tenha algum erro. Nesse caso poderemos ver que a URL que nós fornecemos não corresponde a nenhum de nossos padrões de URL (como listado). O log será desativado durante a produção (quando colocamos nosso site online na WEB), nesse caso uma página menos informativa (porém, mais amigável ao usuário) será exibida.</p> +</div> + +<p>No momento basta saber que o Django está funcionando! </p> + +<div class="note"> +<p><strong>Nota</strong>: Você deve executar novamente as migrações e testar o site sempre que fizer alguma mudança signifcante. Não demora muito!</p> +</div> + +<h2 id="Desafio">Desafio</h2> + +<p>O diretório <strong>catalog/</strong> contém arquivos para views, models, e outras partes da aplicação. Abra esses arquivos e inspecione o bolierplate (códigos incluídos em muitos lugares com pouca ou nenhuma alteração). </p> + +<p>Como você viu acima, um mapeamento de URL para o site Admin já foi adicionado no arquivo <strong>urls.py</strong> do projeto. Vá à área do admin em seu navegador e veja o que acontece (você pode deduzir a URL correta para o mapeamento acima).</p> + +<h2 id="Sumário">Sumário</h2> + +<p>Você acabou de criar um "esqueleto" para websties, agora você pode popular o site com URL's, models, views e templates.</p> + +<p>Como o escopo para o <a href="/pt-BR/docs/Learn/Server-side/Django/Tutorial_local_library_website">website Local Library</a> está completo e executando, é hora de começar a escrever códigos que farão o website realizar sua função.</p> + +<h2 id="Veja_também">Veja também</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.0/intro/tutorial01/">Codificando seu primeiro app Django - parte 1</a> (Documentação Django)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/applications/#configuring-applications">Aplicativos</a> (Documentação Django). Contém informações de como configurar aplicativos.</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django/Models", "Learn/Server-side/Django")}}</p> + +<h2 id="Neste_módulo">Neste módulo</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Introdução ao Django</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Configurando um ambiente de desenvolvimento Django</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django: Website de uma biblioteca local</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Tutorial Django Parte 2: Criando o escopo do website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial </a><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Parte 3: Utilizando models</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial </a><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Parte 4: Django admin site</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial </a><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Parte 5: Criando nossa página principal</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial </a><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Parte 6: Lista genérica e detail views</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial </a><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Parte 7: Framework de Sessões</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial </a><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Parte 8: Autenticação de Usuário e permissões</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial </a><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Parte 9: Trabalhando com formulários</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial </a><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Parte 10: Testando uma aplicação web Django</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Tutorial Django Parte 11: Implantando Django em produção</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Segurança de aplicações Django</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> diff --git a/files/pt-br/learn/server-side/django/testing/index.html b/files/pt-br/learn/server-side/django/testing/index.html new file mode 100644 index 0000000000..19867b2eca --- /dev/null +++ b/files/pt-br/learn/server-side/django/testing/index.html @@ -0,0 +1,944 @@ +--- +title: 'Tutorial Django Parte 10: Testando uma aplicação web Django' +slug: Learn/Server-side/Django/Testing +translation_of: Learn/Server-side/Django/Testing +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Forms", "Learn/Server-side/Django/Deployment", "Learn/Server-side/Django")}}</div> + +<p class="summary">À medida que websites crescem, eles se tornam mais difíceis de testar manualmente. Não apenas mais para testar, mas, as interações entre componentes tornam-se mais complexas, uma pequena mudança em uma área pode impactar outras áreas, portanto mais mudanças serão necessárias para garantir que tudo permaneça funcionando e erros não sejam introduzidos à medida que mais alterações forem feitas. Uma maneira de mitigar esses problemas é escrever testes automatizados, que podem ser executados facilmente e confiavelmente toda vez que você faz uma alteração. Este tutorial mostra como automatizar testes unitários do seu website utilizando o <em>framework</em> de testes do Django.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré-requisitos:</th> + <td>Complete todos os tópicos de tutoriais anteriores, incluindo <a href="/en-US/docs/Learn/Server-side/Django/Forms">Tutorial Django Parte 9: Trabalhando com formulários</a>.</td> + </tr> + <tr> + <th scope="row">Objetivo:</th> + <td>Entender como escrever testes unitários para websites baseados em Django.</td> + </tr> + </tbody> +</table> + +<h2 id="Visão_Geral">Visão Geral</h2> + +<p>A <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Local Library</a> atualmente tem páginas para mostrar listas de todos livros e autores, visualização detalhada para itens <code>Book</code> e <code>Author</code>, uma página para renovar <code>BookInstance</code>s, e páginas para criar, atualizar e excluir itens <code>Author</code> (e também registros de <code>Book</code>, se você completou o desafio no <a href="/en-US/docs/Learn/Server-side/Django/Forms">forms tutorial</a>). Mesmo com este site relativamente pequeno, navegar manualmente por cada página e verificar superficialmente se tudo funciona como esperado pode levar vários minutos. À medida que fizemos mudanças e aumentamos o site, o tempo necessário para verificar manualmente se tudo funciona "devidamente" só aumentará. Se continuássemos como estamos, eventuamente estaríamos gastando a maior parte do tempo testando, e muito pouco tempo aprimorando nosso código.</p> + +<p>Testes automatizados podem realmente ajudar com este problema! Os benefícios óbvios são que eles podem ser executados muito mais rápido que testes manuais, podem testar com um nível mais baixo de detalhes, e testa exatamente a mesma funcionalidade (testadores humanos não são nem de longe tão confiáveis!). Por serem rápidos, testes automatizados podem ser executados mais regularmente, e se um teste falhar, eles apontam exatamente para onde o código não está funcionando como esperado .</p> + +<p>Além disso, testes automatizados podem atuar como o primeiro "usuário" do mundo real do seu código, forçando você a ser rigoroso ao definir e documentar como seu website deve se comportar. Geralmente, eles são a base para seus exemplos de código e documentação. Por essas razões, alguns processos de desenvolvimento de código iniciam com definição e implementação de teste, o qual após o código é escrito para corresponder ao comportamento necessário (ex. <a href="https://en.wikipedia.org/wiki/Test-driven_development">desenvolvimento guiado por testes</a> e <a href="https://en.wikipedia.org/wiki/Behavior-driven_development">desenvolvimento guiado por comportamento</a>).</p> + +<p>Este tutorial mostra como escrever testes automatizados para Django, adicionando um número de testes para o website <em>LocalLibrary</em>.</p> + +<h3 id="Tipos_de_teste">Tipos de teste</h3> + +<p>Há inúmeros tipos, níveis, e classificações de testes e abordagens de testes. Os testes automatizados mais importantes são:</p> + +<dl> + <dt>Testes unitários</dt> + <dd>Verifica o comportamento funcional de componentes individuais, geralmente ao nível de classe e função.</dd> + <dt>Testes de regressão</dt> + <dd>Testes que reproduzem erros históricos. Cada teste é executado inicialmente para verificar se o erro foi corrigido, e então executado novamente para garantir que não foi reintroduzido após alterações posteriores no código.</dd> + <dt>Testes de integração</dt> + <dd>Verifica como agrupamentos de componentes funcionam quando utilizados juntos. Testes de integração estão cientes das interações necessárias entre componentes, mas não necessariamente das operações internas de cada componente. Eles podem abranger agrupamentos simples de componentes através de todo website.</dd> +</dl> + +<div class="note"> +<p><strong>Nota: </strong>Outros tipos de testes comuns incluem caixa preta (black box), caixa branca (white box), manual, automatizado, canário (canary), fumaça (smoke), conformidade (conformance), aceitação (acceptance), funcional (functional), sistema (system), <em>performance</em>, carga (load) e testes de <em>stress</em>. Procure-os para mais informaçãos.</p> +</div> + +<h3 id="O_que_o_Django_fornece_para_testes">O que o Django fornece para testes?</h3> + +<p>Testar um website é uma tarefa complexa, porque isto é composto de várias camadas de lógica – do tratamento de requisições no nível HTTP, consultas de modelos, validação e processamento de formulários, e renderização de <em>template</em>.</p> + +<p>Django fornece um <em>framework</em> de teste com uma baixa hierarquia de classes construida na biblioteca padrão <code><a href="https://docs.python.org/3/library/unittest.html#module-unittest" title="(in Python v3.5)">unittest</a></code> de Python. Apesar do nome, este <em>framework</em> de teste é adequado para testes unitários e de integração. O <em>framework</em> Django adiciona métodos e ferramentas de API para ajudar a testar o comportamento web e específico do Django. Isso permite você simular requisições, inserir dados de teste e inspecionar as saídas do seu aplicativo. Django também fornece uma API (<a href="https://docs.djangoproject.com/en/2.1/topics/testing/tools/#liveservertestcase">LiveServerTestCase</a>) e ferramentas para <a href="https://docs.djangoproject.com/en/2.1/topics/testing/advanced/#other-testing-frameworks">usar diferentes frameworks de teste</a>, por exemplo, você pode integrar com o popular framework <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Your_own_automation_environment">Selenium</a> para simular um usuário interagindo com um navegador.</p> + +<p>Para escrever um teste, você deriva de qualquer uma das classes base de teste de Django (ou <em>unittest</em>) (<a href="https://docs.djangoproject.com/en/2.1/topics/testing/tools/#simpletestcase">SimpleTestCase</a>, <a href="https://docs.djangoproject.com/en/2.1/topics/testing/tools/#transactiontestcase">TransactionTestCase</a>, <a href="https://docs.djangoproject.com/en/2.1/topics/testing/tools/#testcase">TestCase</a>, <a href="https://docs.djangoproject.com/en/2.1/topics/testing/tools/#liveservertestcase">LiveServerTestCase</a>) e então escreve métodos separados para verificar se a funcionalidade específica funciona como esperado (testes usam métodos "<em>assert</em>" para testar se a expressão resulta em valores <code>True</code> ou <code>False</code>, ou se os dois valores são iguais, etc.). Quando você inicia a execução de um teste, o framework executa os métodos de teste escolhidos em suas classes derivadas. Os métodos de teste são executados independentemente, com configuração comum e/ou comportamento <em>tear-down</em> definido na classe, como mostrado abaixo.</p> + +<pre class="brush: python notranslate">class YourTestClass(TestCase): + def setUp(self): + # Setup run before every test method. + pass + + def tearDown(self): + # Clean up run after every test method. + pass + + def test_something_that_will_pass(self): + self.assertFalse(False) + + def test_something_that_will_fail(self): + self.assertTrue(False) +</pre> + +<p>A melhor classe base para maioria dos testes é <a href="https://docs.djangoproject.com/en/2.1/topics/testing/tools/#testcase">django.test.TestCase</a>. Esta classe de teste cria um banco de dados limpo antes dos testes serem executados, e executa todas as funções de teste em sua própria transação. A classe também possui um <a href="https://docs.djangoproject.com/en/2.1/topics/testing/tools/#django.test.Client" title="django.test.Client">Client</a> de teste, que você pode utilizar para simular um usuário interagindo com o código no nível de <em>view</em>. Nas seções a seguir vamos nos concentrar nos testes unitários, criados utilizando a classe base <a href="https://docs.djangoproject.com/en/2.1/topics/testing/tools/#testcase">TestCase</a>.</p> + +<div class="note"> +<p><strong>Nota:</strong> A classe <a href="https://docs.djangoproject.com/en/2.1/topics/testing/tools/#testcase">django.test.TestCase</a> é muito conveniente, mas pode resultar em alguns testes mais lentos do que necessitam ser (nem todo teste necessita configurar seu próprio banco de dados ou simular interação de <em>view</em>). Uma vez que esteja familiar com o que você pode fazer com essa classe, você pode querer substituir alguns dos seus testes por classes de teste mais simples disponíveis.</p> +</div> + +<h3 id="O_que_você_deve_testar">O que você deve testar?</h3> + +<p>Você deve testar todos aspectos do seu próprio código, mas nenhuma biblioteca ou funcionalidade oferecida como parte do Python ou Django.</p> + +<p>Assim por exemplo, conseidere o <em>model</em> <code>Author</code> definido abaixo. Você não precisa testar explicitamente se <code>first_name</code> e <code>last_name</code> foram armazenados corretamente como <code>CharField</code> no banco de dados, porque isso é algo definido pelo Django (embora, é claro, na prática você inevitávelmente testará esta funcionalidade durante o desenvolvimento). Você também não precisa testar se o <code>date_of_birth</code> foi validado para ser um campo de data, porque isso novamente é algo implementeado no Django.</p> + +<p>No entanto, você deve verificar o texto utilizado para os <em>labels</em> (<em>First name, Last name, Date of birth, Died</em>), e o tamanho do campo alocado para o texto (<em>100 caracteres</em>), porque isso faz parte do seu <em>design</em> e algo que pode ser violado/alterado no futuro.</p> + +<pre class="brush: python notranslate">class Author(models.Model): + first_name = models.CharField(max_length=100) + last_name = models.CharField(max_length=100) + date_of_birth = models.DateField(null=True, blank=True) + date_of_death = models.DateField('Died', null=True, blank=True) + + def get_absolute_url(self): + return reverse('author-detail', args=[str(self.id)]) + + def __str__(self): + return '%s, %s' % (self.last_name, self.first_name)</pre> + +<p>Similarmente, você deve verificar se os métodos personalizados <code style="font-style: normal; font-weight: normal;">get_absolute_url()</code> e <code style="font-style: normal; font-weight: normal;">__str__()</code> se comportam como desejado, porque els são sua lógica de código/negócios. No caso de <code style="font-style: normal; font-weight: normal;">get_absolute_url()</code> você pode confiar que o método <code>reverse()</code> de Django, foi implementado corretamente, portanto, o que você esta testando é se a <em>view</em> associada foi realmente definida.</p> + +<div class="note"> +<p><strong>Nota:</strong> Leitores astutos podem notar que também gostariamos de restringir que a data de nascimento e morte como valores sensíveis, e verificar se a morte vem após o nascimento. Em Django, esta restrição seria adicionada a suas classes <em>form</em> (Embora você possa definir validadores para campos do modelo e validadores de modelo, estes só serão usados no nível do formulário se forem chamdos pelo método clean() do model. Isso requer um ModelForm ou o método clean() do modelo precisa ser especificamente chamado).</p> +</div> + +<p>Com isso em mente, vamos começar a ver como definir e executar testes.</p> + +<h2 id="Visão_geral_da_estrutura_de_teste">Visão geral da estrutura de teste</h2> + +<p>Antes de entrarmos nos detalhes de "o que testar", vamos primeiro examinar brevemente <em>onde</em> e <em>como</em> os testes são definidos.</p> + +<p>Django usa o módulo <em>unittest</em> com <a href="https://docs.python.org/3/library/unittest.html#unittest-test-discovery" title="(in Python v3.5)">descoberta de teste acoplada</a>, que descrobrirá testes no diretório de trabalho atual em qualquer arquivo nomeado com o padrão <strong>test*.py</strong>. Fornecido o nome do arquivo adequadamente, você pode usar qualquer estrutura que desejar. Recomendamos que você crie um módulo para seu código de teste, e tenha arquivos separados para <em>models</em>, <em>views</em>, <em>forms </em>e qualquer outro tipo de código que você precise testar. Por exemplo:</p> + +<pre class="notranslate">catalog/ + /tests/ + __init__.py + test_models.py + test_forms.py + test_views.py +</pre> + +<p>Crie uma estrutura de arquivos como mostrado acima em seu projeto <em>LocalLibrary</em>. O <strong>__init__.py</strong> deve ser um arquivo vazio (isso informa ao Python que o diretório é um pacote). Você pode criar os três arquivos de teste copiando e renomeando o arquivo de teste do "esqueleto" <strong>/catalog/tests.py</strong>.</p> + +<div class="note"> +<p><strong>Nota:</strong> O arquivo de teste <strong>/catalog/tests.py</strong> do "esqueleto", foi criado automaticamente quando nós <a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">construimos o "esqueleto" do website Django</a>. É perfeitamente "legal" colocar todos seus testes dentro dele, mas se você testar devidamente, você acabará rapidamente com um arquivo de teste muito grande e incontrolável.</p> + +<p>Exclua o arquivo do "esqueleto", pois não precisamos dele.</p> +</div> + +<p>Abra <strong>/catalog/tests/test_models.py</strong>. O arquivo deve importar <code>django.test.TestCase</code>, como mostrado:</p> + +<pre class="brush: python notranslate">from django.test import TestCase + +# Create your tests here. +</pre> + +<p>Frequentemente, você adicionará uma classe de teste para cada <em>model/view/form</em> que deseja testar, com métodos individuais para testar funcionalidades específicas. Em outros casos, você pode desejar ter uma classe separada para testar um caso de uso específico, com funções de teste individuais que testam aspectos desse caso de uso (por exemplo, uma classe para testar se um campo do <em>model</em> é validado corretamente, com funções para testar cada um dos possíveis casos de falha). Novamente, a estrutura depende muito de você, mas é melhor se você for consistente.</p> + +<p>Adicione a classe de teste abaixo na parte inferior do arquivo. A classe demonstra como construir uma classe de teste derivando de <code>TestCase</code>.</p> + +<pre class="brush: python notranslate">class YourTestClass(TestCase): + @classmethod + def setUpTestData(cls): + print("setUpTestData: Run once to set up non-modified data for all class methods.") + pass + + def setUp(self): + print("setUp: Run once for every test method to setup clean data.") + pass + + def test_false_is_false(self): + print("Method: test_false_is_false.") + self.assertFalse(False) + + def test_false_is_true(self): + print("Method: test_false_is_true.") + self.assertTrue(False) + + def test_one_plus_one_equals_two(self): + print("Method: test_one_plus_one_equals_two.") + self.assertEqual(1 + 1, 2)</pre> + +<p>A nova classe define dois métodos que você pode utilizar para aconfiguração de pré-teste (por exemplo, para criar quaisquer modelos ou outros objetos que precisará para to teste):</p> + +<ul> + <li><code>setUpTestData()</code> é chamado uma vez no início da execução do teste para configuração em nível de classe. Você usaria isso para criar objetos que não serão modificados ou alterados em nenhum dos métodos de teste.</li> + <li><code>setUp()</code> é chamado antes de toda função de teste para configurar qualquer objeto que possa ser modificado pelo teste (toda função de teste receberá uma versão "nova" desses objetos).</li> +</ul> + +<div class="note"> +<p>As classes de teste também têm um método <code>tearDown()</code>, que não usamos. Este método não é particularmente útil para testes de banco de dados, pois a classe base <code>TestCase</code> cuida da desmontagem do banco de dados para você.</p> +</div> + +<p>Abaixo desses, temos vários métodos de teste, que usam funções <code>Assert</code> para testar se as condições são verdadeiras, falsas ou iguais (<code>AssertTrue</code>, <code>AssertFalse</code>, <code>AssertEqual</code>). Se a condição não for avaliada como esperado, então o teste falhará e reportará o erro ao seu console.</p> + +<p><code>AssertTrue</code>, <code>AssertFalse</code>, <code>AssertEqual</code> são assertivas padrão fornecidas pelo <strong>unittest</strong>. Existem outras assertivas padão no <em>framework</em> e também <a href="https://docs.djangoproject.com/en/2.1/topics/testing/tools/#assertions">Django especifica assertivas</a> para testar se uma <em>view</em> redireciona (<code>assertRedirects</code>), para testar se um template específico foi utilizado (<code>assertTemplateUsed</code>), etc.</p> + +<div class="note"> +<p>Você normalmente não deve incluir funções <strong>print()</strong> em seus testes como mostrado acima. Nós fizemos isso aqui apenas para que você posssa ver no console a ordem que as funções de configuração são chamadas (na seção a seguir).</p> +</div> + +<h2 id="Como_executar_os_testes">Como executar os testes</h2> + +<p>A maneira mais fácil para executar todos os testes é usar o comando:</p> + +<pre class="brush: bash notranslate">python3 manage.py test</pre> + +<p>Isso descobrirá todos arquivos nomeados com o padrão <strong>test*.py</strong> no diretório atual e executará todos testes definidos usando as classes base apropriadas (aqui temos vários arquivos de teste, mas, atualmente, apenas <strong>/catalog/tests/test_models.py</strong> contém testes). Por padrão, os testes irão reportar individualmente apenas falhas no teste, seguidos por um resumo do teste.</p> + +<div class="note"> +<p>Se você obter erros semelhantes a: <code>ValueError: Missing staticfiles manifest entry ...</code> isso pode ocorrer porque o teste não é executado como <em>collectstatic</em> por padrão e seu <em>app</em> está usando uma classe de armazenamento que exige isto (veja <a href="https://docs.djangoproject.com/en/2.1/ref/contrib/staticfiles/#django.contrib.staticfiles.storage.ManifestStaticFilesStorage.manifest_strict">manifest_strict</a> para mais informações). Existem várias maneiras de solucionar esse problema - o mais fácil é simplesmente executar <em>collectstatic</em> antes de executar os testes:</p> + +<pre class="brush: bash notranslate">python3 manage.py collectstatic +</pre> +</div> + +<p>Execute os testes no diretório raiz de <em>LocalLibrary</em>. Você deve ver uma saída como a abaixo.</p> + +<pre class="brush: bash notranslate">> python3 manage.py test + +Creating test database for alias 'default'... +<strong>setUpTestData: Run once to set up non-modified data for all class methods. +setUp: Run once for every test method to setup clean data. +Method: test_false_is_false. +setUp: Run once for every test method to setup clean data. +Method: test_false_is_true. +setUp: Run once for every test method to setup clean data. +Method: test_one_plus_one_equals_two.</strong> +. +====================================================================== +FAIL: test_false_is_true (catalog.tests.tests_models.YourTestClass) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "D:\Github\django_tmp\library_w_t_2\locallibrary\catalog\tests\tests_models.py", line 22, in test_false_is_true + self.assertTrue(False) +AssertionError: False is not true + +---------------------------------------------------------------------- +Ran 3 tests in 0.075s + +FAILED (failures=1) +Destroying test database for alias 'default'...</pre> + +<p>Aqui vemos que tivemos uma falha no teste e podemos ver exatamente qual função falhou e por quê (essa falha é esperada, porque <code>False</code> não é <code>True</code>!).</p> + +<div class="note"> +<p><strong>Dica: </strong>A coisa mais importante para aprender com a saída do teste acima é que é muito mais valioso se você utilizar nomes descritivos/informativos para seus objetos e métodos.</p> +</div> + +<p>O texto acima mostrado em <strong>negrito</strong> normalmente não apareceria na saída do teste (isso é gerado pelas funções <code>print()</code> em nossos teste). Isso mostra como o método <code>setUpTestData()</code> é chamdo uma vez para classe e <code>setUp()</code> é chamado antes de cada método.</p> + +<p>As próximas seções mostram como você pode executar testes específicos e como controlar quanta infromação os testes exibem.</p> + +<h3 id="Mostrando_mais_informações_de_teste">Mostrando mais informações de teste</h3> + +<p>Se você deseja obter mais informação sobre a execução do teste, você pode mudar a verbosidade (<em>verbosity)</em>. Por exemplo, para listar os sucessos do teste, bem como as falhas (e um monte de informações sobre como o banco de dados de teste está configurado) vocêpode definir a <em>verbosity</em> para "2" como mostrado:</p> + +<pre class="brush: bash notranslate">python3 manage.py test --verbosity 2</pre> + +<p>Os níveis permitidos de <em>verbosity</em> são 0, 1, 2, e 3, com o padrão sendo "1".</p> + +<h3 id="Executando_testes_específicos">Executando testes específicos</h3> + +<p>Se você desseja executar um subconjunto de seus testes, você pode fazer isso especificando o caminho completo para o(s) pacote(s), módulos, subclasse <code>TestCase</code> ou método:</p> + +<pre class="brush: bash notranslate"># Run the specified module +python3 manage.py test catalog.tests + +# Run the specified module +python3 manage.py test catalog.tests.test_models + +# Run the specified class +python3 manage.py test catalog.tests.test_models.YourTestClass + +# Run the specified method +python3 manage.py test catalog.tests.test_models.YourTestClass.test_one_plus_one_equals_two +</pre> + +<h2 id="Testes_da_LocalLibrary">Testes da LocalLibrary</h2> + +<p>Agora que sabemos como executar nosso testes e que tipo de coisas precisams testar, vamos ver alguns exemplos práticos.</p> + +<div class="note"> +<p><strong>Nota: </strong>Não escreveremos todos os testes possíveis, mas isso deve lhe dar uma ideia de como testes trabalham e o que mais você pode fazer.</p> +</div> + +<h3 id="Models">Models</h3> + +<p>Como discutido acima, devemos testar qualquer coisa que faça parte do nosso projeto ou que seja definido por código que escrevemos, mas não bibliotecas/códigos que já foram testados pelo Django ou pela equipe de desenvolvimento do Python.</p> + +<p>Por exemplo, considere o <em>model</em> <code>Author</code> abaixo. Aqui devemos testar os <em>labels</em> para todos os campos, porque, embora não tenhamos específicado explicitamente a maioria deles, temos um projeto que diz quais devem ser esses valores. Se não testamos os valores, não sabemos se os <em>labels</em> dos campos têm os valores pretendidos. Similarmente, enquanto confiamos que o Django criará um campo com o tamanho específicado, vale a pena específicar um teste para este tamanho, para garantir que ele foi implementado como planejado.</p> + +<pre class="brush: python notranslate">class Author(models.Model): + first_name = models.CharField(max_length=100) + last_name = models.CharField(max_length=100) + date_of_birth = models.DateField(null=True, blank=True) + date_of_death = models.DateField('Died', null=True, blank=True) + + def get_absolute_url(self): + return reverse('author-detail', args=[str(self.id)]) + + def __str__(self): + return f'{self.last_name}, {self.first_name}'</pre> + +<p>Abra nosso <strong>/catalog/tests/test_models.py</strong>, e substitua qualquer código existente pelo seguinte código de teste para o <em>model</em> <code>Author</code>.</p> + +<p>Aqui você verá que primeiro importamos <code>TestCase</code> e derivamos nossa classe de teste (<code>AuthorModelTest</code>) a partir dela, usando um nome descritivo para que possamos identificar facilmente quaiquer testes com falha na saída do teste. Nós então chamamos <code>setUpTestData()</code> para criar um objeto autor que iremos usar mas não modificaremos em nenhum dos testes.</p> + +<pre class="brush: python notranslate">from django.test import TestCase + +from catalog.models import Author + +class AuthorModelTest(TestCase): + @classmethod + def setUpTestData(cls): + # Set up non-modified objects used by all test methods + Author.objects.create(first_name='Big', last_name='Bob') + + def test_first_name_label(self): + author = Author.objects.get(id=1) + field_label = author._meta.get_field('first_name').verbose_name + self.assertEquals(field_label, 'first name') + + def test_date_of_death_label(self): + author=Author.objects.get(id=1) + field_label = author._meta.get_field('date_of_death').verbose_name + self.assertEquals(field_label, 'died') + + def test_first_name_max_length(self): + author = Author.objects.get(id=1) + max_length = author._meta.get_field('first_name').max_length + self.assertEquals(max_length, 100) + + def test_object_name_is_last_name_comma_first_name(self): + author = Author.objects.get(id=1) + expected_object_name = f'{author.last_name}, {author.first_name}' + self.assertEquals(expected_object_name, str(author)) + + def test_get_absolute_url(self): + author = Author.objects.get(id=1) + # This will also fail if the urlconf is not defined. + self.assertEquals(author.get_absolute_url(), '/catalog/author/1')</pre> + +<p>Os testes de campo verificam se os valores dos <em>labels</em> dos campos (<code>verbose_name</code>) e se o tamanho dos campos de caracteres são como esperado. Todos esses métodos possuem nomes descritivos e seguem o mesmo padrão:</p> + +<pre class="brush: python notranslate"># Get an author object to test +author = Author.objects.get(id=1) + +# Get the metadata for the required field and use it to query the required field data +field_label = author._meta.get_field('first_name').verbose_name + +# Compare the value to the expected result +self.assertEquals(field_label, 'first name')</pre> + +<p>As coisas interessantes a serem observadas aqui:</p> + +<ul> + <li>Não podemos obter <code>verbose_name</code> diretamente utilizando <code>author.first_name.verbose_name</code>, porque <code>author.first_name</code> é uma <em>string</em> (não um identificador para o objeto <code>first_name</code> que podemos utilizar para acessar suas propriedades). Em vez disso, precisamos utilizar o atributo <code>_meta</code> de <em>author</em> para obter uma instância do campo e usá-la para consultar informações adicionais.</li> + <li>Optamos por utilizar <code>assertEquals(field_label,'first name')</code> em vez de <code>assertTrue(field_label == 'first name')</code>. A razão para isso é que, se o teste falhar a saída do primeiro informa o que realmente era o <em>label</em>, que torna a depuração do problema um pouco mais fácil.</li> +</ul> + +<div class="note"> +<p><strong>Nota:</strong> Testes para os rótulos <code>last_name</code> e <code>date_of_birth</code> e também para o teste para o tamanho do <code>last_name</code> field foram omitidos. Adicione suas próprias versões agora, seguindo as convenções de nomeclatura e abordagens mostradas acima.</p> +</div> + +<p>Também precisamos testar nossos métodos personalizados. Eles, essencialmente, apenas verificam se o nome do objeto foi construido como esperamos, usando o formato "Last Name", "First Name", e se a URL que obtemos para um item de <code>Author</code> é o que esperávamos.</p> + +<pre class="brush: python notranslate">def test_object_name_is_last_name_comma_first_name(self): + author = Author.objects.get(id=1) + expected_object_name = f'{author.last_name}, {author.first_name}' + self.assertEquals(expected_object_name, str(author)) + +def test_get_absolute_url(self): + author = Author.objects.get(id=1) + # This will also fail if the urlconf is not defined. + self.assertEquals(author.get_absolute_url(), '/catalog/author/1')</pre> + +<p>Execute os testes agora. Se você criou o modelo Author como descrevemos no tutorial de modelos, é bem provável que você obtenha um erro para o <em>label</em> <code>date_of_death</code> como mostrado abaixo. O teste está falhando porque foi escrito esperando que a definição do <em>label</em> siga a convenção do Django de não colocar em maíúscula a primeira letra do <em>label</em> (Django faz isso por você).</p> + +<pre class="brush: bash notranslate">====================================================================== +FAIL: test_date_of_death_label (catalog.tests.test_models.AuthorModelTest) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "D:\...\locallibrary\catalog\tests\test_models.py", line 32, in test_date_of_death_label + self.assertEquals(field_label,'died') +AssertionError: 'Died' != 'died' +- Died +? ^ ++ died +? ^</pre> + +<p>Este é um bug muito pequeno, mas destaca como a escrita de testes pode verificar mais minuciosamente quaislquer suposições que você tenha feito.</p> + +<div class="note"> +<p><strong>Nota:</strong> Altere o <em>label</em> para o campo date_of_death (/catalog/models.py) para "died" e re-executes os testes.</p> +</div> + +<p>Os padrões para testar os outros modelos são semelhantes, portanto não continuaremos discutindo mais isso. Sinta-se livre para criar seus próprios testes para nossos outros modelos.</p> + +<h3 id="Forms">Forms</h3> + +<p>A filosofia para testar seus <em>forms </em>é a mesma que para testar seus <em>models</em>; você precisa testar qualquer coisa que tenha codificado ou seu projeto especifica, mas não o comportamento do framework subjacente e outras bibliotecas de terceiros</p> + +<p>Geralmente, isso significa que você deve testar se os <em>forms</em> têm os campos que você deseja e se esses são exibidos com os <em>labels</em> e texto de ajuda apropriados. Você não precisa verificar se o Django o tipo de campo corretamente (a menos que você tenha criado seu próprio campo e validação personalizados) — ex. você não precisa testar se um campo de email aceita apenas email. No entanto, você precisaria testar qualquer validação adicional que você espera que seja executada nos campos e quaisquer mensagens que seu código irá gerar para erros.</p> + +<p>Considere nosso <em>form</em> para renovação de livros. Ele tem apenas um campo para data de renovação, que terá um <em>label</em> e um texto de ajuda que precisaremos verificar.</p> + +<pre class="brush: python notranslate">class RenewBookForm(forms.Form): + """Form for a librarian to renew books.""" + renewal_date = forms.DateField(help_text="Enter a date between now and 4 weeks (default 3).") + + def clean_renewal_date(self): + data = self.cleaned_data['renewal_date'] + + # Check if a date is not in the past. + if data < datetime.date.today(): + raise ValidationError(_('Invalid date - renewal in past')) + + # Check if date is in the allowed range (+4 weeks from today). + if data > datetime.date.today() + datetime.timedelta(weeks=4): + raise ValidationError(_('Invalid date - renewal more than 4 weeks ahead')) + + # Remember to always return the cleaned data. + return data</pre> + +<p>Abra nosso arquivo <strong>/catalog/tests/test_forms.py</strong> e substitua qualquer código existente pelo seguinte código de teste para o <em>form</em> <code>RenewBookForm</code>. Nós iniciamos importando nosso <em>form</em> e algumas bibliotecas Python e Django para ajudar testar funcionalidades relacionadas ao tempo. Em seguida, declaramos nossa classe de teste do <em>form,</em> da mesma maneira que fizemos para <em>models</em>, usando um nome descritivo para a classe de teste derivada de <code>TestCase</code>.</p> + +<pre class="brush: python notranslate">import datetime + +from django.test import TestCase +from django.utils import timezone + +from catalog.forms import RenewBookForm + +class RenewBookFormTest(TestCase): + def test_renew_form_date_field_label(self): + form = RenewBookForm() + self.assertTrue(form.fields['renewal_date'].label == None or form.fields['renewal_date'].label == 'renewal date') + + def test_renew_form_date_field_help_text(self): + form = RenewBookForm() + self.assertEqual(form.fields['renewal_date'].help_text, 'Enter a date between now and 4 weeks (default 3).') + + def test_renew_form_date_in_past(self): + date = datetime.date.today() - datetime.timedelta(days=1) + form = RenewBookForm(data={'renewal_date': date}) + self.assertFalse(form.is_valid()) + + def test_renew_form_date_too_far_in_future(self): + date = datetime.date.today() + datetime.timedelta(weeks=4) + datetime.timedelta(days=1) + form = RenewBookForm(data={'renewal_date': date}) + self.assertFalse(form.is_valid()) + + def test_renew_form_date_today(self): + date = datetime.date.today() + form = RenewBookForm(data={'renewal_date': date}) + self.assertTrue(form.is_valid()) + + def test_renew_form_date_max(self): + date = timezone.localtime() + datetime.timedelta(weeks=4) + form = RenewBookForm(data={'renewal_date': date}) + self.assertTrue(form.is_valid()) +</pre> + +<p>As primeiras duas funções testam se os campos <code>label</code> e <code>help_text</code> são como esperados. Temos que acessar o campo usando o dicionário de campos (ex. <code>form.fields['renewal_date']</code>). Observe aqui que também precisamos testar se o valor do <em>label</em> é <code>None</code>, porque mesmo que o Django processe o <em>label</em> correto, retornará <code>None</code> se o valor não estiver definido explicitamente.</p> + +<p>O restante das funções testam se o form é valido para datas de renovação dentro do intervalo aceitável e inválido para os valores foram do intervalo. Observe como construimos os valores teste de data em torno de nossa data atual (<code>datetime.date.today()</code>) usando <code>datetime.timedelta()</code> (nesse caso, especificando um número de dias ou semanas). Então, apenas criamos o <em>form</em>, passando nossos dados e testando se é válido.</p> + +<div class="note"> +<p><strong>Nota:</strong> Aqui, na realidade, não usamos o banco de dados ou cliente teste. Considere modificar essses testes para utilizar <a href="https://docs.djangoproject.com/en/2.1/topics/testing/tools/#django.test.SimpleTestCase">SimpleTestCase</a>.</p> + +<p>Também precisamos validar que os erros corretos sejam gerados se o form é inválido, no entanto, isso geralmente é feito no processamento da view, portanto trataremos disso na próxima seção.</p> +</div> + +<p>Isso é tudo para <em>forms</em>; nós temos alguns outros, mas eles são automaticamente criados pelas nossas <em>views</em> de edição baseada na classe genérica, e devem ser testadas lá! Execute os testes e confirme se nosso código ainda passa!</p> + +<h3 id="Views">Views</h3> + +<p>Para validar o comportamento das nossas <em>views</em>, utilzamos <a href="https://docs.djangoproject.com/en/2.1/topics/testing/tools/#django.test.Client">Client</a> de teste do Django. Essa classe funciona como um navegador web fictício que podemos usar para simular requisições <code>GET</code> and <code>POST</code> em uma URL e observar a resposta. Podemos ver quase tudo sobre a resposta, desde HTTP de baixo nível (cabeçalhos de resultados e códigos de status) até o <em>template</em> que estamos utilizando para renderizar o HTML e os dados de contexto que estamos passando para ele. Também podemos ver a cadeia de redirecionamentos (se houver) e verificar a URL e o código de status em cada etapa. Isso nos permite verificar se cada <em>view</em> esta fazendo o que é esperado.</p> + +<p>Vamos iniciar com uma de nossas <em>views</em> mais simples, que fornece uma lista de todos Autores. Isso é exibido na URL <strong>/catalog/authors/</strong> (uma URL chamada 'authors' na configuração de URL).</p> + +<pre class="brush: python notranslate">class AuthorListView(generic.ListView): + model = Author + paginate_by = 10 +</pre> + +<p>Como esta é uma <em>list view</em> genérica, quase tudo é feito para nós pelo Django. Provavelmente, se você confia no Django, então a única coisa que você precisa testar é se a <em>view</em> é acessível na URL correta e pode ser acessada usando seu nome. No entanto, se você está usando um desenvolvimento orientado a testes, você iniciará escrevendo testes que confirmam que a <em>view</em> exibe todos Autores, paginando-os em lotes de 10.</p> + +<p>Abra o arquivo <strong>/catalog/tests/test_views.py</strong> e substitua qualquer texto existente pelo seguinte código de teste para <code>AuthorListView</code>. Como antes, importamos nosso <em>model</em> e algumas classe úteis. No método <code>setUpTestData()</code> configuramos vários objetos <code>Author</code> para que possamos testar nossa paginação.</p> + +<pre class="brush: python notranslate">from django.test import TestCase +from django.urls import reverse + +from catalog.models import Author + +class AuthorListViewTest(TestCase): + @classmethod + def setUpTestData(cls): + # Create 13 authors for pagination tests + number_of_authors = 13 + + for author_id in range(number_of_authors): + Author.objects.create( + first_name=f'Christian {author_id}', + last_name=f'Surname {author_id}', + ) + + def test_view_url_exists_at_desired_location(self): + response = self.client.get('/catalog/authors/') + self.assertEqual(response.status_code, 200) + + def test_view_url_accessible_by_name(self): + response = self.client.get(reverse('authors')) + self.assertEqual(response.status_code, 200) + + def test_view_uses_correct_template(self): + response = self.client.get(reverse('authors')) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'catalog/author_list.html') + + def test_pagination_is_ten(self): + response = self.client.get(reverse('authors')) + self.assertEqual(response.status_code, 200) + self.assertTrue('is_paginated' in response.context) + self.assertTrue(response.context['is_paginated'] == True) + self.assertTrue(len(response.context['author_list']) == 10) + + def test_lists_all_authors(self): + # Get second page and confirm it has (exactly) remaining 3 items + response = self.client.get(reverse('authors')+'?page=2') + self.assertEqual(response.status_code, 200) + self.assertTrue('is_paginated' in response.context) + self.assertTrue(response.context['is_paginated'] == True) + self.assertTrue(len(response.context['author_list']) == 3)</pre> + +<p>Todos os teste usam o cliente (pertenecente a nossa classe derivada <code>TestCase</code>'s) para simular uma requisição <code>GET</code> e obter uma resposta. A primeira versão verifica uma URL específica URL (observe, apenas o caminho específico, sem o domínio), enquanto a segunda gera a URL a partir do seu nome na configuração da URL.</p> + +<pre class="brush: python notranslate">response = self.client.get('/catalog/authors/') +response = self.client.get(reverse('authors')) +</pre> + +<p>Uma vez que temos a resposta, consultamos o seu código de status, o <em>template</em> usado, se a resposta é paginada ou não, o número de itens retonado e o número total de itens.</p> + +<div class="blockIndicator note"> +<p class="brush: python">Nota: Se você definir a variável <code>paginate_by</code> em seu arquivo <strong>/c</strong><strong>atalog/views.py</strong> para um número diferente de 10, atualize as linhas que testam se o número correto de itens é exibido nos <em>templates</em> paginados acima e nas seções seguintes. Por exemplo, se você definiu a variável para a lista de autor para 5, atualize a linha acima para:</p> + +<pre class="brush: python notranslate">self.assertTrue(len(response.context['author_list']) == 5) +</pre> +</div> + +<p>A variável mais importante que demonstramos acima é <code>response.context</code>, que é a variável de contexto passada para o <em>template</em> pela <em>view</em>. Isso é incrivelmente útil para testes, porque permite confirmar que nosso template está obtendo todos os dados necessários. Em outras palavras, podemos verificar se estamos utilizando o <em>template</em> pretendido e quais dados o <em>template</em> está obtendo, o que ajuda bastante a verificar que alguns problemas de renderização são apenas devido ao <em>template</em>.</p> + +<h4 id="Views_restritas_a_usuários_logados"><em>Views</em> restritas a usuários logados</h4> + +<p>Em alguns casos, você desejará testar uma <em>view</em> que é restrita apenas aos usuários logados. Por exemplo, nossa <code>LoanedBooksByUserListView</code> é muito similar a nossa <em>view</em> anterior, mas está disponível apenas para usuários logados e exibe apenas os registros <code>BookInstance</code> que são emprestados pelo usuário atual, têm o status 'emprestado' e são ordenados "mais antigos primeiro".</p> + +<pre class="brush: python notranslate">from django.contrib.auth.mixins import LoginRequiredMixin + +class LoanedBooksByUserListView(LoginRequiredMixin, generic.ListView): + """Generic class-based view listing books on loan to current user.""" + model = BookInstance + template_name ='catalog/bookinstance_list_borrowed_user.html' + paginate_by = 10 + + def get_queryset(self): + return BookInstance.objects.filter(borrower=self.request.user).filter(status__exact='o').order_by('due_back')</pre> + +<p>Adicione o código seguinte ao <strong>/catalog/tests/test_views.py</strong>. Aqui, primeiro usamos <code>SetUp()</code> para criar alguma contas de login de usuário e objetos <code>BookInstance</code> (junto com seus livros associados e outros registros) que usaremos posteriormente nos testes. Metade dos livros são emprestados para cada usuário teste, mas inicialmente definimos o status de todos os livros como "manutenção". Usamos <code>SetUp()</code> em vez de <code>setUpTestData()</code> porque modificaremos alguns desses objetos depois.</p> + +<div class="note"> +<p><strong>Nota:</strong> O código <code>setUp()</code> abaixo, cria um livro com uma <code>Language</code> especificada, mas seu código pode não incluir o <em>model</em> <code>Language</code>, pois foi criado como um desafio. Se esse for o caso, simplesmente comente as partes do código que cria ou importa objetos <em>Language</em>. Você também deve fazer isso na seção <code>RenewBookInstancesViewTest</code> a seguir.</p> +</div> + +<pre class="brush: python notranslate">import datetime + +from django.utils import timezone +from django.contrib.auth.models import User # Required to assign User as a borrower + +from catalog.models import BookInstance, Book, Genre, Language + +class LoanedBookInstancesByUserListViewTest(TestCase): + def setUp(self): + # Create two users + test_user1 = User.objects.create_user(username='testuser1', password='1X<ISRUkw+tuK') + test_user2 = User.objects.create_user(username='testuser2', password='2HJ1vRV0Z&3iD') + + test_user1.save() + test_user2.save() + + # Create a book + test_author = Author.objects.create(first_name='John', last_name='Smith') + test_genre = Genre.objects.create(name='Fantasy') + test_language = Language.objects.create(name='English') + test_book = Book.objects.create( + title='Book Title', + summary='My book summary', + isbn='ABCDEFG', + author=test_author, + language=test_language, + ) + + # Create genre as a post-step + genre_objects_for_book = Genre.objects.all() + test_book.genre.set(genre_objects_for_book) # Direct assignment of many-to-many types not allowed. + test_book.save() + + # Create 30 BookInstance objects + number_of_book_copies = 30 + for book_copy in range(number_of_book_copies): + return_date = timezone.localtime() + datetime.timedelta(days=book_copy%5) + the_borrower = test_user1 if book_copy % 2 else test_user2 + status = 'm' + BookInstance.objects.create( + book=test_book, + imprint='Unlikely Imprint, 2016', + due_back=return_date, + borrower=the_borrower, + status=status, + ) + + def test_redirect_if_not_logged_in(self): + response = self.client.get(reverse('my-borrowed')) + self.assertRedirects(response, '/accounts/login/?next=/catalog/mybooks/') + + def test_logged_in_uses_correct_template(self): + login = self.client.login(username='testuser1', password='1X<ISRUkw+tuK') + response = self.client.get(reverse('my-borrowed')) + + # Check our user is logged in + self.assertEqual(str(response.context['user']), 'testuser1') + # Check that we got a response "success" + self.assertEqual(response.status_code, 200) + + # Check we used correct template + self.assertTemplateUsed(response, 'catalog/bookinstance_list_borrowed_user.html') +</pre> + +<p>Para verificar se a <em>view</em> será redirecionada para uma página de login se o usuário não estiver logado, usamos <code>assertRedirects</code>, como demonstrado em <code>test_redirect_if_not_logged_in()</code>. Para verificar se a página é exibida para um usuário logado, primeiro logamos com nosso usuário teste e então acessamos a página novamente e verificamos se obtivemos um <code>status_code</code> de 200 (successo). </p> + +<p>O restante dos testes verificam se nossa <em>view</em> retorna apenas livros emprestados ao nosso usuário atual. Copie o código abaixo e cole no final da classe de teste acima.</p> + +<pre class="brush: python notranslate"> def test_only_borrowed_books_in_list(self): + login = self.client.login(username='testuser1', password='1X<ISRUkw+tuK') + response = self.client.get(reverse('my-borrowed')) + + # Check our user is logged in + self.assertEqual(str(response.context['user']), 'testuser1') + # Check that we got a response "success" + self.assertEqual(response.status_code, 200) + + # Check that initially we don't have any books in list (none on loan) + self.assertTrue('bookinstance_list' in response.context) + self.assertEqual(len(response.context['bookinstance_list']), 0) + + # Now change all books to be on loan + books = BookInstance.objects.all()[:10] + + for book in books: + book.status = 'o' + book.save() + + # Check that now we have borrowed books in the list + response = self.client.get(reverse('my-borrowed')) + # Check our user is logged in + self.assertEqual(str(response.context['user']), 'testuser1') + # Check that we got a response "success" + self.assertEqual(response.status_code, 200) + + self.assertTrue('bookinstance_list' in response.context) + + # Confirm all books belong to testuser1 and are on loan + for bookitem in response.context['bookinstance_list']: + self.assertEqual(response.context['user'], bookitem.borrower) + self.assertEqual('o', bookitem.status) + + def test_pages_ordered_by_due_date(self): + # Change all books to be on loan + for book in BookInstance.objects.all(): + book.status='o' + book.save() + + login = self.client.login(username='testuser1', password='1X<ISRUkw+tuK') + response = self.client.get(reverse('my-borrowed')) + + # Check our user is logged in + self.assertEqual(str(response.context['user']), 'testuser1') + # Check that we got a response "success" + self.assertEqual(response.status_code, 200) + + # Confirm that of the items, only 10 are displayed due to pagination. + self.assertEqual(len(response.context['bookinstance_list']), 10) + + last_date = 0 + for book in response.context['bookinstance_list']: + if last_date == 0: + last_date = book.due_back + else: + self.assertTrue(last_date <= book.due_back) + last_date = book.due_back</pre> + +<p>Você também pode adicionar testes de paginação, se desejar!</p> + +<h4 id="Testando_views_com_forms">Testando <em>views</em> com <em>forms</em></h4> + +<p>Testar views com forms é um pouco mais complicado que nos casos acima, porque você precisa testar mais caminhos de código: exibição inicial, exibição após falha de validação de dados e exibição após validação com sucesso. A boa notícia é que usamos o cliente para testar quase exatamente da mesma maneira que fizemos para <em>views</em> somente de exibição.</p> + +<p>Para demonstrar, vamos escrever alguns testes para a <em>view</em> usada para renovar livros (<code>renew_book_librarian()</code>):</p> + +<pre class="brush: python notranslate">from catalog.forms import RenewBookForm + +@permission_required('catalog.can_mark_returned') +def renew_book_librarian(request, pk): + """View function for renewing a specific BookInstance by librarian.""" + book_instance = get_object_or_404(BookInstance, pk=pk) + + # If this is a POST request then process the Form data + if request.method == 'POST': + + # Create a form instance and populate it with data from the request (binding): + book_renewal_form = RenewBookForm(request.POST) + + # Check if the form is valid: + if form.is_valid(): + # process the data in form.cleaned_data as required (here we just write it to the model due_back field) + book_instance.due_back = form.cleaned_data['renewal_date'] + book_instance.save() + + # redirect to a new URL: + return HttpResponseRedirect(reverse('all-borrowed')) + + # If this is a GET (or any other method) create the default form + else: + proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3) + book_renewal_form = RenewBookForm(initial={'renewal_date': proposed_renewal_date}) + + context = { + 'book_renewal_form': book_renewal_form, + 'book_instance': book_instance, + } + + return render(request, 'catalog/book_renew_librarian.html', context)</pre> + +<p>Precisamos testar se a <em>view</em> está disponível apenas para usuários que têm a permissão <code>can_mark_returned </code>, e se eles são direcionados para uma página de erro HTTP 404 se tentarem renovar um <code>BookInstance</code> que não existe. Devemos verificar se o valor inicial do form é propagado com uma data três semanas no futuro e se a validação for bem sucedida somos redirecionados para a <em>view</em> "all-borrowed books". Como parte da verificação dos testes de falha de validação, também verificaremos se nosso <em>form</em> está enviando mensagens de erro apropriadas.</p> + +<p>Adicione a primeira parte da classe de teste (mostrada abaixo) na parte inferior de <strong>/catalog/tests/test_views.py</strong>. Isso cria dois usuários e duas instâncias de livro, mas apenas concede a um usuário a permissão necessária para acessar a <em>view</em>. O código para conceder permissões durante os testes é mostrado em negrito:</p> + +<pre class="brush: python notranslate">import uuid + +from django.contrib.auth.models import Permission # Required to grant the permission needed to set a book as returned. + +class RenewBookInstancesViewTest(TestCase): + def setUp(self): + # Create a user + test_user1 = User.objects.create_user(username='testuser1', password='1X<ISRUkw+tuK') + test_user2 = User.objects.create_user(username='testuser2', password='2HJ1vRV0Z&3iD') + + test_user1.save() + test_user2.save() + +<strong> permission = Permission.objects.get(name='Set book as returned') + test_user2.user_permissions.add(permission) + test_user2.save()</strong> + + # Create a book + test_author = Author.objects.create(first_name='John', last_name='Smith') + test_genre = Genre.objects.create(name='Fantasy') + test_language = Language.objects.create(name='English') + test_book = Book.objects.create( + title='Book Title', + summary='My book summary', + isbn='ABCDEFG', + author=test_author, + language=test_language, + ) + + # Create genre as a post-step + genre_objects_for_book = Genre.objects.all() + test_book.genre.set(genre_objects_for_book) # Direct assignment of many-to-many types not allowed. + test_book.save() + + # Create a BookInstance object for test_user1 + return_date = datetime.date.today() + datetime.timedelta(days=5) + self.test_bookinstance1 = BookInstance.objects.create( + book=test_book, + imprint='Unlikely Imprint, 2016', + due_back=return_date, + borrower=test_user1, + status='o', + ) + + # Create a BookInstance object for test_user2 + return_date = datetime.date.today() + datetime.timedelta(days=5) + self.test_bookinstance2 = BookInstance.objects.create( + book=test_book, + imprint='Unlikely Imprint, 2016', + due_back=return_date, + borrower=test_user2, + status='o', + )</pre> + +<p>Adicione os seguintes testes na parte inferior da classe de teste. Eles verificam se apenas usuários com a permissão correta (testuser2) podem aceesar a <em>view</em>. Verificamos todos os casos: quando o usuários não está logado, quando um usuário está logado mas não tem as permissões corretas, quando o usuário possui permissões, mas não é o tomador do empréstimo (deve ter êxito), e o que acontece quando eles tentam acessar uma <code>BookInstance</code> que não existe. Também verificamos se o <em>template</em> correto é utilizado.</p> + +<pre class="brush: python notranslate"> def test_redirect_if_not_logged_in(self): + response = self.client.get(reverse('renew-book-librarian', kwargs={'pk': self.test_bookinstance1.pk})) + # Manually check redirect (Can't use assertRedirect, because the redirect URL is unpredictable) + self.assertEqual(response.status_code, 302) + self.assertTrue(response.url.startswith('/accounts/login/')) + + def test_redirect_if_logged_in_but_not_correct_permission(self): + login = self.client.login(username='testuser1', password='1X<ISRUkw+tuK') + response = self.client.get(reverse('renew-book-librarian', kwargs={'pk': self.test_bookinstance1.pk})) + self.assertEqual(response.status_code, 403) + + def test_logged_in_with_permission_borrowed_book(self): + login = self.client.login(username='testuser2', password='2HJ1vRV0Z&3iD') + response = self.client.get(reverse('renew-book-librarian', kwargs={'pk': self.test_bookinstance2.pk})) + + # Check that it lets us login - this is our book and we have the right permissions. + self.assertEqual(response.status_code, 200) + + def test_logged_in_with_permission_another_users_borrowed_book(self): + login = self.client.login(username='testuser2', password='2HJ1vRV0Z&3iD') + response = self.client.get(reverse('renew-book-librarian', kwargs={'pk': self.test_bookinstance1.pk})) + + # Check that it lets us login. We're a librarian, so we can view any users book + self.assertEqual(response.status_code, 200) + + def test_HTTP404_for_invalid_book_if_logged_in(self): + # unlikely UID to match our bookinstance! + test_uid = uuid.uuid4() + login = self.client.login(username='testuser2', password='2HJ1vRV0Z&3iD') + response = self.client.get(reverse('renew-book-librarian', kwargs={'pk':test_uid})) + self.assertEqual(response.status_code, 404) + + def test_uses_correct_template(self): + login = self.client.login(username='testuser2', password='2HJ1vRV0Z&3iD') + response = self.client.get(reverse('renew-book-librarian', kwargs={'pk': self.test_bookinstance1.pk})) + self.assertEqual(response.status_code, 200) + + # Check we used correct template + self.assertTemplateUsed(response, 'catalog/book_renew_librarian.html') +</pre> + +<p>Adicione o próximo método de teste, como mostrado abaixo. Isso verifica se a data inicial para o form é três semanas no futuro. Observe como podemos acessar o valor do valor inicial do campo do form (mostrado em negrito).</p> + +<pre class="brush: python notranslate"> def test_form_renewal_date_initially_has_date_three_weeks_in_future(self): + login = self.client.login(username='testuser2', password='2HJ1vRV0Z&3iD') + response = self.client.get(reverse('renew-book-librarian', kwargs={'pk': self.test_bookinstance1.pk})) + self.assertEqual(response.status_code, 200) + + date_3_weeks_in_future = datetime.date.today() + datetime.timedelta(weeks=3) + self.assertEqual(response<strong>.context['form'].initial['renewal_date']</strong>, date_3_weeks_in_future) +</pre> + +<div class="warning"> +<p>Se você usar a classe <em>form</em> <code>RenewBookModelForm(forms.ModelForm)</code> em vez da classe <code>RenewBookForm(forms.Form)</code>, então o nome do campo do <em>form</em> será <strong>'due_back' </strong>em vez de <strong>'renewal_date'</strong>.</p> +</div> + +<p>O próximo teste (adicione isso a classe também) verifica se a <em>view</em> redireciona para uma lista de todos livros emprestados, se a renovação for bem-sucedida. O que difere aqui é que pela primeira vez mostramos como você pode fazer <code>POST</code> de dados usando o cliente. Os dados do <em>post</em> são o segundo argumento da função <em>post</em>, e são especificados como um dicionário de chave/valores.</p> + +<pre class="brush: python notranslate"> def test_redirects_to_all_borrowed_book_list_on_success(self): + login = self.client.login(username='testuser2', password='2HJ1vRV0Z&3iD') + valid_date_in_future = datetime.date.today() + datetime.timedelta(weeks=2) + <strong>response = self.client.post(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}), {'renewal_date':valid_date_in_future})</strong> + self.assertRedirects(response, reverse('all-borrowed')) +</pre> + +<div class="warning"> +<p>A view <em>all-borrowed</em> foi adicionada como um <em>desafio</em>, e seu código pode, em vez disso, direcionar para a página inicial '/'. Nesse caso, modifique as últimas duas linhas do código de teste para que sejam como o código abaixo. O <code>follow=True</code> na solicitação, garante que a solicitação retorna a URL final de destino (portanto verifique <code>/catalog/</code> em vez de <code>/</code>).</p> + +<pre class="brush: python notranslate"> response = self.client.post(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}), {'renewal_date':valid_date_in_future}, <strong>follow=True</strong> ) + <strong>self.assertRedirects(</strong><strong>response, '/catalog/')</strong></pre> +</div> + +<p>Copie as última duas funções para a classe, como visto abaixo. Elas testam novamente as requisições <code>POST</code>, mas nesse caso, com datas inválidas de renovação. Utilizamos <code>assertFormError()</code> para verificar se as mensagens de erro são as esperadas.</p> + +<pre class="brush: python notranslate"> def test_form_invalid_renewal_date_past(self): + login = self.client.login(username='testuser2', password='2HJ1vRV0Z&3iD') + date_in_past = datetime.date.today() - datetime.timedelta(weeks=1) + response = self.client.post(reverse('renew-book-librarian', kwargs={'pk': self.test_bookinstance1.pk}), {'renewal_date': date_in_past}) + self.assertEqual(response.status_code, 200) + <strong>self.assertFormError(</strong><strong>response, 'form', 'renewal_date', 'Invalid date - renewal in past')</strong> + + def test_form_invalid_renewal_date_future(self): + login = self.client.login(username='testuser2', password='2HJ1vRV0Z&3iD') + invalid_date_in_future = datetime.date.today() + datetime.timedelta(weeks=5) + response = self.client.post(reverse('renew-book-librarian', kwargs={'pk': self.test_bookinstance1.pk}), {'renewal_date': invalid_date_in_future}) + self.assertEqual(response.status_code, 200) + <strong>self.assertFormError(</strong><strong>response, 'form', 'renewal_date', 'Invalid date - renewal more than 4 weeks ahead')</strong> +</pre> + +<p>Os mesmos tipos de técnicas podem ser usadas para testar a outra <em>view</em>.</p> + +<h3 id="Templates"><em>Templates</em></h3> + +<p>Django fornece APIs de teste para verificar se o template correto esta sendo chamado por suas views, e para permitir que você verifique se a informação correta está sendo enviada. Entretanto, não há suporte específico à API para testar no Django que sua saída HTML seja renderizada conforme esperado.</p> + +<h2 id="Outras_ferramentas_de_teste_recomendadas">Outras ferramentas de teste recomendadas</h2> + +<p>O framework de teste do Django pode ajudar você a escrever eficazes testes unitários e de integração — nós apenas arranhamos a superfície do que o framework <strong>unittest</strong> pode fazer, muito menos as adições de Django (por exemplo, confira como você pode usar <a href="https://docs.python.org/3.5/library/unittest.mock-examples.html">unittest.mock</a> para corrigir bibliotecas de terceiros para que você possa testar mais detalhadamente seu próprio código).</p> + +<p>Embora existam inúmeras outras ferramentas de teste que você pode utilizar, destacaremos apenas duas:</p> + +<ul> + <li><a href="http://coverage.readthedocs.io/en/latest/">Coverage</a>: Essa ferramenta Python reporta quando do seu código é realmente executado pelos seus testes. É particularmente útil quando você começando e está tentando descobrir o que exatamente deve testar.</li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Your_own_automation_environment">Selenium</a> é um framework para automatizar testes em um navegador real. Ele permite simular um usuário real interagindo com o site e fornece uma excelente estrutura para o sistema testar seu site (a próxima etapa do teste de integração).</li> +</ul> + +<h2 id="Desafie-se">Desafie-se</h2> + +<p>Existem muito mais <em>models</em> e <em>views</em> que podemos testar. Como uma tarefa simples, tente criar um caso de teste para a <em>view</em> <code>AuthorCreate</code>.</p> + +<pre class="brush: python notranslate">class AuthorCreate(PermissionRequiredMixin, CreateView): + model = Author + fields = '__all__' + initial = {'date_of_death':'12/10/2016'} + permission_required = 'catalog.can_mark_returned'</pre> + +<p>Lembre-se de que você precisa verificar qualquer coisa que você especificar ou que faça parte do projeto. Isso incluirá quem tem acesso, a data inicial, o <em>template</em> utilizado e para onde a view é redirecionada quando bem-sucedida.</p> + +<h2 id="Resumo">Resumo</h2> + +<p>Escrever código de teste não é divertido nem glamuroso, e é consequentemente muitas vezes deixado por último (ou nem isso) ao criar um site. No entanto, é uma parte essencial para garantir que seu código esteja seguro para <em>release</em> após fazer alterações e de baixo custo de manutenção.</p> + +<p>Neste tutorial, mostramos como escrever e executar testes para seus <em>models</em>, <em>forms</em> e <em>views</em>. Mais importante ainda, fornecemos um breve resumo do que você deve testar, que geralmente é a coisa mais difícil de resolver quando você está iniciando. Há muito mais para conhecer, mas mesmo com o que você já aprendeu, poderá criar testes unitários eficazes para seus websites.</p> + +<p>O próximo e último tutorial mostra como você pode implantar seu maravilhoso (e totalmente testado!) website Django.</p> + +<h2 id="Veja_também">Veja também</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.1/topics/testing/overview/">Escrevendo e executando testes</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.1/intro/tutorial05/">Escrevendo seu primeiro app Django, parte 5 > Introduzindo testes automatizados</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.1/topics/testing/tools/">Refererências de ferramentas de teste</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.1/topics/testing/advanced/">Tópicos avançados de testes</a> (Django docs)</li> + <li><a href="http://toastdriven.com/blog/2011/apr/10/guide-to-testing-in-django/">Um Guia para testes no Django</a> (Toast Driven Blog, 2011)</li> + <li><a href="http://test-driven-django-development.readthedocs.io/en/latest/index.html">Workshop: Desenvolvimento web Orientado a Testes com Django</a> (San Diego Python, 2014)</li> + <li><a href="https://realpython.com/blog/python/testing-in-django-part-1-best-practices-and-examples/">Testando no Django (Parte 1) - Melhores práticas e Exemplos</a> (RealPython, 2013)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Forms", "Learn/Server-side/Django/Deployment", "Learn/Server-side/Django")}}</p> + +<h2 id="Neste_módulo">Neste módulo</h2> + +<ul> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Introduction">Introdução ao Django</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/development_environment">Configurando um ambiente de desenvolvimento Django</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django: Website de uma Biblioteca Local</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/skeleton_website">Tutorial Django Parte 2: Criando a base do website</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Models">Tutorial Django Parte 3: Usando models</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Admin_site">Tutorial Django Parte 4: Django admin site</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Home_page">Tutorial Django Parte 5: Criando nossa página principal</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Generic_views">Tutorial Django Parte 6: Lista genérica e detail views</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Sessions">Tutorial Django Parte 7: Framework de Sessões</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Authentication">Tutorial Django Parte 8: Autenticação de Usuário e permissões</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Forms">Tutorial Django Parte 9: Trabalhando com formulários</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Testing">Tutorial Django Parte 10: Testando uma aplicação web Django</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Deployment">Tutorial Django Parte 11: Implantando Django em produção</a></li> + <li><a rel="nofollow" title="A página ainda não foi criada.">Segurança de aplicações web Django</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> diff --git a/files/pt-br/learn/server-side/django/tutorial_website_biblioteca_local/index.html b/files/pt-br/learn/server-side/django/tutorial_website_biblioteca_local/index.html new file mode 100644 index 0000000000..da69f5c9de --- /dev/null +++ b/files/pt-br/learn/server-side/django/tutorial_website_biblioteca_local/index.html @@ -0,0 +1,98 @@ +--- +title: 'Tutorial Django: Website da Biblioteca Local' +slug: Learn/Server-side/Django/Tutorial_website_biblioteca_local +tags: + - Artigo + - Guía + - Iniciante + - Tutorial + - django +translation_of: Learn/Server-side/Django/Tutorial_local_library_website +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/development_environment", "Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django")}}</div> + +<p class="summary">O primeiro artigo da nossa série de tutoriais práticos explica o que você irá aprender, e fornece uma visão do site de exemplo "biblioteca local" que estaremos trabalhando e evoluindo em artigos seguintes.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré-requisitos:</th> + <td>Ler a <a href="/pt-BR/docs/Learn/Server-side/Django/Introduction">introdução ao Django</a>. Para os próximos artigos você também necessitará ter montando o <a href="/pt-BR/docs/Learn/Server-side/Django/development_environment">ambiente de desenvolvimento</a> para o Django.</td> + </tr> + <tr> + <th scope="row">Objetivo:</th> + <td>Introduzir o exemplo da aplicação usado neste tutorial, e permitir que os leitores entendam quais tópicos serão abordados.</td> + </tr> + </tbody> +</table> + +<h2 id="Visão_geral">Visão geral</h2> + +<p>Bem vindo ao tutorial Django "Biblioteca Local" do MDN, no qual desenvolveremos um website que pode ser usado para gerenciar um catálogo para uma biblioteca local.</p> + +<p>Nessa série de artigos você irá:</p> + +<ul> + <li>Usar as ferramentas do Django para criar a estrutura de um website e aplicação.</li> + <li>Começar e parar o servidor de desenvolvimento.</li> + <li>Criar models para representar os dados da aplicação.</li> + <li>Usar o <em>admin</em> do Django para popular os dados do seu site.</li> + <li>Criar <em>views </em>para recuperar dados específicos em resposta a diferentes requisições, e <em>templates</em> para renderizar os dados como HTML para serem exibidos no navegador.</li> + <li>Criar <em>mappers</em> para associar diferentes padrões de URL com as<em>views</em> específicas.</li> + <li>Adicionar autorização de usuário e sessões para controlar o comportamento e acesso do site.</li> + <li>Trabalhar com formulários.</li> + <li>Criar teste de código para a sua aplicação.</li> + <li>Usar a segurança do Django de forma eficaz.</li> + <li>Implantar sua aplicação para produção. </li> +</ul> + +<p>Você já aprendeu alguns desses tópicos e passou brevemente por outros. Até o final dessa série de tutoriais você deve saber o suficiente para desenvolver uma aplicação simples em Django sozinho.</p> + +<h2 id="Website_da_Biblioteca_Local_-_LocalLibrary">Website da Biblioteca Local - LocalLibrary</h2> + +<p><em>LocalLibrary</em> é o nome do site que vamos criar e evoluir ao longo dessa série de tutoriais. Como seria de esperar, a proposta do site é fornecer um catálogo online para uma pequena biblioteca local, onde os usuários podem procurar por livros disponíveis e gerenciar suas contas.</p> + +<p>Esse exemplo foi cuidadosamente escolhido porque escalar para mostrar quanto detalhe precisamos, muito ou pouco, e pode ser usado para mostrar quase qualquer recurso do Django. Mais importante ainda, nos permite fornecer um caminho <em>guiado</em> através da funcionalidade mais importante do estrutura web do Django:</p> + +<ul> + <li>Nos primeiros tutoriais, vamos definir uma biblioteca simples de <em>navegação exclusiva</em> que os membros podem usar para procurar quais livros estão disponíveis. Isso nos permite explorar operações simples que são comuns para quase todos os sites: leitura e exibição de conteúdo de um banco de dados</li> + <li>Conforme formos progredindo, o exemplo da biblioteca irá (naturalmente) se estender para demonstrar recursos mais avançados do Django. Nós podemos expandir a biblioteca, por exemplo, para permitir que usuários reservem livros, e usar isto para demonstrar como usar formulários e suporte a autenticação de usuários.</li> +</ul> + +<p>Embora este seja um exemplo extenso, ele é chamado Biblioteca<strong> Local</strong> por uma razão - nós esperamos mostrar o mínimo de informação necessária para ajudar a desenvolver e executar uma aplicação com o Django rapidamente. Como resultado nós armazenaremos informações sobre livros, seus exemplares, autores e outras informações chave. Contudo, nós não armazenaremos informações sobre outros itens que uma biblioteca pode utilizar, ou fornecer a infraestrutura necessária para dar suporte a sites multi-biblioteca ou outros recursos do tipo "grande biblioteca".</p> + +<h2 id="Onde_posso_obter_o_código_fonte">Onde posso obter o código fonte?</h2> + +<p>Na medida em que você avança com o tutorial, nós forneceremos os fragmentos de código apropriados para que você possa copiá-los e colá-los em cada ponto. Também existirão outros códigos que você estenderá por conta própria (com alguma orientação).</p> + +<p>Se você travar, a versão completa do website pode ser encontrada<a href="https://github.com/mdn/django-locallibrary-tutorial"> aqui no Github</a>.</p> + +<h2 id="Resumo">Resumo</h2> + +<p>Agora que você sabe um pouco mais sobre o website <em>LocalLIbrary</em> e o que você irá aprender, é hora de começar a criar um <a href="/pt-BR/docs/Learn/Server-side/Django/skeleton_website">escopo do projeto</a>.</p> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/development_environment", "Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django")}}</p> + + + +<h2 id="Neste_módulo">Neste módulo</h2> + +<ul> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Introduction">Introdução ao Django</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/development_environment">Configurando um ambiente de desenvolvimento Django</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django: Website de uma Biblioteca Local</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/skeleton_website">Tutorial Django Parte 2: Criando a base do website</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Models">Tutorial Django Parte 3: Usando models</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Admin_site">Tutorial Django Parte 4: Django admin site</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Home_page">Tutorial Django Parte 5: Criando nossa página principal</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Generic_views">Tutorial Django Parte 6: Lista genérica e detail views</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Sessions">Tutorial Django Parte 7: Framework de Sessões</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Authentication">Tutorial Django Parte 8: Autenticação de Usuário e permissões</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Forms">Tutorial Django Parte 9: Trabalhando com formulários</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Testing">Tutorial Django Parte 10: Testando uma aplicação web Django</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Deployment">Tutorial Django Parte 11: Implantando Django em produção</a></li> + <li><a rel="nofollow" title="A página ainda não foi criada.">Segurança de aplicações web Django</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> diff --git a/files/pt-br/learn/server-side/django/web_application_security/index.html b/files/pt-br/learn/server-side/django/web_application_security/index.html new file mode 100644 index 0000000000..777a24a7cc --- /dev/null +++ b/files/pt-br/learn/server-side/django/web_application_security/index.html @@ -0,0 +1,187 @@ +--- +title: Segurança de aplicações web Django +slug: Learn/Server-side/Django/web_application_security +tags: + - Aprender + - Artigo + - Codificação + - Iniciante + - Programação server-side + - Python + - Segurança + - Segurança web + - django + - lado servidor (server-side) +translation_of: Learn/Server-side/Django/web_application_security +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Deployment", "Learn/Server-side/Django/django_assessment_blog", "Learn/Server-side/Django")}}</div> + +<p class="summary">Proteger dados do usuário é uma parte essencial de qualquer projeto de website. Anteriormente, explicamos algumas das ameaças de segurança mais comuns no artigo <a href="https://developer.mozilla.org/en-US/docs/Web/Security">Web security</a> — esse artigo fornece uma demonstração prática de como as proteções internas de Django lidam com essas ameaças.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré-requisitos:</th> + <td>Ler o tópico "<a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps/Website_security">Website security</a>" de Programação Server-side. Conclua os tópicos do tutorial Django tutorial até (e incluindo) pelos menos <a href="/en-US/docs/Learn/Server-side/Django/Forms">Tutorial Django Parte 9: Trabalhando com formulários</a>.</td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td>Para entender as principais coisas que você precisa fazer (ou não fazer) para proteger seu aplicatico web Django.</td> + </tr> + </tbody> +</table> + +<h2 id="Visão_geral">Visão geral</h2> + +<p>O tópico <a href="https://developer.mozilla.org/en-US/docs/Web/Security">Website security</a> fornece uma visão geral do que a segurança de website siginifica para o projeto server-side e algumas das ameaças mais comuns contra as quais você deve se proteger. Uma das mensagens chave nesse artigo é que quase todos os ataques são bem sucedidos quando a aplicação web confia nos dados do navegador.</p> + +<div class="warning"> +<p><strong>Importante:</strong> A lição mais importante que você pode aprender sobre segurança de website é <strong>nunca confiar nos dados do navegador</strong>. Isso inclui dados de requisição GET em parâmetros de URL, dados <code>POST</code>, cabeçalhos HTTP e cookies, arquivos enviados por usuários, etc. Sempre verifique e "desinfete" todos os dados recebidos. Sempre assuma o pior.</p> +</div> + +<p>A boa notícia para usuários Django é que muitas das ameaças mais comuns são tratadas pelo framework! O artigo <a href="https://docs.djangoproject.com/en/2.0/topics/security/">Segurança no Django</a> (Django docs) explica os recursos de segurança e como proteger um website desenvolvido pelo Django.</p> + +<h2 id="Ameaçasproteções_comuns">Ameaças/proteções comuns</h2> + +<p>Em vez de duplicar a documentação do Django aqui, neste artigo demonstraremos apenas alguns dos recursos de segurança no contexto do nosso tutorial Django da <a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a>.</p> + +<h3 id="Cross_site_scripting_XSS">Cross site scripting (XSS)</h3> + +<p>XSS é um termo utilizado para descrever uma classe de ataques que permitem um invasor injetar scripts no lado cliente, através do website, no navegador de outros usuários. Issi geralmente é conseguido armazenando scripts maliciosos no banco de dados onde eles podem ser recuperado e exibidos para outros usuários, ou fazendo com que usuários cliquem em um link que fará com que o JavaScript do invasor seja executado pelo navegador do usuário.</p> + +<p>O sistema de <em>templates</em> do Django protege você da maioria dos ataques XSS <a href="https://docs.djangoproject.com/en/2.0/ref/templates/language/#automatic-html-escaping">escapando de caracteres específicos</a> que são "perigosos" em HTML. Podemos demonstrar isso tentando injetar algum JavaScript em nosso website LocalLibrary usando o <em>form</em> Create-author que configuramos em <a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Parte 9: Trabalhando com formulários</a>.</p> + +<ol> + <li>Inicie o website usando o servidor de desenvolvimento (<code>python3 manage.py runserver</code>).</li> + <li>Abra o site em seu navegador local e faça login em sua conta de superusuário.</li> + <li>Navegue até a página de criação do autor (que deve estar na URL: <code><a href="http://127.0.0.1:8000/catalog/author/create/">http://127.0.0.1:8000/catalog/author/create/</a></code>).</li> + <li>Digite os nomes e os detalhes de data para um novo usuário, e então acrescente o seguinte texto no campo Last Name :<br> + <code><script>alert('Test alert');</script></code>.<br> + <img alt="Author Form XSS test" src="https://mdn.mozillademos.org/files/14305/author_create_form_alert_xss.png" style="border-style: solid; border-width: 1px; height: 245px; width: 594px;"> + <div class="note"> + <p><strong>Nota:</strong> Este é um script inofensivo que, se executado, exibirá uma caixa de alerta em seu navegador. Se o alerta é exibido quando você submeter o registro então o site está vulnerável a ameaças XSS.</p> + </div> + </li> + <li>Pressione <strong>Submit</strong> para salvar o registro.</li> + <li>Quando você salvar o autor, ele será exibido como mostrado abaixo. Por causa das proteções XSS o <code>alert()</code> não deve ser executado. Em vez disso o script é exibido como texto simples.<img alt="Author detail view XSS test" src="https://mdn.mozillademos.org/files/14307/author_detail_alert_xss.png" style="border-style: solid; border-width: 1px; height: 248px; width: 986px;"></li> +</ol> + +<p>Se você visualizar o código fonte da página HTML, poderá ver que os carcteres perigosos para as tags de script foram trasnformadoes em seus equivalentes de código de escape inofensivos (ex. <code>></code> agora é <code>&gt;</code>)</p> + +<pre class="brush: html notranslate"><h1>Author: Boon&lt;script&gt;alert(&#39;Test alert&#39;);&lt;/script&gt;, David (Boonie) </h1> +</pre> + +<p>Usar templates Django protege você contra a maioria dos ataques de XSS. No entanto, é possível desativar esta proteção, e a proteção não é automaticamente aplicada a todas as tags que normalmente não seriam preenchidas pela entrada do usuário (por exemplo, o <code>help_text</code> em um campo de formulário normalmente não é preechido pelo usuário, então Django não escapa esses valores).</p> + +<p>Também é possível que os ataques XSS se originem de outra fonte de dados não confiável, como cookies, webservices ou upload de arquivos (sempre que os dados não forem suficientemente limpos antes de serem incluídos em uma página). Se estiver exibindo dados dessas fontes, então pode ser necessário adicionar seu próprio código de limpeza.</p> + +<h3 id="Proteção_contra_Cross_site_request_forgery_CSRF">Proteção contra Cross site request forgery (CSRF) </h3> + +<p>Ataques CSRF permitem que um usuário malicioso execute ações usando as credenciais de outro usuário sem o conhecimento ou consentimento desse usuário. Por exemplo, considere o caso em que temos um hacker que quer criar autores adicionais para nossa LocalLibrary.</p> + +<div class="note"> +<p><strong>Nota:</strong> Obviamente nosso hacker não está nisso por dinheiro! Um hacker mais ambicioso poderia usar a mesma abordagem em outros sites para realizar tarefas muito mais prejudiciais (ex. transferir dinheiro para suas prórpias contas, etc.)</p> +</div> + +<p>Para fazer isso, eles podem criar um arquivo HTML como o abaixo, que contém um form de criação de autor (como o que usamos na seção anterior) que é enviado assim que o arquivo é carregado. Eles então enviariam o arquivo para todos os bibliotecários e sugeririam que eles abrissem o arquivo (ele contém algumas informações inofensivas, honestamente!). Se o arquivo for aberto por qualquer bibliotecário logado, o formulário será enviado com suas credenciais e um novo autor será criado.</p> + +<pre class="brush: html notranslate"><html> +<body onload='document.EvilForm.submit()'> + +<form action="http://127.0.0.1:8000/catalog/author/create/" method="post" name='EvilForm'> + <table> + <tr><th><label for="id_first_name">First name:</label></th><td><input id="id_first_name" maxlength="100" name="first_name" type="text" value="Mad" required /></td></tr> + <tr><th><label for="id_last_name">Last name:</label></th><td><input id="id_last_name" maxlength="100" name="last_name" type="text" value="Man" required /></td></tr> + <tr><th><label for="id_date_of_birth">Date of birth:</label></th><td><input id="id_date_of_birth" name="date_of_birth" type="text" /></td></tr> + <tr><th><label for="id_date_of_death">Died:</label></th><td><input id="id_date_of_death" name="date_of_death" type="text" value="12/10/2016" /></td></tr> + </table> + <input type="submit" value="Submit" /> +</form> + +</body> +</html> +</pre> + +<p>Execute o servidor web de desenvolvimento e faça login com a conta de superusuário. Copie o texto acima em um arquivo e abra-o no navegado. Você deve obter um erro de CSRF, porque Django tem protteção contra esse tipo de coisa!</p> + +<p>A forma como a proteção é habilitada é incluindo a tag de template <code>{% csrf_token %}</code> em sua definição de formulário. Esse token é então renderizado em seu HTML como mostrado abaixo com um valor que é específico para o usuário no navegador atual.</p> + +<pre class="brush: html notranslate"><input type='hidden' name='csrfmiddlewaretoken' value='0QRWHnYVg776y2l66mcvZqp8alrv4lb8S8lZ4ZJUWGZFA5VHrVfL2mpH29YZ39PW' /> +</pre> + +<p>Django gera uma chave específica de usuário/navegador e irá rejeitar formulários que não contenham o campo, ou que contenham um valor de campo incorreto para o usuário/navegador.</p> + +<p>Para usar esse tipo de ataque o hacker agora precisa descobrir e incluir a chave CSRF para o usuário alvo específico. Eles também não podem usar a abordagem "scattergun" de enviar um arquivo malicioso para todos bibliotecários e esperar que um deles abra, já que a chave CSRF é específica do navegador.</p> + +<p>A proteção CSRF do Django é ativada por padrão. Você deve sempre usar a tag de template <code>{% csrf_token %}</code> em seus formulários e utilizar <code>POST</code> para requisições que podem alterar ou adicionar dados ao banco de dados.</p> + +<h3 id="Outras_proteções">Outras proteções</h3> + +<p>Django also provides other forms of protection (most of which would be hard or not particularly useful to demonstrate):</p> + +<dl> + <dt>Proteção contra Injeção de SQL</dt> + <dd>As vulnerabilidades de injeção de SQL (SQL injection) permitem usuários mal-intencionados executarem código SQL arbitrário em um banco de dados, permitindo que dados sejam acessados, modificados ou apagados independentemente das permissões do usuário. Em quase todos os casos você acessará o banco de dados usando querysets/models do Django, de mdo que o SQL resultante será devidamente escapado pelo driver de banco de dados subjacente. Se você precisa escrever consultas brutas ou SQL customizado precisará pensar explicitamente sobre como previnir injeção de SQL.</dd> + <dt>Proteção contra Clickjacking </dt> + <dd>Nesse ataque, um usuário malicioso sequestra clicks destinados a um site de visível no nível superior e os encaminha para uma página oculta abaixo. Essa técnica pode ser usada, por exemplo, para exibir um site de banco legítimo, mas capturar as credenciais de login em um <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe" title="The HTML Inline Frame Element (<iframe>) represents a nested browsing context, effectively embedding another HTML page into the current page. In HTML 4.01, a document may contain a head and a body or a head and a frameset, but not both a body and a frameset. However, an <iframe> can be used within a normal document body. Each browsing context has its own session history and active document. The browsing context that contains the embedded content is called the parent browsing context. The top-level browsing context (which has no parent) is typically the browser window."><code><iframe></code></a> invisível, controlado pelo atacante. O Django possui <a href="https://docs.djangoproject.com/en/2.0/ref/clickjacking/#clickjacking-prevention">proteção contra clickjacking</a> na forma do <a href="https://docs.djangoproject.com/en/2.0/ref/middleware/#django.middleware.clickjacking.XFrameOptionsMiddleware" title="django.middleware.clickjacking.XFrameOptionsMiddleware"><code>X-Frame-Options middleware</code></a> que, em um navegador de suporte, pode impedir que um site seja renderizado dentro de um frame.</dd> + <dt>Aplicação de SSL/HTTPS</dt> + <dd>SSL/HTTPS pode ser habilitado no servidor web para criptografar todo o tráfego entre o site e o navegador, incluindo credenciais de autenticação que seriam enviadas em texto simples (habilitar HTTPS é altamente recomendado). Se HTTPS estiver habilitado o Django fornece uma série de outras proteções que você pode utilizar:</dd> +</dl> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-SECURE_PROXY_SSL_HEADER"><code>SECURE_PROXY_SSL_HEADER</code></a> pode ser utilizado para verificar se o conteúdo é seguro, mesmo se for recebido de um proxy não HTTP.</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-SECURE_SSL_REDIRECT"><code>SECURE_SSL_REDIRECT</code></a> é usado para redirecionar todas as requisições HTTP para HTTPS.</li> + <li>Usar <a href="https://docs.djangoproject.com/en/2.0/ref/middleware/#http-strict-transport-security">HTTP Strict Transport Security</a> (HSTS). Este é um cabeçalho HTTP que informa ao navegador que todas as conexões futuras com um determinado site devem sempre utilizar HTTPS. Combinada com o redirecionamento de requisições HTTP para HTTPS, essa configuração garante que HTTPS é sempre usado depois que uma conexão bem-sucedida ocorrer. HSTS pode ser configurado com <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-SECURE_HSTS_SECONDS"><code>SECURE_HSTS_SECONDS</code></a> e <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-SECURE_HSTS_INCLUDE_SUBDOMAINS"><code>SECURE_HSTS_INCLUDE_SUBDOMAINS</code></a> ou no servidor web.</li> + <li>Usar cookies "seguros" definindo <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-SESSION_COOKIE_SECURE"><code>SESSION_COOKIE_SECURE</code></a> e <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-CSRF_COOKIE_SECURE"><code>CSRF_COOKIE_SECURE</code></a> como <code>True</code>. Isso garantirá que os cookies sejam enviados apenas por HTTPS.</li> +</ul> + +<dl> + <dt>Validação de cabeçalho de host</dt> + <dd>Usar <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-ALLOWED_HOSTS"><code>ALLOWED_HOSTS</code></a> para aceitar apenas requisições de hosts confiáveis.</dd> +</dl> + +<p>Existem muitas outras proteções, e ressalvas para o uso dos mecanismos acima. Embora esperamos que isso tenha dado a você uma visão geral do que o Django oferece, você ainda deve ler a documentação de segurança de Django.</p> + +<ul> +</ul> + +<h2 id="Resumo">Resumo</h2> + +<p>Django tem proteções eficazes contra uma série de ameaças comuns, incluindo ataques XSS e CSRF. Neste artigo demonstramos como essas ameaças específicas são tratadas pelo Django em nosso website <em>LocalLibrary</em>. Também fornecemos uma breve visão geral de algumas das outras proteções.</p> + +<p>Esta foi uma incursão muito breve em segurança web. Nós recomendamos fortemente que você leia <a href="https://docs.djangoproject.com/en/2.0/topics/security/">Segurança no Django</a> para obter um entendimento mais profundo.</p> + +<p>A próxima e última etapa neste módulo sobre Django é concluir a <a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">tarefa de avaliação</a>.</p> + +<h2 id="Veja_também">Veja também</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.0/topics/security/">Segurança no Django</a> (Django docs)</li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/Security">Segurança de website no lado do servidor</a> (MDN)</li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/Security">Segurança web</a> (MDN)</li> + <li><a href="/en-US/docs/Web/Security/Securing_your_site">Protegendo seu site</a> (MDN)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Deployment", "Learn/Server-side/Django/django_assessment_blog", "Learn/Server-side/Django")}}</p> + +<h2 id="Neste_módulo">Neste módulo</h2> + +<ul> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Introduction">Introdução ao Django</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/development_environment">Configurando um ambiente de desenvolvimento Django</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Tutorial_local_library_website">Tutorial Django: Website de uma Biblioteca Local</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/skeleton_website">Tutorial Django Parte 2: Criando a base do website</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Models">Tutorial Django Parte 3: Usando models</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Admin_site">Tutorial Django Parte 4: Django admin site</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Home_page">Tutorial Django Parte 5: Criando nossa página principal</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Generic_views">Tutorial Django Parte 6: Lista genérica e detail views</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Sessions">Tutorial Django Parte 7: Framework de Sessões</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Authentication">Tutorial Django Parte 8: Autenticação de Usuário e permissões</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Forms">Tutorial Django Parte 9: Trabalhando com formulários</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Testing">Tutorial Django Parte 10: Testando uma aplicação web Django</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/Deployment">Tutorial Django Parte 11: Implantando Django em produção</a></li> + <li><a rel="nofollow" title="A página ainda não foi criada.">Segurança de aplicações web Django</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> diff --git a/files/pt-br/learn/server-side/express_nodejs/ambiente_de_desenvolvimento/index.html b/files/pt-br/learn/server-side/express_nodejs/ambiente_de_desenvolvimento/index.html new file mode 100644 index 0000000000..289af21dde --- /dev/null +++ b/files/pt-br/learn/server-side/express_nodejs/ambiente_de_desenvolvimento/index.html @@ -0,0 +1,387 @@ +--- +title: Configurando o Node como ambiente de desenvolvimento +slug: Learn/Server-side/Express_Nodejs/ambiente_de_desenvolvimento +tags: + - Express + - Iniciante + - Introdução + - Node + - nodejs + - npm + - server-side + - web server +translation_of: Learn/Server-side/Express_Nodejs/development_environment +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Introduction", "Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs")}}</div> + +<p class="summary">Agora que você sabe para que serve o Express, nós vamos lhe mostrar como configurar e testar o ambiente Node/Express no Windows, Linux (Ubuntu) e macOS. Independentemente do sistema operacional que você prefere, este artigo deve lhe proporcionar o que você precisa para desenvolver aplicativos em Express.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré-Requisitos:</th> + <td>Saber como abrir um terminal/linha de comando. Saber como instalar pacotes de software no sistema operacional do computador utilizado para desenvolvimento</td> + </tr> + <tr> + <th scope="row">Objetivo:</th> + <td>Configurar o ambiente de desenvolvimento para Express (X.XX) em seu computador</td> + </tr> + </tbody> +</table> + +<h2 id="Visão_geral_do_ambiente_de_desenvolvimento_do_Express">Visão geral do ambiente de desenvolvimento do Express</h2> + +<p><em>Node</em> e <em>Express </em>facilitam a configuração de seu computador para começar a desenvolver aplicações web. Esta seção fornece uma visão ampla de quais ferramentas serão necessárias, explica alguns métodos simples para instalar o Node (e Express) no Ubuntu, macOS e Windows e também mostra como você pode testar sua aplicação.</p> + +<h3 id="O_que_é_o_ambiente_de_desenvolvimento_Express">O que é o ambiente de desenvolvimento Express?</h3> + +<p>O ambiente de desenvolvimento <em>Express</em> inclui uma instalação do <em>Nodejs, </em>o pacote de gerenciamento<em> NPM </em>e (opcionalmente) o <em>Gerador de Aplicações Express </em>em seu computador local.</p> + +<p>O <em>Node </em>e o <em>NPM </em>são instalados em conjunto por meio de um pacote binário preparado, instaladores, pacotes de gerenciamento de sistemas operacionais ou diretamente da fonte (como mostra a seção seguinte). O <em>Express </em>é então instalado pelo NPM como uma dependência de sua aplicação web <em>Express </em>individual (junto a outras bibliotecas como motores de modelo, drivers de banco de dados, autenticações middleware, middleware para arquivos estáticos, etc.)</p> + +<p>NPM também pode ser utilizado para instalar (globalmente) o Express Application Generator, uma ferramenta que cria um "esqueleto" de um app Express, seguindo o padrão MVC. O gerador de app é opcional porque você não precisa dessa ferramenta para criar um app ou um construtor Express para ter a mesma arquitetura. Nós vamos usá-lo nesta seção porque nos permite iniciar uma aplicação de uma maneira mais rápida e promover uma estrutura modular.</p> + +<div class="note"> +<p><strong>Nota:</strong> Ao contrário de muitos outros framework que não oferecem um servidor web junto ao ambiente de desenvolvimento, o Node/Express cria e roda o seu próprio servidor web.</p> +</div> + +<p>Há outras ferramentas periféricas que integram o ambiente de desenvolvimento, é o caso dos editores de textos (códigos), conhecidos como IDE, e versionadores de códigos, como o Git, que ajudam a gerenciar diferentes versões do código. Estamos partindo da ideia de que você já conhece essas ferramentas e as têm instaladas (em especial o editor de texto).</p> + +<h3 id="Quais_sistemas_operacionais_têm_suporte">Quais sistemas operacionais têm suporte?</h3> + +<p><em>Node</em> roda em Windows, macOS, diferentes versões do Linux, Docker, etc. Há uma lista de sistemas suportados que pode ser encontrada na página de <a href="https://nodejs.org/en/download/">Downloads</a> do Nodejs. Quase todos os computadores pessoais têm o que é necessário para rodar o Node. O Express roda no ambiente Node e, consequentemente, roda em qualquer plataforma que roda o <em>Node</em>.</p> + +<p>Neste artigo, vamos abordar as instruções de configuração para Windows, macOS, e Ubuntu Linux.</p> + +<h3 id="Qual_versão_do_NodeExpress_você_deve_usar">Qual versão do Node/Express você deve usar?</h3> + +<p>Há várias <a href="https://nodejs.org/en/blog/release/">versões do Node</a> - as mais recentes contém correção de bugs, suporte para EMCAScript (JavaScript) e melhorias nas APIs do Node.</p> + +<p>De maneira geral, você deve usar a versão mais recente do LTS (long-term supported), pois é a mais estável do que a versão "current". Além disso, você deve usar a versão current apenas se precisar de alguma funcionalidade que não está presente na versão LTS.</p> + +<p>Para o Express, você deve usar sempre a versão mais completa.</p> + +<h3 id="Sobre_o_banco_de_dados_e_outras_dependências">Sobre o banco de dados e outras dependências?</h3> + +<p>Outras dependências, como database drivers, engine para templates, ferramentas para autenticação, etc, são parte da aplicação e são importadas para o ambiente a partir do NPM. Nós vamos falar sobre essa parte mais para frente.</p> + +<h2 id="Instalando_o_Node">Instalando o Node</h2> + +<p>Para utilizar o Express, você terá que instalar o Nodejs e o <a href="https://docs.npmjs.com/">NPM</a> em seu sistema operacional. Nas seções a seguir, vamos explicar o jeito mais fácil de instalar a versão LTS do Nodejs no Ubuntu Linux 16.04, macOS e Windows 10.</p> + +<div class="note"> +<p><strong>Dica:</strong> As seções abaixo mostram o jeito mais fácil de instalar o NPM nos Sistemas Operacionais. Se você utilizar outro sistema ou quer ver uma abordagem diferente para as plataformas atuais acesse <a href="https://nodejs.org/en/download/package-manager/">Instalando Node.js via NPM</a> (nodejs.org).</p> +</div> + +<h3 id="Windows_e_macOS">Windows e macOS</h3> + +<p>Instalar o Node e o NPM no Windows ou no macOS é uma tarefa rápida e simples. Siga os seguintes passos:</p> + +<ol> + <li>Baixar o instalador: + <ol> + <li>Vá para <a href="https://nodejs.org/en/">https://nodejs.org/en/</a></li> + <li>Selecione o botão de download da versão LTS, que é a recomendada para a maioria dos usuários.</li> + </ol> + </li> + <li>Instale o Node ao clicar duas vezes no arquivo de download. Siga a instalação a partir das janelas que vão aparecer na sua tela.</li> +</ol> + +<h3 id="Ubuntu_16.04">Ubuntu 16.04</h3> + +<p>O jeito mais fácil de instalar a versão LTS do Node é usar o NPM a partir do Ubuntu <em>binary distributions repository</em>. Isso pode ser feito de uma maneira muito simples. Rode os seguintes comandos no seu terminal.</p> + +<pre class="brush: bash notranslate"><code>curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - +sudo apt-get install -y nodejs</code> +</pre> + +<div class="warning"> +<p><strong>Atenção:</strong> Não faça a instalação direto do repositório normal do Ubuntu pois ele contém versões antigas do Node.</p> +</div> + +<ol> +</ol> + +<h3 id="Testando_a_instalação_do_Nodejs_e_do_NPM">Testando a instalação do Nodejs e do NPM</h3> + +<p>O jeito mais fácil de testar se tudo correu bem na instalação é checar qual a versão do Node está rodando no computador. Para isso, vá ao terminal/command prompt e digite o seguinte comando para retornar a resposta com a versão mais recente.</p> + +<pre class="brush: bash notranslate">>node -v +v8.9.4</pre> + +<p>O <em>NPM</em> também deve ter sido instalado. Você pode checar da seguinte maneira:</p> + +<pre class="brush: bash notranslate">>npm -v +5.6.0</pre> + +<p>Uma maneira um pouco mais divertida de testar é criar um servidor web em "puro node". Vamos imprimir a tradicional frase "Hello World" no browser quando visitarmos uma determinada URL.</p> + +<ol> + <li>Crie um arquivo chamado hellonode.js e cole dentro dele o código abaixo. Estamos usando apenas o Node, sem o Express, e com sintaxe do ES6. + <pre class="brush: js notranslate">//Chame o módulo HTTP +var http = require("http"); + +//Crie um servidor HTTP para ouvir as requisições na porta 8000 +http.createServer(function (request, response) { + + // Configure o resposta HTTP header com o HTTP status e Content type + response.writeHead(200, {'Content-Type': 'text/plain'}); + + // Envie a resposta do body "Hello World" + response.end('Hello World\n'); +}).listen(8000); + +// Imprima URL para acessar o servidor +console.log('Server running at http://127.0.0.1:8000/') +</pre> + + <p>O código importa o módulo "http" e o utiliza para criar um servidor (<code>createServer()</code>) que escuta as requisições HTTP na porta 8000. O script, então, imprime a mensagem no console. A função <code>createServer()</code> recebe como argumento uma função callback que é chamada quando recebe uma requisição HTTP - isso retorna uma resposta com um status 200 ("OK") do HTTP e o texto "Hello World".</p> + </li> + <li> + <div class="note"> + <p><strong>Nota:</strong> Não se preocupe se você não entendeu exatamente o que esse código faz. Nós vamos explicar isso em mais detalhes quando iniciarmos a parte do Express.</p> + </div> + </li> + <li>Inicie o servidor e navegue pelo mesmo diretório que o seu arquivo hellonode.js no terminal. Depois chame o Node da seguinte forma: + <pre class="brush: bash notranslate">>node hellonode.js +Server running at http://127.0.0.1:8000/ +</pre> + </li> + <li>Navegue até a URL (<a href="http://127.0.0.1:8000/">http://127.0.0.1:8000/</a>). Se tudo estiver funcionando bem, o browser vai apresentar a frase "Hello World".</li> +</ol> + +<h2 id="Usando_o_NPM">Usando o NPM</h2> + +<p>Ao lado do próprio Node, o NPM é a ferramenta de trabalho mais importante nas aplicações Node. O NPM é usado para buscar qualquer pacote (biblioteca JavaScript) que uma aplicação precisa para ser desenvolvida, testada ou produzida, além de ser adotado para rodar testes ao longo de todo o processo de desenvolvimento.</p> + +<div class="note"> +<p><strong>Nota:</strong> A partir da perspectiva do Node, Express é um pacote que precisa ser instalado utilizando o NPM e depois importado para o seu código.</p> +</div> + +<p>Você pode usar o NPM separadamente para buscar cada pacote desejado. Em geral, nós gerenciamos as dependências com um arquivo chamado <a href="https://docs.npmjs.com/files/package.json">package.json</a>. Esse arquivo lista todas as dependências para um pacote JavaScript específico, incluindo o nome do pacote, a versão, descrição, arquivo de inicialização, produção de dependências, desenvolvimento de dependências, versões do Node que podem ser utilizadas. O <strong>package.json</strong> contém tudo que o NPM precisa para buscar e rodar a sua aplicação (se você está escrevendo uma biblioteca para ser reutilizável, você pode usar essa definição para fazer o upload do pacote para o repositório npm e deixá-lo acessível a qualquer usuário).</p> + +<h3 id="Adicionando_dependências">Adicionando dependências</h3> + +<p>Os passos seguintes mostram como baixar pacotes via NPM, salvá-los nas dependências do projeto e importá-los/chamá-los para dentro da aplicação Node.</p> + +<div class="note"> +<p><strong>Nota:</strong> Nesta seção mostraremos como buscar e instalar o pacote do Express. Depois, explicaremos como esse e outros pacotes já estão especificados para nós graças ao <em>Express Application Generator</em>. É muito importante entendermos como o NPM funciona e o que é criado com o generator. </p> +</div> + +<ol> + <li>Primeiro passo é criar um diretório para sua aplicação. No prompt, insira os comandos a seguir. + <pre class="brush: bash notranslate">mkdir myapp +cd myapp</pre> + </li> + <li> Use o comando <code>npm init</code> para criar o arquivo <strong>package.json</strong> da sua aplicação. Esse comando registra para você uma série de informações, como o nome e a versão do seu aplicativo, além do nome do seu "entry point" (<strong>index.js</strong> por padrão). Por hora, vamos manter a configuração padrão. + <pre class="brush: bash notranslate">npm init</pre> + + <p>Se você acessar o arquivo <strong>package.json</strong> (<code>cat packge.json</code>), você verá toda a configuração padrão e, ao final, o tipo de licença que o app está utilizando.</p> + + <pre class="brush: json notranslate">{ + "name": "myapp", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} +</pre> + </li> + <li>Agora, instale o Express dentro do diretório <strong>myapp</strong>. O pacote será salvo automaticamente na lista de dependências do seu <strong>package.json</strong>.</li> + <li> + <pre class="brush: bash notranslate">npm install express</pre> + + <p>A lista de dependências do <strong>package.json</strong> agora mostra também a versão do Express que estamos usando. Está grifada no final do arquivo.</p> + + <pre class="brush: json notranslate">{ + "name": "myapp", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", +<strong> "dependencies": { + "express": "^4.16.2" + }</strong> +} +</pre> + </li> + <li>Para usar o Express, é preciso incluir a função <code>require()</code> no arquivo index.js dentro da sua aplicação. Crie esse arquivo agora mesmo na pasta raiz "<strong>myapp</strong>" e inclua o código a seguir. + <pre class="notranslate"><code><strong>var express = require('express')</strong> +var app = express() + +app.get('/', function (req, res) { + res.send('Hello World!') +}) + +app.listen(</code>8000<code>, function () { + console.log('Example app listening on port </code>8000<code>!') +})</code> +</pre> + + <p>O código mostra uma aplicação web bem simples cujo objetivo único é imprimir a mensagem "HelloWorld". Em linhas gerais, esse arquivo importa o módulo do express e o utiliza para criar um servidor (<code>app</code>) que escuta as requisições HTTP pela porta 8000 e imprime a mensagem no console, além de definir qual URL usada para testar o servidor. A função <code>app.get()</code> responde apenas às requisições HTTP feitas com o método GET, desde que especificadas com o path ('/'). Nesse caso, chamando a função para enviar a mensagem <em>Hello World</em>!</p> + </li> + <li>Rode a linha de comando abaixo para iniciar o servidor. + <pre class="brush: bash notranslate">>node index.js +Example app listening on port 8000 +</pre> + </li> + <li>Vá para a seguinte URL (<a href="http://127.0.0.1:8000/">http://127.0.0.1:8000/</a>). Se tudo estiver funcionando corretamente, o browser vai mostrar a mensagem "Hello World!".</li> +</ol> + +<h3 id="Desenvolvendo_dependências">Desenvolvendo dependências</h3> + +<p>Se você utilizar uma dependência apenas durante o desenvolvimento da aplicação, é recomendado que você a salve como uma "development dependency". Dessa forma, o pacote não será utilizado no ambiente de produção. Por exemplo: caso utilizar o pacote <a href="http://eslint.org/">esling</a> (JavaScript Linting), você faria a instalação via NPM da seguinte forma.</p> + +<pre class="brush: bash notranslate"><code>npm install eslint --save-dev</code></pre> + +<p>Assim, a esling vai aparecer da seguinte forma na lista de dependências do <strong>package.json</strong>.</p> + +<pre class="brush: js notranslate"> "devDependencies": { + "eslint": "^4.12.1" + } +</pre> + +<div class="note"> +<p><strong>Note:</strong> "<a href="https://en.wikipedia.org/wiki/Lint_(software)">Linters</a>" são ferramentas que nos ajudam a identificar e reportar que o código está sendo escrito dentro das melhores práticas.</p> +</div> + +<h3 id="Rodando_tarefas">Rodando tarefas</h3> + +<p>Além de definir e buscar dependências, você também pode nomear scripts dentro do seu arquivo <strong>package.json</strong> e chamar o NPM para executá-lo a partir de um <a href="https://docs.npmjs.com/cli/run-script">run-script</a> command. Essa abordagem é comum para automatizar testes e tarefas ao longo do desenvolvimento (por exemplo: minificar o JavaScript, reduzir imagens, LINT/análise de códigos, etc).</p> + +<div class="note"> +<p><strong>Nota:</strong> Ferramentas de automação de tarefas como o <a href="http://gulpjs.com/">Gulp</a> e o <a href="http://gruntjs.com/">Grunt</a> também podem ser utilizados, além de outros pacotes externos. </p> +</div> + +<p>Para definir o script que roda o <em>esling</em>, citado na seção acima, nós precisamos adicionar o seguinte bloco no nosso <strong>package.json</strong> (importante: sua aplicação precisa ter como source está na pasta /src/js):</p> + +<pre class="brush: js notranslate">"scripts": { + ... + "lint": "eslint src/js" + ... +} +</pre> + +<p>Explicando um pouco mais: <code>eslint src/js</code> é o comando que colocamos no nosso terminal para rodar o <code>eslint</code> nos arquivos JavaScript situados no diretório <code>src/js</code> dentro do diretório do nosso app. Incluindo o comando, criamos o comando de atalho - <code>lint</code>.</p> + +<pre class="brush: bash notranslate"><code>npm run-script lint +# OR (using the alias) +npm run lint</code> +</pre> + +<p>O exemplo pode não parecer mais curto do que o comando original, mas com o que você aprendeu é possível incluir comandos bem maiores dentro do npm scripts, como as cadeias de múltiplos comandos. Você pode até escrever um único script npm para rodar todos os seus testes de uma só vez.</p> + +<h2 id="Instalando_o_Express_Application_Generator">Instalando o Express Application Generator</h2> + +<p>O <a href="https://expressjs.com/en/starter/generator.html">Express Application Generator</a> é uma ferramenta que cria "esqueleto" para aplicações Express. A instalação é realizada via NPM como mostrada a seguir (o comando <code>-g</code> instala a pacote globalmente, ou seja, você pode acessá-lo de qualquer lugar do seu computador).</p> + +<pre class="notranslate"><code>npm install express-generator -g</code></pre> + +<p>Para criar um aplicativo Express chamado "helloworld" com as configurações padrões, vá até o local/pasta em que você deseja desenvolver o projeto e escreva a seguinte linha de comando:</p> + +<pre class="brush: bash notranslate">express helloworld</pre> + +<div class="note"> +<p>Nota: Você também pode definir a biblioteca de template que pretende usar e muitas outras configurações. Use o comando <code>help</code> para ver todas as opções. </p> + +<pre class="brush: bash notranslate">express --help +</pre> +</div> + +<p>O NPM vai criar um novo aplicativo Express em uma subpasta na localização em que você está. O progresso será apresentado no console. Para finalizar, o processo, a ferramenta mostrará os comandos que você precisa seguir para instalar a dependência Node e iniciar o seu app.</p> + +<div class="note"> +<p>O novo app terá um arquivo package.json no diretório raiz. Você pode abrir esse arquivo para checar o que foi instalado, incluindo o Express e Jade (template library) .</p> + +<pre class="brush: js notranslate">{ + "name": "helloworld", + "version": "0.0.0", + "private": true, + "scripts": { + "start": "node ./bin/www" + }, + "dependencies": { + "body-parser": "~1.18.2", + "cookie-parser": "~1.4.3", + "debug": "~2.6.9", + "express": "~4.15.5", + "jade": "~1.11.0", + "morgan": "~1.9.0", + "serve-favicon": "~2.4.5" + } +}</pre> +</div> + +<p>Instale todas as dependências para o app helloworld com o NPM, de acordo com os comandos abaixo:</p> + +<pre class="brush: bash notranslate">cd helloworld +npm install +</pre> + +<p>Agora, rode o aplicativo (o comando muda um pouco entre Windows, Linux/macOS), como está no código a seguir:</p> + +<pre class="brush: bash notranslate"># Rode o helloworld no Windows +SET DEBUG=helloworld:* & npm start + +# Rode helloworld no Linux/macOS +DEBUG=helloworld:* npm start +</pre> + +<p>O comando DEBUG gera um loggin bem útil, apresentando resultados, como abaixo:</p> + +<pre class="brush: bash notranslate">>SET DEBUG=helloworld:* & npm start + +> helloworld@0.0.0 start D:\Github\expresstests\helloworld +> node ./bin/www + + helloworld:server Listening on port 3000 +0ms</pre> + +<p>Abre um browser e navegue para <a href="http://127.0.0.1:3000/">http://127.0.0.1:3000/</a> e veja a página default apresentada pelo aplicativo.</p> + +<p><img alt="Express - Generated App Default Screen" src="https://mdn.mozillademos.org/files/14331/express_default_screen.png" style="border-style: solid; border-width: 1px; display: block; height: 301px; margin: 0px auto; width: 675px;"></p> + +<p>Vamos falar mais sobre o "gerador" quando chegarmos ao artigo referente à geração de esqueletos de uma aplicação.</p> + +<ul> +</ul> + +<h2 id="Sumário">Sumário</h2> + +<p>Agora você tem o desenvolvimento do Node pronto para rodar no seu computador e que pode ser utilizado para criar aplicações web com o framework Express. Você também viu como o NPM é utilizado para importar o Express em sua aplicação e como criar um esqueleto a partir do Express Aplication Generator.</p> + +<p>No próximo artigo, nós vamos iniciar um tutorial para construir uma aplicação web completa utilizando esse ambiente junto com as ferramentas.</p> + +<h2 id="Veja_também">Veja também</h2> + +<ul> + <li><a href="https://nodejs.org/en/download/">Downloads</a> página (nodejs.org)</li> + <li><a href="https://nodejs.org/en/download/package-manager/">Installing Node.js via package manager</a> (nodejs.org)</li> + <li><a href="http://expressjs.com/en/starter/installing.html">Installing Express</a> (expressjs.com)</li> + <li><a href="https://expressjs.com/en/starter/generator.html">Express Application Generator</a> (expressjs.com)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Introduction", "Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs")}}</p> + +<h2 id="Outros_módulos">Outros módulos</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Setting up a Node (Express) development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li> +</ul> diff --git a/files/pt-br/learn/server-side/express_nodejs/deployment/index.html b/files/pt-br/learn/server-side/express_nodejs/deployment/index.html new file mode 100644 index 0000000000..77e9914e87 --- /dev/null +++ b/files/pt-br/learn/server-side/express_nodejs/deployment/index.html @@ -0,0 +1,527 @@ +--- +title: 'Express Tutorial Part 7: Deploying to production' +slug: Learn/Server-side/Express_Nodejs/deployment +tags: + - Express + - Implantação + - Iniciante + - Node + - aprendizado + - heroku +translation_of: Learn/Server-side/Express_Nodejs/deployment +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenu("Learn/Server-side/Express_Nodejs/forms", "Learn/Server-side/Express_Nodejs")}}</div> + +<p class="summary">Now you've created (and tested) an awesome <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">LocalLibrary</a> website, you're going to want to install it on a public web server so that it can be accessed by library staff and members over the Internet. This article provides an overview of how you might go about finding a host to deploy your website, and what you need to do in order to get your site ready for production.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré-requisitos:</th> + <td>Complete todos os tópicos anteriores do turotrial, inclusive o <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a>.</td> + </tr> + <tr> + <th scope="row">Objetivo:</th> + <td>Aprender onde e como você pode implantar um app Express app em produção.</td> + </tr> + </tbody> +</table> + +<h2 id="Overview">Overview</h2> + +<p>Once your site is finished (or finished "enough" to start public testing) you're going to need to host it somewhere more public and accessible than your personal development computer.</p> + +<p>Up to now you've been working in a <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">development environment</a>, using Express/Node as a web server to share your site to the local browser/network, and running your website with (insecure) development settings that expose debugging and other private information. Before you can host a website externally you're first going to have to:</p> + +<ul> + <li>Choose an environment for hosting the Express app.</li> + <li>Make a few changes to your project settings.</li> + <li>Set up a production-level infrastructure for serving your website.</li> +</ul> + +<p>This tutorial provides some guidance on your options for choosing a hosting site, a brief overview of what you need to do in order to get your Express app ready for production, and a worked example of how to install the LocalLibrary website onto the <a href="https://www.heroku.com/">Heroku</a> cloud hosting service.</p> + +<p>Bear in mind that you don't have to use Heroku — there are other hosting service available. We've also provided a separate tutorial to show how to <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Installing_on_PWS_Cloud_Foundry">Install LocalLibrary on PWS/Cloud Foundry</a>.</p> + +<h2 id="What_is_a_production_environment">What is a production environment?</h2> + +<p>The production environment is the environment provided by the server computer where you will run your website for external consumption. The environment includes:</p> + +<ul> + <li>Computer hardware on which the website runs.</li> + <li>Operating system (e.g. Linux or Windows).</li> + <li>Programming language runtime and framework libraries on top of which your website is written.</li> + <li>Web server infrastructure, possibly incuding a web server, reverse proxy, load balancer, etc.</li> + <li>Databases on which your website is dependent.</li> +</ul> + +<p>The server computer could be located on your premises and connected to the Internet by a fast link, but it is far more common to use a computer that is hosted "in the cloud". What this actually means is that your code is run on some remote computer (or possibly a "virtual" computer) in your hosting company's data center(s). The remote server will usually offer some guaranteed level of computing resources (e.g. CPU, RAM, storage memory, etc.) and Internet connectivity for a certain price.</p> + +<p>This sort of remotely accessible computing/networking hardware is referred to as <em>Infrastructure as a Service (IaaS)</em>. Many IaaS vendors provide options to preinstall a particular operating system, onto which you must install the other components of your production environment. Other vendors allow you to select more fully-featured environments, perhaps including a complete Node setup.</p> + +<div class="note"> +<p><strong>Note:</strong> Pre-built environments can make setting up your website very easy because they reduce the configuration, but the available options may limit you to an unfamiliar server (or other components) and may be based on an older version of the OS. Often it is better to install components yourself, so that you get the ones that you want, and when you need to upgrade parts of the system, you have some idea of where to start!</p> +</div> + +<p>Other hosting providers support Express as part of a <em>Platform as a Service</em> (<em>PaaS</em>) offering. When using this sort of hosting you don't need to worry about most of your production environment (servers, load balancers, etc.) as the host platform takes care of those for you. That makes deployment quite easy, because you just need to concentrate on your web application and not any other server infrastructure.</p> + +<p>Some developers will choose the increased flexibility provided by IaaS over PaaS, while others will appreciate the reduced maintenance overhead and easier scaling of PaaS. When you're getting started, setting up your website on a PaaS system is much easier, so that is what we'll do in this tutorial.</p> + +<div class="note"> +<p><strong>Tip:</strong> If you choose a Node/Express-friendly hosting provider they should provide instructions on how to set up an Express website using different configurations of webserver, application server, reverse proxy, etc. For example, there are many step-by-step guides for various configurations in the <a href="https://www.digitalocean.com/community/tutorials?q=node">Digital Ocean Node community docs</a>.</p> +</div> + +<h2 id="Choosing_a_hosting_provider">Choosing a hosting provider</h2> + +<p>There are numerous hosting providers that are known to either actively support or work well with <em>Node</em> (and <em>Express</em>). These vendors provide different types of environments (IaaS, PaaS), and different levels of computing and network resources at different prices.</p> + +<div class="note"> +<p><strong>Tip:</strong> There are a lot of hosting solutions, and their services and pricing can change over time. While we introduce a few options below, it is worth performing your own Internet search before selecting a hosting provider.</p> +</div> + +<p>Some of the things to consider when choosing a host:</p> + +<ul> + <li>How busy your site is likely to be and the cost of data and computing resources required to meet that demand.</li> + <li>Level of support for scaling horizontally (adding more machines) and vertically (upgrading to more powerful machines) and the costs of doing so.</li> + <li>Where the supplier has data centres, and hence where access is likely to be fastest.</li> + <li>The host's historical uptime and downtime performance.</li> + <li>Tools provided for managing the site — are they easy to use and are they secure (e.g. SFTP vs FTP).</li> + <li>Inbuilt frameworks for monitoring your server.</li> + <li>Known limitations. Some hosts will deliberately block certain services (e.g. email). Others offer only a certain number of hours of "live time" in some price tiers, or only offer a small amount of storage.</li> + <li>Additional benefits. Some providers will offer free domain names and support for SSL certificates that you would otherwise have to pay for.</li> + <li>Whether the "free" tier you're relying on expires over time, and whether the cost of migrating to a more expensive tier means you would have been better off using some other service in the first place!</li> +</ul> + +<p>The good news when you're starting out is that there are quite a few sites that provide computing environments for "free", albeit with some conditions. For example, <a href="https://www.heroku.com/">Heroku</a> provides a free but resource-limited <em>PaaS</em> environment "forever", while <a href="http://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/billing-free-tier.html">Amazon Web Services</a>, <a href="https://azure.microsoft.com/en-us/pricing/details/app-service/">Microsoft Azure</a>, and the open source option <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Installing_on_PWS_Cloud_Foundry">PWS/Cloud Foundry</a> provide free credit when you first join.</p> + +<p>Many providers also have a "basic" tier that provides more useful levels of computing power and fewer limitations. <a href="https://www.digitalocean.com/">Digital Ocean</a> is an example of a popular hosting provider that offers a relatively inexpensive basic computing tier (in the $5 per month lower range at time of writing).</p> + +<div class="note"> +<p><strong>Note:</strong> Remember that price is not the only selection criterion. If your website is successful, it may turn out that scalability is the most important consideration.</p> +</div> + +<h2 id="Getting_your_website_ready_to_publish">Getting your website ready to publish</h2> + +<p>The main things to think about when publishing your website are web security and performance. At the bare minimum, you will want to remove the stack traces that are included on error pages during development, tidy up your logging, and set the appropriate headers to avoid many common security threats.</p> + +<p>In the following subsections we outline the most important changes that you should make to your app.</p> + +<div class="note"> +<p><strong>Tip:</strong> There are other useful tips in the Express docs — see <a href="https://expressjs.com/en/advanced/best-practice-performance.html">Production best practices: performance and reliability</a> and <a href="https://expressjs.com/en/advanced/best-practice-security.html">Production Best Practices: Security</a>.</p> +</div> + +<h3 id="Set_NODE_ENV_to_'production'">Set NODE_ENV to 'production'</h3> + +<p>We can remove stack traces in error pages by setting the <code>NODE_ENV</code> environment variable to <em>production</em> (it is set to '<em>development</em>' by default). In addition to generating less-verbose error messages, setting the variable to <em>production</em> caches view templates and CSS files generated from CSS extensions. Tests indicate that setting <code>NODE_ENV</code> to <em>production</em> can improve app performance by a factor of three!</p> + +<p>This change can be made either by using export or an environment file, or using the OS initialisation system. </p> + +<div class="note"> +<p><strong>Note:</strong> This is actually a change you make in your environment setup rather than your app, but important enough to note here! We'll show how this is set for our hosting example below. </p> +</div> + +<h3 id="Log_appropriately">Log appropriately</h3> + +<p>Logging calls can have an impact on a high-traffic website. In a production environment you may need to log website activity (e.g. tracking traffic or logging API calls) but you should attempt to minimise the amount of logging added for debugging purposes.</p> + +<p>One way to minimise "debug" logging in production is to use a module like <a href="https://www.npmjs.com/package/debug">debug </a>that allows you to control what logging is performed by setting an environment variable. For example, the code fragment below shows how you might set up "author" logging. The debug variable is declared with the name 'author', and the prefix "author" will be automatically displayed for all logs from this object.</p> + +<pre class="brush: js"><strong>var debug = require('debug')('author');</strong> + +// Display Author update form on GET +exports.author_update_get = function(req, res, next) { + + req.sanitize('id').escape().trim(); + Author.findById(req.params.id, function(err, author) { + if (err) { +<strong> debug('update error:' + err);</strong> + return next(err); + } + //On success + res.render('author_form', { title: 'Update Author', author: author }); + }); + +};</pre> + +<p>You can then enable a particular set of logs by specifying them as a comma-separated list in the <code>DEBUG</code> environment variable. You can set the variables for displaying author and book logs as shown (wildcards are also supported).</p> + +<pre class="brush: bash">#Windows +set DEBUG=author,book + +#Linux +export DEBUG="author,book" +</pre> + +<div class="note"> +<p><strong>Challenge:</strong> Calls to <code>debug</code> can replace logging you might previously have done using <code>console.log()</code> or <code>console.error()</code>. Replace any <code>console.log()</code> calls in your code with logging via the <a href="https://www.npmjs.com/package/debug">debug </a>module. Turn the logging on and off in your development environment by setting the DEBUG variable and observe the impact this has on logging.</p> +</div> + +<p>If you need to log website activity you can use a logging library like <em>Winston</em> or <em>Bunyan</em>. For more information on this topic see: <a href="https://expressjs.com/en/advanced/best-practice-performance.html">Production best practices: performance and reliability</a>.</p> + +<h3 id="Use_gzipdeflate_compression_for_responses">Use gzip/deflate compression for responses</h3> + +<p>Web servers can often compress the HTTP response sent back to a client, significantly reducing the time taken to for the client to get and load the page. The compression method used will depend on what decompression methods the client says that it supports in the request (if no compression methods are supported the response will be sent uncompressed).</p> + +<p>You can add this to your site using <a href="https://www.npmjs.com/package/compression">compression</a> middleware. Install this to your project by running the following command at the root of the project.</p> + +<pre class="brush: bash">npm install compression</pre> + +<p>Open <strong>./app.js</strong> and require the compression library as shown. Add the compression library to the middleware chain with the <code>use()</code> method (this should appear before any routes that you want compressed — in this case all of them!)</p> + +<pre class="brush: js">var catalog = require('./routes/catalog'); //Import routes for "catalog" area of site +<strong>var compression = require('compression');</strong> + +// Create the Express application object +var app = express(); + +... + +<strong>app.use(compression()); //Compress all routes</strong> + +app.use(express.static(path.join(__dirname, 'public'))); + +app.use('/', index); +app.use('/users', users); +app.use('/catalog', catalog); // Add catalog routes to middleware chain. + +... +</pre> + +<div class="note"> +<p><strong>Note</strong>: For a high-traffic website in production you wouldn't use this middleware. Instead you would use a reverse proxy like <em>Nginx</em>.</p> +</div> + +<h3 id="Use_Helmet_to_protect_against_well_known_vulnerabilities">Use Helmet to protect against well known vulnerabilities</h3> + +<p><a href="https://www.npmjs.com/package/helmet">Helmet</a> is a middleware package that can help protect your app from some well-known web vulnerabilities by setting appropriate HTTP headers (see the <a href="https://helmetjs.github.io/docs/">docs</a> for more information on what headers it sets/vulnerabilities it protects against). </p> + +<p>Install this to your project by running the following command at the root of the project.</p> + +<pre class="brush: bash">npm install helmet +</pre> + +<p>Open <strong>./app.js</strong> and require the <em>helmet</em> library as shown. Then add the module to the middleware chain with the <code>use()</code> method.</p> + +<pre class="brush: js">var compression = require('compression'); +<strong>var helmet = require('helmet'); +</strong> +// Create the Express application object +var app = express(); + +<strong>app.use(helmet())</strong>; +...</pre> + +<div class="note"> +<p id="production-best-practices-performance-and-reliability"><strong>Note:</strong> The command above adds the <em>subset</em> of available headers that makes sense for most sites. You can add/disable specific headers as needed by following the instructions on <a href="https://www.npmjs.com/package/helmet">npm</a>.</p> +</div> + +<h2 id="Example_Installing_LocalLibrary_on_Heroku">Example: Installing LocalLibrary on Heroku</h2> + +<p>This section provides a practical demonstration of how to install <em>LocalLibrary</em> on the <a href="http://heroku.com">Heroku PaaS cloud</a>.</p> + +<h3 id="Why_Heroku">Why Heroku?</h3> + +<p>Heroku is one of the longest running and popular cloud-based PaaS services. It originally supported only Ruby apps, but now can be used to host apps from many programming environments, including Node (and hence Express)!</p> + +<p>We are choosing to use Heroku for several reasons:</p> + +<ul> + <li>Heroku has a <a href="https://www.heroku.com/pricing">free tier</a> that is <em>really</em> free (albeit with some limitations).</li> + <li>As a PaaS, Heroku takes care of a lot of the web infrastructure for us. This makes it much easier to get started, because you don't worry about servers, load balancers, reverse proxies, restarting your website on a crash, or any of the other web infrastructure that Heroku provides for us under the hood.</li> + <li>While it does have some limitations, these will not affect this particular application. For example: + <ul> + <li>Heroku provides only short-lived storage so user-uploaded files cannot safely be stored on Heroku itself.</li> + <li>The free tier will sleep an inactive web app if there are no requests within a half hour period. The site may then take several seconds to respond when it is woken up.</li> + <li>The free tier limits the time that your site is running to a certain amount of hours every month (not including the time that the site is "asleep"). This is fine for a low use/demonstration site, but will not be suitable if 100% uptime is required.</li> + <li>Other limitations are listed in <a href="https://devcenter.heroku.com/articles/limits">Limits</a> (Heroku docs).</li> + </ul> + </li> + <li>Mostly it just works, and if you end up loving it and want to upgrade, scaling your app is very easy.</li> +</ul> + +<p>While Heroku is perfect for hosting this demonstration it may not be perfect for your real website. Heroku makes things easy to set up and scale, at the cost of being less flexible, and potentially a lot more expensive once you get out of the free tier.</p> + +<h3 id="How_does_Heroku_work">How does Heroku work?</h3> + +<p>Heroku runs websites within one or more "<a href="https://devcenter.heroku.com/articles/dynos">Dynos</a>", which are isolated, virtualized Unix containers that provide the environment required to run an application. The dynos are completely isolated and have an <em>ephemeral</em> file system (a short-lived file system that is cleaned/emptied every time the dyno restarts). The only thing that dynos share by default are application <a href="https://devcenter.heroku.com/articles/config-vars">configuration variables</a>. Heroku internally uses a load balancer to distribute web traffic to all "web" dynos. Since nothing is shared between them, Heroku can scale an app horizontally by adding more dynos (though of course you may also need to scale your database to accept additional connections).</p> + +<p>Because the file system is ephemeral you can't install services required by your application directly (e.g. databases, queues, caching systems, storage, email services, etc). Instead Heroku web applications use backing services provided as independent "add-ons" by Heroku or 3rd parties. Once attached to your web application, the add-on services are accessed in your web application via environment variables.</p> + +<p>In order to execute your application Heroku needs to be able to set up the appropriate environment and dependencies, and also understand how it is launched. For Node apps all the information it needs is obtained from your <strong>package.json</strong> file.</p> + +<p>Developers interact with Heroku using a special client app/terminal, which is much like a Unix bash script. This allows you to upload code that is stored in a git repository, inspect the running processes, see logs, set configuration variables, and much more!</p> + +<p>In order to get our application to work on Heroku we'll need to put our Express web application into a git repository and make some minor changes to the package.json. Once we've done that we can set up a Heroku account, get the Heroku client, and use it to install our website.</p> + +<p>That's all the overview you need in order to get started (see <a href="https://devcenter.heroku.com/articles/getting-started-with-nodejs">Getting Started on Heroku with Node.js</a> for a more comprehensive guide).</p> + +<h3 id="Creating_an_application_repository_in_Github">Creating an application repository in Github</h3> + +<p>Heroku is closely integrated with the <strong>git</strong> source code version control system, using it to upload/synchronise any changes you make to the live system. It does this by adding a new Heroku "remote" repository named <em>heroku</em> pointing to a repository for your source on the Heroku cloud. During development you use git to store changes on your "master" repository. When you want to deploy your site, you sync your changes to the Heroku repository.</p> + +<div class="note"> +<p><strong>Note:</strong> If you're used to following good software development practices you are probably already using git or some other SCM system. If you already have a git repository, then you can skip this step.</p> +</div> + +<p>There are a lot of ways of to work with git, but one of the easiest is to first set up an account on <a href="https://github.com/">GitHub</a>, create the repository there, and then sync to it locally:</p> + +<ol> + <li>Visit <a href="https://github.com/">https://github.com/</a> and create an account.</li> + <li>Once you are logged in, click the <strong>+</strong> link in the top toolbar and select <strong>New repository</strong>.</li> + <li>Fill in all the fields on this form. While these are not compulsory, they are strongly recommended. + <ul> + <li>Enter a new repository name (e.g. <em>express-locallibrary-tutorial</em>), and description (e.g. "Local Library website written in Express (Node)".</li> + <li>Choose <strong>Node</strong> in the <em>Add .gitignore</em> selection list.</li> + <li>Choose your preferred license in the <em>Add license</em> selection list.</li> + <li>Check <strong>Initialize this repository with a README</strong>.</li> + </ul> + </li> + <li>Press <strong>Create repository</strong>.</li> + <li>Click the green "<strong>Clone or download</strong>" button on your new repo page.</li> + <li>Copy the URL value from the text field inside the dialog box that appears (it should be something like: <strong>https://github.com/<em><your_git_user_id></em>/express-locallibrary-tutorial.git</strong>).</li> +</ol> + +<p>Now the repository ("repo") is created we are going to want to clone it on our local computer:</p> + +<ol> + <li>Install <em>git</em> for your local computer (you can find versions for different platforms <a href="https://git-scm.com/downloads">here</a>).</li> + <li>Open a command prompt/terminal and clone your repository using the URL you copied above: + <pre class="brush: bash">git clone https://github.com/<strong><em><your_git_user_id></em></strong>/express-locallibrary-tutorial.git +</pre> + This will create the repository below the current point.</li> + <li>Navigate into the new repo. + <pre class="brush: bash">cd express-locallibrary-tutorial</pre> + </li> +</ol> + +<p>The final step is to copy in your application and then add the files to your repo using git:</p> + +<ol> + <li>Copy your Express application into this folder (excluding <strong>/node_modules</strong>, which contains dependency files that you should fetch from NPM as needed).</li> + <li>Open a command prompt/terminal and use the <code>add</code> command to add all files to git.</li> + <li> + <pre class="brush: bash">git add -A +</pre> + </li> + <li>Use the status command to check all files that you are about to add are correct (you want to include source files, not binaries, temporary files etc.). It should look a bit like the listing below. + <pre>> git status +On branch master +Your branch is up-to-date with 'origin/master'. +Changes to be committed: + (use "git reset HEAD <file>..." to unstage) + + new file: ...</pre> + </li> + <li>When you're satisfied commit the files to your local repository: + <pre class="brush: bash">git commit -m "First version of application moved into github"</pre> + </li> + <li>Then synchronise your local repository to the Github website, using the following: + <pre>git push origin master</pre> + </li> +</ol> + +<p>When this operation completes, you should be able to go back to the page on Github where you created your repo, refresh the page, and see that your whole application has now been uploaded. You can continue to update your repository as files change using this add/commit/push cycle.</p> + +<div class="note"> +<p><strong>Tip:</strong> This is a good point to make a backup of your "vanilla" project — while some of the changes we're going to be making in the following sections might be useful for deployment on any platform (or development) others might not.</p> + +<p>The <em>best</em> way to do this is to use <em>git</em> to manage your revisions. With <em>git</em> you can not only go back to a particular old version, but you can maintain this in a separate "branch" from your production changes and cherry-pick any changes to move between production and development branches. <a href="https://help.github.com/articles/good-resources-for-learning-git-and-github/">Learning Git</a> is well worth the effort, but is beyond the scope of this topic.</p> + +<p>The <em>easiest</em> way to do this is to just copy your files into another location. Use whichever approach best matches your knowledge of git!</p> +</div> + +<h3 id="Update_the_app_for_Heroku">Update the app for Heroku</h3> + +<p>This section explains the changes you'll need to make to our <em>LocalLibrary</em> application to get it to work on Heroku.</p> + +<h4 id="Set_node_version">Set node version </h4> + +<p>The <strong>package.json</strong> contains everything needed to work out your application dependencies and what file should be launched to start your site. Heroku detects the presence of this file, and will use it to provision your app environment.</p> + +<p>The only useful information missing in our current <strong>package.json</strong> is the version of node. We can find the version of node we're using for development by entering the command:</p> + +<pre class="brush: bash">>node --version +v8.9.1</pre> + +<p>Open <strong>package.json</strong>, and add this information as an <strong>engines > node</strong> section as shown (using the version number for your system).</p> + +<pre class="brush: json">{ + "name": "express-locallibrary-tutorial", + "version": "0.0.0", +<strong> "engines": { + "node": "8.9.1" + },</strong> + "private": true, + ... +</pre> + +<h4 id="Database_configuration">Database configuration</h4> + +<p>So far in this tutorial we've used a single database that is hard coded into <strong>app.js</strong>. Normally we'd like to be able to have a different database for production and development, so next we'll modify the LocalLibrary website to get the database URI from the OS environment (if it has been defined), and otherwise use our development database.</p> + +<p>Open <strong>app.js</strong> and find the line that sets the mongoDB connection variable. It will look something like this:</p> + +<pre class="brush: js">var mongoDB = 'mongodb://your_user_id:your_password@ds119748.mlab.com:19748/local_library';</pre> + +<p>Replace the line with the following code that uses <code>process.env.MONGODB_URI</code> to get the connection string from an environment variable named <code>MONGODB_URI</code> if has been set (use your own database URL instead of the placeholder below.)</p> + +<pre class="brush: js">var mongoDB = <strong>process.env.MONGODB_URI</strong> || 'mongodb://your_user_id:your_password@ds119748.mlab.com:19748/local_library'; +</pre> + +<h4 id="Get_dependencies_and_re-test">Get dependencies and re-test</h4> + +<p>Before we proceed, let's test the site again and make sure it wasn't affected by any of our changes. </p> + +<p>First we will need to fetch our dependencies (you will recall we didn't copy the <strong>node_modules</strong> folder into our git tree). You can do this by running the following command in your terminal at the root of the project:</p> + +<pre class="brush: bash">npm install +</pre> + +<p>Now run the site (see <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes#Testing_the_routes">Testing the routes</a> for the relevant commands) and check that the site still behaves as you expect.</p> + +<h4 id="Save_changes_to_Github">Save changes to Github</h4> + +<p>Next let's save all our changes to Github. In the terminal (whilst inside our repository), enter the following commands:</p> + +<pre class="brush: bash">git add -A +git commit -m "Added files and changes required for deployment to heroku" +git push origin master</pre> + +<p>We should now be ready to start deploying <em>LocalLibrary</em> on Heroku.</p> + +<h3 id="Get_a_Heroku_account">Get a Heroku account</h3> + +<p>To start using Heroku you will first need to create an account (skip ahead to <a href="#Create_and_upload_the_website">Create and upload the website</a> if you've already got an account and installed the Heroku client):</p> + +<ul> + <li>Go to <a href="https://www.heroku.com/">www.heroku.com</a> and click the <strong>SIGN UP FOR FREE</strong> button.</li> + <li>Enter your details and then press <strong>CREATE FREE ACCOUNT</strong>. You'll be asked to check your account for a sign-up email.</li> + <li>Click the account activation link in the signup email. You'll be taken back to your account on the web browser.</li> + <li>Enter your password and click <strong>SET PASSWORD AND LOGIN</strong>.</li> + <li>You'll then be logged in and taken to the Heroku dashboard: <a href="https://dashboard.heroku.com/apps">https://dashboard.heroku.com/apps</a>.</li> +</ul> + +<h3 id="Install_the_client">Install the client</h3> + +<p>Download and install the Heroku client by following the <a href="https://devcenter.heroku.com/articles/getting-started-with-python#set-up">instructions on Heroku here</a>.</p> + +<p>After the client is installed you will be able run commands. For example to get help on the client:</p> + +<pre class="brush: bash">heroku help +</pre> + +<h3 id="Create_and_upload_the_website">Create and upload the website</h3> + +<p>To create the app we run the "create" command in the root directory of our repository. This creates a git remote ("pointer to a remote repository") named <em>heroku</em> in our local git environment.</p> + +<pre class="brush: bash">heroku create</pre> + +<div class="note"> +<p><strong>Note:</strong> You can name the remote if you like by specifying a value after "create". If you don't then you'll get a random name. The name is used in the default URL.</p> +</div> + +<p>We can then push our app to the Heroku repository as shown below. This will upload the app, get all its dependencies, package it in a dyno, and start the site.</p> + +<pre class="brush: bash">git push heroku master</pre> + +<p>If we're lucky, the app is now "running" on the site. To open your browser and run the new website, use the command:</p> + +<pre class="brush: bash">heroku open</pre> + +<div class="note"> +<p><strong>Note</strong>: The site will be running using our development database. Create some books and other objects, and check out whether the site is behaving as you expect. In the next section we'll set it to use our new database.</p> +</div> + +<h3 id="Setting_configuration_variables">Setting configuration variables</h3> + +<p>You will recall from a preceding section that we need to <a href="#NODE_ENV">set NODE_ENV to 'production'</a> in order to improve our performance and generate less-verbose error messages. We do this by entering the following command:</p> + +<pre class="brush: bash">>heroku config:set NODE_ENV='production' +Setting NODE_ENV and restarting limitless-tor-18923... done, v13 +NODE_ENV: production +</pre> + +<p>We should also use a separate database for production, setting its URI in the <strong>MONGODB_URI</strong> environment variable. You can set up a new database and database-user exactly <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose#Setting_up_the_MongoDB_database">as we did originally</a>, and get its URI. You can set the URI as shown (obviously, using your own URI!)</p> + +<pre class="brush: bash">>heroku config:set <strong>MONGODB_URI</strong>='mongodb://your_user:your_password@ds139278.mlab.com:39278/local_library_production' +Setting MONGODB_URI and restarting limitless-tor-18923... done, v13 +MONGODB_URI: mongodb://your_user:your_password@ds139278.mlab.com:39278/local_library_production +</pre> + +<p>You can inspect your configuration variables at any time using the <code>heroku config</code> command — try this now:</p> + +<pre class="brush: bash">>heroku config +=== limitless-tor-18923 Config Vars +MONGODB_URI: mongodb://your_user:your_password@ds139278.mlab.com:39278/local_library_production +NODE_ENV: production +</pre> + +<p>Heroku will restart your app when it updates the variables. If you check the home page now it should show zero values for your object counts, as the changes above mean that we're now using a new (empty) database.</p> + +<h3 id="Managing_addons">Managing addons</h3> + +<p>Heroku uses independent add-ons to provide backing services to apps — for example email or database services. We don't use any addons in this website, but they are an important part of working with Heroku, so you may want to check out the topic <a href="https://devcenter.heroku.com/articles/managing-add-ons">Managing Add-ons</a> (Heroku docs).</p> + +<h3 id="Debugging">Debugging</h3> + +<p>The Heroku client provides a few tools for debugging:</p> + +<pre class="brush: bash">heroku logs # Show current logs +heroku logs --tail # Show current logs and keep updating with any new results +heroku ps #Display dyno status +</pre> + +<ul> +</ul> + +<h2 id="Summary">Summary</h2> + +<p>That's the end of this tutorial on setting up Express apps in production, and also the series of tutorials on working with Express. We hope you've found them useful. You can check out a fully worked-through version of the <a href="https://github.com/mdn/express-locallibrary-tutorial">source code on Github here</a>.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li id="production-best-practices-performance-and-reliability"><a href="https://expressjs.com/en/advanced/best-practice-performance.html">Production best practices: performance and reliability</a> (Express docs)</li> + <li><a href="https://expressjs.com/en/advanced/best-practice-security.html">Production Best Practices: Security</a> (Express docs)</li> + <li>Heroku + <ul> + <li><a href="https://devcenter.heroku.com/articles/getting-started-with-nodejs">Getting Started on Heroku with Node.js</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/deploying-nodejs">Deploying Node.js Applications on Heroku</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/nodejs-support">Heroku Node.js Support</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/node-concurrency">Optimizing Node.js Application Concurrency</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/how-heroku-works">How Heroku works</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/dynos">Dynos and the Dyno Manager</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/config-vars">Configuration and Config Vars</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/limits">Limits</a> (Heroku docs)</li> + </ul> + </li> + <li>Digital Ocean + <ul> + <li><a href="https://www.digitalocean.com/community/tutorials?q=express">Express</a> tutorials</li> + <li><a href="https://www.digitalocean.com/community/tutorials?q=node.js">Node.js</a> tutorials </li> + </ul> + </li> +</ul> + +<p>{{PreviousMenu("Learn/Server-side/Express_Nodejs/forms", "Learn/Server-side/Express_Nodejs")}}</p> + +<p> </p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Setting up a Node (Express) development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li> +</ul> + +<p> </p> diff --git a/files/pt-br/learn/server-side/express_nodejs/displaying_data/flow_control_using_async/index.html b/files/pt-br/learn/server-side/express_nodejs/displaying_data/flow_control_using_async/index.html new file mode 100644 index 0000000000..1f4b09375b --- /dev/null +++ b/files/pt-br/learn/server-side/express_nodejs/displaying_data/flow_control_using_async/index.html @@ -0,0 +1,135 @@ +--- +title: Controle de fluxo assíncrono usando async +slug: Learn/Server-side/Express_Nodejs/Displaying_data/flow_control_using_async +translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/flow_control_using_async +--- +<p>O código da <em>Controller</em>, para algumas de nossas páginas dependerá dos resultados de várias solicitações assíncronas, que talvez possam ser necessárias para serem executadas em uma ordem específica ou em paralelo. Para gerenciar o controle do nosso fluxo e renderizar páginas quando tivermos todas as informações necessárias disponíveis, usaremos o popular módulo <a href="https://www.npmjs.com/package/async">async</a>.</p> + +<div class="note"> +<p><strong>Nota:</strong> Há várias outras maneiras de gerenciar o comportamento assíncrono e o controle de fluxo em JavaScript, um dos recursos Javascript que pode ser utilizado, são as <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/Techniques/Promises">Promises</a>. </p> +</div> + +<p>Async has a lot of useful methods (check out <a class="external external-icon" href="http://caolan.github.io/async/docs.html" rel="noopener">the documentation</a>). Some of the more important functions are:</p> + +<ul> + <li><code><a class="external external-icon" href="http://caolan.github.io/async/docs.html#parallel" rel="noopener">async.parallel()</a></code> executa qualquer operação que deva ser processada em paralelo.</li> + <li><code><a class="external external-icon" href="http://caolan.github.io/async/docs.html#series" rel="noopener">async.series()</a></code> garante que as operações assíncronas sejam executadas em série.</li> + <li><code><a class="external external-icon" href="http://caolan.github.io/async/docs.html#waterfall" rel="noopener">async.waterfall()</a></code> operações que devem ser executadas em série, baseando-se no resultado de cada operação anterior. </li> +</ul> + +<h2 class="highlight-spanned" id="Por_que_isso_é_necessário"><span class="highlight-span">Por que isso é necessário ?</span></h2> + +<p>A maioria dos métodos que usamos no Express são assíncronos - você especifica uma operação para executar, passando um <em>callback</em>. O método retorna imediatamente e o <em>callback </em>é invocado quando a operação solicitada é concluída. Por convenção no <em>Express</em>, as funções de <em>callback </em>passam um valor de erro como o primeiro parâmetro (ou nulo em sucesso) e os resultados da função (se houver algum) como o segundo parâmetro.</p> + +<p>Se uma <em>Controller </em>só precisa <em>executar</em> <em><strong>uma </strong>operação assíncrona</em> para obter as informações necessárias para renderizar uma página, a implementação é fácil —simplesmente renderizamos o <em>template</em> no <em>callback</em>. O código abaixo ilustra uma função que renderiza a contagem de um <em>model</em> <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">ExampleModel </span></font>(usando o método <code><a href="http://mongoosejs.com/docs/api.html#model_Model.count" rel="noopener">count()</a> </code> do Mongoose.</p> + +<pre class="brush: js"><code>exports.example_model_count = function(req, res, next) { + +</code> <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">ExampleModel </span></font>.count({ a_model_field: 'match_value' }, function (err, count) { + // ... do something if there is an err + + // On success, render the result by passing count into the render function (here, as the variable 'data'). + res.render('the_template', { data: count } ); + }); +<code>}</code> +</pre> + +<p>However what if you need to make <strong>multiple </strong>asynchronous queries, and you can't render the page until all the operations have completed? A naive implementation could "daisy chain" the requests, kicking off subsequent requests in the callback of a previous request, and rendering the response in the final callback. The problem with this approach is that our requests would have to be run in series, even though it might be more efficient to run them in parallel. This could also result in complicated nested code, commonly referred to as <a class="external external-icon" href="http://callbackhell.com/" rel="noopener">callback hell</a>.</p> + +<p>A much better solution would be to execute all the requests in parallel and then have a single callback that executes when all of the queries have completed. This is the sort of flow operation that the <em>Async</em> module makes easy!</p> + +<h2 class="highlight-spanned" id="Operações_assíncronas_em_paralelo"><span class="highlight-span">Operações assíncronas em paralelo</span></h2> + +<p>The method <code><a class="external external-icon" href="http://caolan.github.io/async/docs.html#parallel" rel="noopener">async.parallel()</a></code> is used to run multiple asynchronous operations in parallel.</p> + +<p>The first argument to <code>async.parallel()</code> is a collection of the asynchronous functions to run (an array, object or other iterable). Each function is passed a <code>callback(err, result)</code> which it must call on completion with an error <code>err</code> (which can be <code>null</code>) and an optional <code>results</code> value.</p> + +<p>The optional second argument to <code>async.parallel()</code> is a callback that will be run when all the functions in the first argument have completed. The callback is invoked with an error argument and a result collection that contains the results of the individual asynchronous operations. The result collection is of the same type as the first argument (i.e. if you pass an array of asynchronous functions, the final callback will be invoked with an array of results). If any of the parallel functions reports an error the callback is invoked early (with the error value).</p> + +<p>The example below shows how this works when we pass an object as the first argument. As you can see, the results are <em>returned</em> in an object with the same property names as the original functions that were passed in.</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">async</span><span class="punctuation token">.</span><span class="function token">parallel</span><span class="punctuation token">(</span><span class="punctuation token">{</span> + one<span class="punctuation token">:</span> <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span> <span class="punctuation token">}</span><span class="punctuation token">,</span> + two<span class="punctuation token">:</span> <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span> <span class="punctuation token">}</span><span class="punctuation token">,</span> + <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span> + something_else<span class="punctuation token">:</span> <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span> <span class="punctuation token">}</span> + <span class="punctuation token">}</span><span class="punctuation token">,</span> + <span class="comment token">// optional callback</span> + <span class="keyword token">function</span><span class="punctuation token">(</span>err<span class="punctuation token">,</span> results<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="comment token">// 'results' is now equal to: {one: 1, two: 2, ..., something_else: some_value}</span> + <span class="punctuation token">}</span> +<span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre> + +<p>If you instead pass an array of functions as the first argument, the results will be an array (the array order results will match the original order that the functions were declared—not the order in which they completed).</p> + +<h2 class="highlight-spanned" id="Operações_assíncronas_em_série"><span class="highlight-span">Operações assíncronas em série</span></h2> + +<p>The method <code><a class="external external-icon" href="http://caolan.github.io/async/docs.html#series" rel="noopener">async.series()</a></code> is used to run multiple asynchronous operations in sequence, when subsequent functions do not depend on the output of earlier functions. It is essentially declared and behaves in the same way as <code>async.parallel()</code>.</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">async</span><span class="punctuation token">.</span><span class="function token">series</span><span class="punctuation token">(</span><span class="punctuation token">{</span> + one<span class="punctuation token">:</span> <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span> <span class="punctuation token">}</span><span class="punctuation token">,</span> + two<span class="punctuation token">:</span> <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span> <span class="punctuation token">}</span><span class="punctuation token">,</span> + <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span> + something_else<span class="punctuation token">:</span> <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span> <span class="punctuation token">}</span> + <span class="punctuation token">}</span><span class="punctuation token">,</span> + <span class="comment token">// optional callback after the last asynchronous function completes.</span> + <span class="keyword token">function</span><span class="punctuation token">(</span>err<span class="punctuation token">,</span> results<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="comment token">// 'results' is now equals to: {one: 1, two: 2, ..., something_else: some_value} </span> + <span class="punctuation token">}</span> +<span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre> + +<div class="note"> +<p><strong>Note:</strong> The ECMAScript (JavaScript) language specification states that the order of enumeration of an object is undefined, so it is possible that the functions will not be called in the same order as you specify them on all platforms. If the order really is important, then you should pass an array instead of an object, as shown below.</p> +</div> + +<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">async</span><span class="punctuation token">.</span><span class="function token">series</span><span class="punctuation token">(</span><span class="punctuation token">[</span> + <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="comment token">// do some stuff ...</span> + <span class="function token">callback</span><span class="punctuation token">(</span><span class="keyword token">null</span><span class="punctuation token">,</span> <span class="string token">'one'</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span><span class="punctuation token">,</span> + <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="comment token">// do some more stuff ... </span> + <span class="function token">callback</span><span class="punctuation token">(</span><span class="keyword token">null</span><span class="punctuation token">,</span> <span class="string token">'two'</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span> + <span class="punctuation token">]</span><span class="punctuation token">,</span> + <span class="comment token">// optional callback</span> + <span class="keyword token">function</span><span class="punctuation token">(</span>err<span class="punctuation token">,</span> results<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="comment token">// results is now equal to ['one', 'two'] </span> + <span class="punctuation token">}</span> +<span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre> + +<h2 class="highlight-spanned" id="Operações_assíncronas_dependentes_em_série"><span class="highlight-span">Operações assíncronas dependentes em série</span></h2> + +<p>The method <code><a class="external external-icon" href="http://caolan.github.io/async/docs.html#waterfall" rel="noopener">async.waterfall()</a></code> is used to run multiple asynchronous operations in sequence when each operation is dependent on the result of the previous operation.</p> + +<p>The callback invoked by each asynchronous function contains <code>null</code> for the first argument and results in subsequent arguments. Each function in the series takes the results arguments of the previous callback as the first parameters, and then a callback function. When all operations are complete, a final callback is invoked with the result of the last operation. The way this works is more clear when you consider the code fragment below (this example is from the <em>async</em> documentation):</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">async</span><span class="punctuation token">.</span><span class="function token">waterfall</span><span class="punctuation token">(</span><span class="punctuation token">[</span> + <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="function token">callback</span><span class="punctuation token">(</span><span class="keyword token">null</span><span class="punctuation token">,</span> <span class="string token">'one'</span><span class="punctuation token">,</span> <span class="string token">'two'</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span><span class="punctuation token">,</span> + <span class="keyword token">function</span><span class="punctuation token">(</span>arg1<span class="punctuation token">,</span> arg2<span class="punctuation token">,</span> callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="comment token">// arg1 now equals 'one' and arg2 now equals 'two' </span> + <span class="function token">callback</span><span class="punctuation token">(</span><span class="keyword token">null</span><span class="punctuation token">,</span> <span class="string token">'three'</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span><span class="punctuation token">,</span> + <span class="keyword token">function</span><span class="punctuation token">(</span>arg1<span class="punctuation token">,</span> callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="comment token">// arg1 now equals 'three'</span> + <span class="function token">callback</span><span class="punctuation token">(</span><span class="keyword token">null</span><span class="punctuation token">,</span> <span class="string token">'done'</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span> +<span class="punctuation token">]</span><span class="punctuation token">,</span> <span class="keyword token">function</span> <span class="punctuation token">(</span>err<span class="punctuation token">,</span> result<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="comment token">// result now equals 'done'</span> +<span class="punctuation token">}</span> +<span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre> + +<h2 class="highlight-spanned" id="Instalando_o_async"><span class="highlight-span">Instalando o async</span></h2> + +<p>Install the async module using the NPM package manager so that we can use it in our code. You do this in the usual way, by opening a prompt in the root of the <em>LocalLibrary</em> project and enter the following command:</p> + +<pre class="brush: bash line-numbers language-bash"><code class="language-bash">npm install async</code></pre> + +<h2 id="Next_steps">Next steps</h2> + +<ul> + <li>Return to <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a>.</li> + <li>Proceed to the next subarticle of Part 5: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Template_primer">Template primer</a>.</li> +</ul> diff --git a/files/pt-br/learn/server-side/express_nodejs/displaying_data/index.html b/files/pt-br/learn/server-side/express_nodejs/displaying_data/index.html new file mode 100644 index 0000000000..732e4e4417 --- /dev/null +++ b/files/pt-br/learn/server-side/express_nodejs/displaying_data/index.html @@ -0,0 +1,87 @@ +--- +title: 'Express Tutorial Part 5: Displaying library data' +slug: Learn/Server-side/Express_Nodejs/Displaying_data +translation_of: Learn/Server-side/Express_Nodejs/Displaying_data +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs/forms", "Learn/Server-side/Express_Nodejs")}}</div> + +<p class="summary">We're now ready to add the pages that display the <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">LocalLibrary</a> website books and other data. The pages will include a home page that shows how many records we have of each model type, and list and detail pages for all of our models. Along the way we'll gain practical experience in getting records from the database, and using templates.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré-requisitos:</th> + <td>Complete previous tutorial topics (including <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a>).</td> + </tr> + <tr> + <th scope="row">Objetivo:</th> + <td>To understand how to use the async module and Pug template language, and how to get data from the URL in our controller functions.</td> + </tr> + </tbody> +</table> + +<h2 id="Overview">Overview</h2> + +<p>In our previous tutorial articles we defined <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Mongoose models</a> that we can use to interact with a database and created some initial library records. We then <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">created all the routes</a> needed for the LocalLibrary website, but with "dummy controller" functions (these are skeleton controller functions that just return a "not implemented" message when a page is accessed).</p> + +<p>The next step is to provide proper implementations for the pages that <em>display</em> our library information (we'll look at implementing pages featuring forms to create, update, or delete information in later articles). This includes updating the controller functions to fetch records using our models, and defining templates to display this information to users.</p> + +<p>We will start by providing overview/primer topics explaining how to manage asynchronous operations in controller functions and how to write templates using Pug. Then we'll provide implementations for each of our main "read only" pages with a brief explanation of any special or new features that they use.</p> + +<p>At the end of this article you should have a good end-to-end understanding of how routes, asynchronous functions, views, and models work in practice.</p> + +<h2 id="Displaying_library_data_tutorial_subarticles">Displaying library data tutorial subarticles</h2> + +<p>The following subarticles go through the process of adding the different features required for us to display the required website pages. You need to read and work through each one of these in turn, before moving on to the next one.</p> + +<ol> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/flow_control_using_async">Asynchronous flow control using async</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Template_primer">Template primer</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/LocalLibrary_base_template">The LocalLibrary base template</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Home_page">Home page</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Book_list_page">Book list page</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_list_page">BookInstance list page</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Date_formatting_using_moment">Date formatting using moment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Author_list_page">Author list page and Genre list page challenge</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Genre_detail_page">Genre detail page</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Book_detail_page">Book detail page</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Author_detail_page">Author detail page</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_detail_page_and_challenge">BookInstance detail page and challenge</a></li> +</ol> + +<h2 id="Summary">Summary</h2> + +<p>We've now created all the "read-only" pages for our site: a home page that displays counts of instances of each of our models, and list and detail pages for our books, book instances, authors, and genres. Along the way we've gained a lot of fundamental knowledge about controllers, managing flow control when using asynchronous operations, creating views using <em>Pug</em>, querying the database using our models, how to pass information to a template from your view, and how to create and extend templates. Those who completed the challenge will also have learned a little about date handling using <em>moment</em>.</p> + +<p>In our next article we'll build on our knowledge, creating HTML forms and form handling code to start modifying the data stored by the site.</p> + +<h2 id="Veja_mais">Veja mais</h2> + +<ul> + <li><a href="http://caolan.github.io/async/docs.html">Async module</a> (Async docs)</li> + <li><a href="https://expressjs.com/en/guide/using-template-engines.html">Using Template engines with Express</a> (Express docs)</li> + <li><a href="https://pugjs.org/api/getting-started.html">Pug</a> (Pug docs)</li> + <li><a href="http://momentjs.com/docs/">Moment</a> (Moment docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs/forms", "Learn/Server-side/Express_Nodejs")}}</p> + +<p> </p> + +<h2 id="Neste_módulo">Neste módulo</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Setting up a Node (Express) development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li> +</ul> + +<p> </p> diff --git a/files/pt-br/learn/server-side/express_nodejs/index.html b/files/pt-br/learn/server-side/express_nodejs/index.html new file mode 100644 index 0000000000..a94962ad4d --- /dev/null +++ b/files/pt-br/learn/server-side/express_nodejs/index.html @@ -0,0 +1,65 @@ +--- +title: Express Web Framework (Node.js/JavaScript) +slug: Learn/Server-side/Express_Nodejs +translation_of: Learn/Server-side/Express_Nodejs +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">Express é um popular framework web estruturado, escrito em JavaScript que roda sobre o ambiente node.js em tempo de execução. Este módulo explica alguns dos principais benefícios deste framework, como configurar o seu ambiente de desenvolvimento e como executar tarefas comuns de desenvolvimento e implantação da web.</p> + +<h2 id="Pré-requisitos">Pré-requisitos</h2> + +<p>Antes de iniciar este módulo, você precisará entender o que é programação web e as estruturas do lado do servidor são, o ideal é ler os tópicos em nosso <a href="/en-US/docs/Learn/Server-side/First_steps">Módulo de primeiros passos da programação de sites do lado servidor</a>. Um conhecimento geral de conceitos de programação e JavaScript é altamente recomendado, mas não é essencial para a compreensão dos conceitos fundamentais.</p> + +<div class="note"> +<p><strong>Nota</strong>: Nota: Este site possui muitos recursos úteis para aprender JavaScript no contexto do desenvolvimento do lado do cliente: JavaScript, Guia de JavaScript, princípios básicos de JavaScript, JavaScript (aprendizagem). O core JavaScript linguagem e conceitos são os mesmos para o desenvolvimento do lado do servidor no Node.js e este material será relevante. O Node.js oferece APIs adicionais para suportar funcionalidades que são úteis em ambientes sem navegador, e. Para criar servidores HTTP e acessar o sistema de arquivos, mas não suporta APIs JavaScript para trabalhar com o navegador e o DOM.</p> + +<p>Este guia fornecerá algumas informações sobre como trabalhar com o Node.js e o Express, e existem inúmeros outros recursos excelentes na Internet e em livros - alguns desses relacionados de Como faço para começar com Node.js (StackOverflow) e O que são os Melhores recursos para aprender Node.js? (Quora).</p> +</div> + +<h2 id="Tutoriais">Tutoriais</h2> + +<dl> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introdução</a></dt> + <dd>Neste primeiro artigo Express, respondemos as perguntas "O que é Node?" E "O que é Express?" E dar-lhe uma visão geral do que torna a estrutura web Express especial. Apresentaremos os principais recursos e mostraremos alguns dos principais blocos de construção de um aplicativo Express (embora neste momento você ainda não tenha um ambiente de desenvolvimento para testá-lo).</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Configurando um ambiente de desenvolvimento em Node (Express) </a></dt> + <dd>Agora que você sabe o que o Express é, vamos mostrar-lhe como configurar e testar um ambiente de desenvolvimento de Node.js / Express no Windows, Linux (Ubuntu) e Mac OS X. Qualquer sistema operacional comum que você esteja usando, este artigo deve Dê o que você precisa para começar a desenvolver aplicativos Express.</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Tutorial Express: O site da Biblioteca Local</a></dt> + <dd>O primeiro artigo da nossa série de tutoriais práticos explica o que você aprenderá e fornecer uma visão geral do exemplo de site da "biblioteca local", no qual estaremos trabalhando e evoluindo em artigos subsquentes.</dd> + <dt></dt> + <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></dt> + <dd>Este artigo mostra como você pode criar um projeto de "esqueleto" de website, no qual você pode popular com as rotas específicas do site, modelos/vizualizações e bancos de dados.</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></dt> + <dd>This article briefly introduces databases for Node/Express. It then goes on to show how we can use <a href="http://mongoosejs.com/">Mongoose</a> to provide database access for the <em>LocalLibrary</em> website. It explains how object schema and models are declared, the main field types, and basic validation. It also briefly shows a few of the main ways you can access model data.</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></dt> + <dd>In this tutorial we'll set up routes (URL handling code) with "dummy" handler functions for all the resource endpoints that we'll eventually need in the <em>LocalLibrary</em> website. On completion, we'll have a modular structure for our route handling code, that we can extend with real handler functions in the following articles. We'll also have a really good understanding of how to create modular routes using Express.</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></dt> + <dd>We're now ready to add the pages that display the <em>LocalLibrary</em> website books and other data. The pages will include a home page that shows how many records we have of each model type, and list and detail pages for all of our models. Along the way we'll gain practical experience in getting records from the database, and using templates.</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></dt> + <dd>In this tutorial we'll show you how to work with <a href="/en-US/docs/Web/Guide/HTML/Forms">HTML Forms</a> in Express, using Pug, and in particular how to write forms to create, update, and delete documents from the database.</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></dt> + <dd>Now you've created an awesome <em>LocalLibrary</em> website, you're going to want to install it on a public web server so that it can be accessed by library staff and members over the Internet. This article provides an overview of how you might go about finding a host to deploy your website, and what you need to do in order to get your site ready for production.</dd> +</dl> + +<h2 id="See_also">See also</h2> + +<dl> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Installing_on_PWS_Cloud_Foundry">Installing LocalLibrary on PWS/Cloud Foundry</a></dt> + <dd>This article provides a practical demonstration of how to install <em>LocalLibrary</em> on the <a href="http://run.pivotal.io">Pivotal Web Services PaaS cloud</a> — this is a full-featured, open source alternative to Heroku, the PaaS cloud service used in Part 7 of the tutorial, listed above. PWS/Cloud Foundry is definitely worth checking out if you are looking for an alternative to Heroku (or another PaaS cloud service), or simply feel like trying something different.</dd> +</dl> + +<h2 id="Adding_more_tutorials">Adding more tutorials</h2> + +<div> +<p>That's the end of the tutorial articles (for now). If you would like to extend it, other interesting topics to cover are:</p> + +<ul> + <li>Using sessions</li> + <li>User authentication</li> + <li>User authorisation and permissions</li> + <li>Testing an Express web application</li> + <li>Web security for Express web applications.</li> +</ul> + +<p>And of course it would be excellent to have an assessment task!</p> +</div> diff --git a/files/pt-br/learn/server-side/express_nodejs/introdução/index.html b/files/pt-br/learn/server-side/express_nodejs/introdução/index.html new file mode 100644 index 0000000000..15ccfc6145 --- /dev/null +++ b/files/pt-br/learn/server-side/express_nodejs/introdução/index.html @@ -0,0 +1,519 @@ +--- +title: Introdução Express/Node +slug: Learn/Server-side/Express_Nodejs/Introdução +tags: + - Aprender + - Express + - Iniciante + - JavaScript + - Node + - Servidor + - Tutorial + - nodejs +translation_of: Learn/Server-side/Express_Nodejs/Introduction +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs")}}</div> + +<p class="summary">Neste primeiro artigo sobre Express responderemos as questões " O que é Node?" e "O que é Express?", além de dar a você uma visão geral sobre o que torna o Express um framework web tão especial. Vamos descrever as principais características e mostrar alguns dos principais blocos de códigos de construção de um aplicativo Express <span id="result_box" lang="pt"><span>(embora neste momento você ainda não tenha um ambiente de desenvolvimento para testá-lo).</span></span></p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré-requisitos:</th> + <td>Conhecimentos básicos em informática. Uma compreensão geral de <a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/First_steps">programação web no lado servidor (backend)</a>, em particular, nos mecanismos de <a href="/pt-BR/docs/Learn/Server-side/First_steps/Client-Server_overview">interação cliente-servidor de websites</a>.</td> + </tr> + <tr> + <th scope="row">Objetivos:</th> + <td>Familiarizar-se com Express, como este framework trabalha junto ao Node, <span id="result_box" lang="pt"><span>quais as funcionalidades que fornece e quais são os principais blocos de construção de um aplicativo Express.</span></span></td> + </tr> + </tbody> +</table> + +<h2 id="O_que_é_Express_e_Node">O que é Express e Node ?</h2> + +<p><a href="https://nodejs.org/">Node</a> (ou formalmente <em>Node.js</em>) é um ambiente em tempo de execução open-source (código aberto) e multiplataforma que permite aos desenvolvedores criarem todo tipo de aplicativos e ferramentas do lado servidor (backend) em <a href="/pt-BR/docs/Glossary/JavaScript">JavaScript</a>. Node<span id="result_box" lang="pt"><span> é usado fora do contexto de um navegador</span></span> (ou seja executado diretamente no computador ou no servidor). Como tal, <span id="result_box" lang="pt"><span>o ambiente omite APIs JavaScript específicas do navegador e adiciona suporte para APIs de sistema operacional mais tradicionais, incluindo bibliotecas de sistemas HTTP e arquivos.</span></span></p> + +<p><span id="result_box" lang="pt"><span>Do ponto de vista do desenvolvimento de um servidor web, o Node possui vários benefícios:</span></span></p> + +<ul> + <li>Performance excelente. Node foi projetado para otimizar a taxa de transferência e a escalabilidade em aplicações web. É <span id="result_box" lang="pt"><span>uma ótima combinação para resolver muitos problemas comuns no desenvolvimento da web (por exemplo, aplicações em tempo real).</span></span></li> + <li>O código é escrito em "JavaScript simples e antigo". Isso significa menos tempo gasto para lidar com mudanças de código entre navegador e servidor web, não sendo necessária uma mudança na linguagem.</li> + <li>JavaScript é uma linguagem de programação relativamente nova e apresenta <span id="result_box" lang="pt"><span>algumas vantagens quando comparadas a outras linguagens tradicionais de servidor</span></span> (por exemplo Python, PHP, etc.). <span id="result_box" lang="pt"><span>Muitas outras linguagens novas e populares compilam/convertem em JavaScript, permitindo que você também use essas linguagens, como TypeScript, CoffeeScript, ClosureScript, Scala, LiveScript, etc.</span></span></li> + <li>O Gerenciador de Pacotes do Node (NPM, na sigla em inglês) provê acesso a centenas de milhares de pacotes reutiliváveis. <span id="result_box" lang="pt"><span>NPM possui a melhor coleção de dependências e também pode ser usado para automatizar a maior parte da cadeia de ferramentas de compilação.</span></span></li> + <li><span id="result_box" lang="pt"><span>É portátil, com versões para diferentes sistemas operacionais, como Microsoft Windows, OS X, Linux, Solaris, FreeBSD, OpenBSD, WebOS e NonStop.</span> <span>Além disso, tem excelente suporte de muitos provedores de hospedagem na web, que muitas vezes fornecem documentação e infraestrutura específica para hospedar sites desenvolvidos em Node.</span></span></li> + <li>P<span id="result_box" lang="pt"><span>ossui uma comunidade de desenvolvedores e um ecossistema muito ativo, com muitas pessoas dispostas a ajudar.</span></span></li> +</ul> + +<p>Você pode utilizar o Node.js para criar um simples servidor web, utilizando o pacote Node HTTP.</p> + +<h3 id="Olá_Node.js">Olá, Node.js</h3> + +<p>O exemplo a seguir cria um servidor web que escuta qualquer tipo de requisição HTTP na URL <code>http://127.0.0.1:8000/</code> -- quando uma requisição é recebida, o script vai responder com a string (texto) "Olá Mundo". Se você já instalou o Node, você pode seguir os passos seguintes deste exemplo.</p> + +<ol> + <li>Abre o Terminal (no Windows, abra o prompt da linha de comando)</li> + <li>Crie uma pasta onde você quer salvar o programa, por exemplo, <code>test-node</code>. Então, entre na pasta com o seguinte comando no terminal:</li> +</ol> + +<pre class="notranslate">cd test-node +</pre> + +<p>Use o seu editor de texto preferido, crie um arquivo chamado <code>hello.js</code> e cole o código a seguir:</p> + +<pre class="brush: js notranslate">// Carrega o modulo HTTP do Node +var http = require("http"); + +// Cria um servidor HTTP e uma escuta de requisições para a porta 8000 +http.createServer(function(request, response) { + + // Configura o cabeçalho da resposta com um status HTTP e um Tipo de Conteúdo + response.writeHead(200, {'Content-Type': 'text/plain'}); + + // Manda o corpo da resposta "Olá Mundo" + response.end('Olá Mundo\n'); +}).listen(8000, '127.0.0.1'); + +// Imprime no console a URL de acesso ao servidor +console.log('Servidor executando em http://127.0.0.1:8000/');</pre> + +<p>Salve o arquivo na pasta que você criou acima.</p> + +<p>Por último, vá para o terminal e digite o comando a seguir:</p> + +<p><code>node hello.js</code></p> + +<p>Enfim, abra o browser e digite <code>http://localhost:8000.</code> Você verá o texto "<strong>Olá, Mundo</strong>", no canto superior esquerdo.</p> + +<h2 id="Web_Frameworks">Web Frameworks</h2> + +<p>Algumas tarefas comuns no desenvolvimento web não são suportadas diretamente pelo Node. Se você quiser que a sua aplicação possua diferentes verbos HTTP (por exemplo <code>GET</code>, <code>POST</code>, <code>DELETE</code>, etc), que gerencie requisições de diferentes URLs ("rotas"), apresente arquivos estáticos ou utilize templates para mostrar as respostas (response) de maneira dinâmica, você não terá muita praticidade usando apenas o Node. Você terá duas opções. Escrever o código por conta própria ou então evitar todo esse trabalho de reinventar a roda ao utilizar um framework.</p> + +<h2 id="Introduzindo_o_Express">Introduzindo o Express</h2> + +<p><a href="https://expressjs.com/">Express</a> é o framework Node mais popular e a biblioteca subjacente para uma série de outros frameworks do Node. O Express oferece soluções para:</p> + +<ul> + <li>Gerenciar requisições de diferentes verbos HTTP em diferentes URLs.</li> + <li>Integrar "view engines" para inserir dados nos templates<span id="result_box" lang="pt"><span>.</span></span></li> + <li>Definir as configurações comuns da aplicação web, como a porta a ser usada para conexão e a localização dos modelos que são usados para renderizar a resposta.</li> + <li><span id="result_box" lang="pt"><span>Adicionar novos processos de requisição por meio de "middleware" em qualquer ponto da "fila" de requisições.</span></span></li> +</ul> + +<p>O <em>Express </em>é bastante minimalista, no entanto, os desenvolvedores têm liberdade para criar pacotes de middleware específicos com o objetivo de resolver problemas específicos que surgem no desenvolvimento de uma aplicação. Há bibliotecas para trabalhar com cookies, sessões, login de usuários, parâmetros de URL, dados em requisições POST, cabeçalho de segurança e tantos outros. Você pode achar uma lista de pacotes de middleware mantidos pela equipe Express em <a href="http://expressjs.com/en/resources/middleware.html">Express Middleware</a> <span id="result_box" lang="pt"><span>(juntamente com uma lista de pacotes populares desenvolvidos por terceiros).</span></span></p> + +<div class="note"> +<p><strong>Nota:</strong> <span id="result_box" lang="pt"><span>Essa flexibilidade do Express é uma espada de dois gumes.</span> <span>Há pacotes de middleware para resolver quase qualquer problema ou requisito ao longo do desenvolvimento, mas utilizar os pacotes corretos para cada situação às vezes se torna um grande desafio.</span> <span>Não há "caminho certo" para estruturar um aplicativo. Muitos exemplos que você encontra na Internet não são bons ou mostram apenas uma pequena parte do que você precisa fazer para desenvolver uma aplicação web.</span></span></p> +</div> + +<h2 id="De_onde_o_Node_e_o_Express_vieram"><span class="short_text" id="result_box" lang="pt"><span>De onde o Node e o Express vieram?</span></span></h2> + +<p><span id="result_box" lang="pt"><span>Node foi inicialmente lançado em 2009, mas naquela época apenas para Linux. O gerenciador de pacotes NPM veio no ano seguinte, 2010, e o suporte nativo do Windows chegou em 2012. A versão atual do </span></span>Long Term Support (LTS)<span lang="pt"><span> é o Node v8.9.3, enquanto a versão mais recente é o Node 9. Esse é um resumo da rica histórica do Node, mas é possível conhecer mais na</span><span> </span></span><a href="https://pt.wikipedia.org/wiki/Node.js#History">Wikipédia</a><span lang="pt"><span>.</span></span></p> + +<p><span id="result_box" lang="pt"><span>O Express foi lançado em novembro de 2010 e atualmente está na versão 4.16 da API.</span> <span>Você pode verificar o </span></span> <a href="https://expressjs.com/en/changelog/4x.html">changelog</a> <span lang="pt"><span> para obter informações sobre as mudanças na versão atual e o </span></span><a href="https://github.com/expressjs/express/blob/master/History.md">GitHub</a><span lang="pt"><span> para obter notas detalhadas das versões históricas.</span></span></p> + +<h2 id="O_quão_popular_é_NodeExpress">O quão popular é Node/Express ?</h2> + +<p><span id="result_box" lang="pt"><span>É importante considerar a popularidade de um framework web porque indica se a ferramenta continuará sendo mantida e atualizada, além de apontar quais recursos provavelmente estarão disponíveis na documentação, nas bibliotecas de complemento e no suporte técnico.</span></span></p> + +<p><span id="result_box" lang="pt"><span>Não há nenhum número capaz de medir precisamente a popularidade de um framework (apesar de que alguns sites como o <a href="http://hotframeworks.com/">Hot Frameworks</a> avaliarem a popularidade a partir do número de projetos do GitHub e do número de perguntas do StackOverflow relativas a cada tecnologia).</span></span><span id="result_box" lang="pt"><span> Diante dessa limitação, o mais importante é fazermos algumas outras perguntas para saber se o Node e o Express são "suficientemente populares" para não caírem nos problemas clássicos das tecnologias com pouca adesão da comunidade.</span></span></p> + +<p><span style="">O Node e o Express continuam a evoluir ?</span><span style=""> </span><span style="">Você pode obter ajuda na comunidade caso precise?</span><span style=""> </span><span style="">Existe uma oportunidade para você receber trabalho remunerado ao dominar o Node e o Express ?</span></p> + +<p>Baseado no <a href="https://expressjs.com/en/resources/companies-using-express.html">número de empresas de alto perfil</a> que usam Express, no número de pessoas contribuindo para o código base, e no número de pessoas que oferecem suporte (gratuito ou pago), a reposta é sim. O Node e o Express são tecnologias populares!</p> + +<h2 id="Express_é_opinativo">Express é opinativo ?</h2> + +<p><span id="result_box" lang="pt"><span>Os frameworks web costumam se autodeclararem "opinativos" ou "não opinativos".</span></span></p> + +<p><span id="result_box" lang="pt"><span>Os frameworks opinativos são aqueles com "opiniões" sobre o "caminho certo" para lidar com qualquer tarefa específica.</span> <span>Muitas vezes, apoiam o desenvolvimento rápido em um domínio particular (resolvendo problemas de um tipo específico) porque a maneira correta de fazer qualquer coisa geralmente é bem compreendida e bem documentada.</span> <span>No entanto, são menos flexíveis na resolução de problemas fora de seu domínio principal e tendem a oferecer menos opções para quais componentes e abordagens podem usar nesses casos.</span></span></p> + +<p>Frameworks não opinativos<span id="result_box" lang="pt"><span>, por outro lado, têm muito menos restrições sobre a melhor maneira de utilizar componentes para atingir um objetivo, ou mesmo quais componentes devem ser usados.</span> <span>Eles tornam mais fácil para os desenvolvedores usar as ferramentas mais adequadas para completar uma tarefa específica, embora você precise encontrar esses componentes por si próprio.</span></span></p> + +<p>Express é um framework não opinativo. Você pode inserir qualquer middleware que você goste no manuseio das solicitações em quase qualquer ordem que desejar. Pode estruturar o aplicativo em um arquivo ou em vários, usar qualquer estrutura de pastas dentro do diretório principal, etc.</p> + +<h2 id="Como_se_parece_o_código_do_Express">Como se parece o código do Express ?</h2> + +<p><span id="result_box" lang="pt"><span>Em um site tradicional baseado em dados, um aplicativo da Web aguarda pedidos HTTP do navegador da web (ou outro cliente).</span> <span>Quando um pedido é recebido, o aplicativo descreve quais ações são necessárias com base no padrão de URL e possivelmente informações associadas contidas em dados POST ou GET.</span> <span>Dependendo do que é necessário, pode-se ler ou escrever informações em um banco de dados ou executar outras tarefas necessárias para satisfazer a solicitação.</span> <span>O aplicativo retornará uma resposta ao navegador da Web, criando, de forma dinâmica, uma página HTML para o navegador, exibindo e inserindo os dados recuperados em espaços reservados em um modelo HTML.</span></span></p> + +<p><span id="result_box" lang="pt"><span>Express fornece métodos para especificar qual função é chamada quando chega requisição HTTP (GET, POST, SET, etc.) e de rotas e métodos para especificar o mecanismo de modelo ("view") usado, onde o modelo</span> <span>arquivos estão localizados e qual modelo usar para renderizar uma resposta.</span> <span>Você pode usar o middleware Express para adicionar suporte para cookies, sessões e usuários, obtendo parâmetros POST / GET, etc. Você pode usar qualquer mecanismo de banco de dados suportado por Node (o Express não define nenhum comportamento relacionado a banco de dados).</span></span></p> + +<p><span id="result_box" lang="pt"><span>As seções a seguir explicam algumas das coisas comuns que você verá ao trabalhar com o código Express e Node.</span></span></p> + +<h3 id="Olá_Mundo_Express">Olá Mundo Express</h3> + +<p><span id="result_box" lang="pt"><span>Primeiro, considere o padrão do exemplo do Express </span></span><a href="http://expressjs.com/pt-br/starter/hello-world.html">Olá Mundo</a><span lang="pt"><span> (discutiremos cada trecho do código nas seções abaixo e nas seções a seguir).</span></span></p> + +<div class="note"> +<p><strong>Dica:</strong> <span id="result_box" lang="pt"><span>Se você tiver o Node e o Express já instalados (ou se você os instalar como mostrado no </span></span><a href="/pt-BR/docs/Learn/Server-side/Express_Nodejs/development_environment">próximo artigo</a><span lang="pt"><span>, você pode salvar este código em um arquivo chamado <strong>app.js</strong> e executá-lo em um prompt, ao digitar o comando</span></span> <code>node app.js</code>.</p> +</div> + +<pre class="brush: js notranslate">var express = require('express'); +var app = express(); + +<strong>app.get('/', function(req, res) { + res.send('Olá Mundo!'); +});</strong> + +app.listen(3000, function() { + console.log('App de Exemplo escutando na porta 3000!'); +}); +</pre> + +<p>As duas primeiras linhas <code>require()</code> importam o módulo Express e criam uma aplicação <a href="https://expressjs.com/en/4x/api.html#app">Express</a>. Esse objeto (tradicionalmente nomeado de <code>app</code>), tem métodos de roteamento de requisições HTTP, configurações de middleware, renderização de views HTML, registro de engines de templates e <span id="result_box" lang="pt"><span>modificação das <a href="https://expressjs.com/en/4x/api.html#app.settings.table">configurações</a> que controlam como o aplicativo se comporta (por exemplo, o modo de ambiente, se as definições de rota são sensíveis a maiúsculas e minúsculas, etc).</span></span></p> + +<p><span id="result_box" lang="pt"><span>A parte do meio do código (as três linhas que começam com </span></span><code>app.get</code><span lang="pt"><span>) mostra uma definição de rota.</span> <span>O método </span></span><code>app.get()</code><span lang="pt"><span> especifica uma função de retorno de chamada que será invocada sempre que exista uma solicitação HTTP </span></span><code>GET</code><span lang="pt"><span> com um caminho (</span></span><code>'/'</code><span lang="pt"><span>) relativo à raiz do site.</span> <span>A função de retorno de chamada requer uma solicitação e um objeto de resposta como argumentos, e simplesmente chama </span></span><code><a href="https://expressjs.com/en/4x/api.html#res.send">send()</a></code><span lang="pt"><span> na resposta para retornar a string "Olá Mundo!"</span></span></p> + +<p><span id="result_box" lang="pt"><span>O bloco final inicia o servidor na porta '3000' e imprime um comentário de log no console.</span> <span>Com o servidor em execução, você pode acessar o </span></span><code>localhost:3000</code><span lang="pt"><span> em seu navegador para ver o exemplo de resposta retornado.</span></span></p> + +<h3 id="Importando_e_criando_módulos">Importando e criando módulos</h3> + +<p><span id="result_box" lang="pt"><span>Um módulo é uma biblioteca/arquivo de JavaScript que você pode importar para outro código usando a função </span></span><code>require()</code><span lang="pt"><span> do Node.</span> <span>Express por si é um módulo, assim como as bibliotecas de middleware e banco de dados que usamos em nossos aplicativos Express.</span></span></p> + +<p><span lang="pt"><span>O código abaixo mostra como importamos um módulo por nome, usando o quadro Express como um exemplo.</span> <span>Primeiro invocamos a função </span></span><code style="font-style: normal; font-weight: normal;">require()</code><span lang="pt"><span>, especificando o nome do módulo como uma string </span></span>(<code>'express'</code>), <span lang="pt"><span>e chamando o objeto retornado para criar um </span></span><a href="https://expressjs.com/en/4x/api.html#app">aplicativo Express</a><span lang="pt"><span>.</span> <span>Podemos então acessar as propriedades e funções do objeto da aplicação.</span></span></p> + +<pre class="brush: js notranslate">var express = require('express'); +var app = express(); +</pre> + +<p>Você também pode criar seus próprios módulos para serem importados da mesma maneira.</p> + +<div class="note"> +<p><strong>Dica:</strong> Você vai <em><strong>querer</strong></em> criar seus próprios módulos <span id="result_box" lang="pt"><span>porque isso permite que você organize seu código em peças gerenciáveis - um aplicativo monolítico (de arquivo único) é difícil de entender e manter.</span> <span>O uso de módulos também ajuda você a gerenciar o namespace, pois somente as variáveis que você exporta explicitamente são importadas quando você usa um módulo.</span></span></p> +</div> + +<p>Para tornar os objetos disponíveis fora do módulo, você precisa apenas atribuí-los ao objeto <code>exports</code>. Por Exemplo, o módulo <strong>square.js</strong> abaixo é um arquivo que exporta os métodos <code>area()</code> e <code>perimeter()</code>:</p> + +<pre class="brush: js notranslate">exports.area = function(width) { return width * width; }; +exports.perimeter = function(width) { return 4 * width; }; +</pre> + +<p>Nós podemos importar este módulo usando <code>require()</code>. D<span class="short_text" id="result_box" lang="pt"><span>epois, conecte ao(s) método(s) exportado(s) como mostrado a seguir:</span></span></p> + +<pre class="brush: js notranslate">var square = require('./square'); // Chamamos o arquivo utilizando o require() +console.log('The area of a square with a width of 4 is ' + square.area(4));</pre> + +<div class="note"> +<p><strong>Nota:</strong> <span id="result_box" lang="pt"><span>Você também pode especificar um caminho absoluto para o módulo (ou um nome, como fizemos inicialmente).</span></span></p> +</div> + +<p><span id="result_box" lang="pt"><span>Se você deseja exportar um objeto completo em uma atribuição, em vez de criar uma propriedade de cada vez, atribua ao module.exports como mostrado abaixo (você também pode fazer isso para tornar a raiz do objeto exporter um construtor ou outra função)</span><span>:</span></span></p> + +<pre class="brush: js notranslate">module.exports = { + area: function(width) { + return width * width; + }, + + perimeter: function(width) { + return 4 * width; + } +}; +</pre> + +<p>Para muitas outras informações sobre módulos veja <a href="https://nodejs.org/api/modules.html#modules_modules">Módulos</a> (Node API docs).</p> + +<h3 id="Usando_APIs_assíncronas">Usando APIs assíncronas</h3> + +<p>O código JavaScript frequentemente usa APIs assíncronas em vez de síncronas para operações que podem levar algum tempo para serem concluídas. <span id="result_box" lang="pt"><span>Uma API síncrona é aquela em que cada operação deve ser concluída antes que a próxima operação seja iniciada.</span> <span>Por exemplo, as seguintes funções de log são síncronas e imprimirão o texto no console em ordem (Primeiro, Segundo).</span></span></p> + +<pre class="brush: js notranslate">console.log('Primeiro'); +console.log('Segundo');</pre> + +<div id="gt-res-content"> +<div class="trans-verified-button-small" dir="ltr" id="gt-res-dir-ctr"><span id="result_box" lang="pt"><span>Em contrapartida, uma API assíncrona é aquela em que a API iniciará uma operação e retornará imediatamente (antes da conclusão da operação).</span> <span>Assim que a operação terminar, a API usará algum mecanismo para executar operações adicionais.</span> <span>Por exemplo, o código abaixo imprimirá "Segundo, Primeiro". Isso porque, mesmo que o método </span></span><code>setTimeout()</code><span lang="pt"><span> seja chamado primeiro e retornae imediatamente, a operação precisa de três segundos para finalizar.</span></span></div> + +<div class="trans-verified-button-small" dir="ltr"></div> +</div> + +<pre class="brush: js notranslate">setTimeout(function() { + console.log('Primeiro'); + }, 3000); +console.log('Segundo'); +</pre> + +<p><span id="result_box" lang="pt"><span>O uso de APIs assíncronas não bloqueadoras é ainda mais importante no Node do que no navegador, pois o Node é um ambiente de execução orientado por evento único (single threaded).</span> <span>"Single threaded" significa que todos os pedidos para o servidor são executados no mesmo tópico (em vez de serem gerados em processos separados).</span> <span>Esse modelo é extremamente eficiente em termos de velocidade e recursos do servidor, mas isso significa que, se qualquer uma das suas funções chamar métodos síncronos que demoram muito para completar, eles bloquearão não apenas a solicitação atual, mas todas as outras solicitações serão tratadas por</span> <span>sua aplicação web.</span></span></p> + +<p><span id="result_box" lang="pt"><span>Há várias maneiras de uma API assíncrona notificar para a aplicação que alguma função chegou ao fim.</span> <span>A maneira mais comum é registrar uma função de retorno de chamada quando você invoca a API assíncrona, que será chamada de volta quando a operação for concluída.</span> <span>Usamos essa abordagem acima.</span></span></p> + +<div class="note"> +<p><strong>Dica:</strong> O uso de callbacks pode ser bastante "bagunçado" se você tiver uma sequência de operações assíncronas dependentes que devem ser executadas em ordem, porque isto resulta em multiplo níveis de callbacks aninhados. Este problema é comumente conhecido como "inferno de callback" ou "código hadouken". Pode-se reduzir o problema ao adotar boas práticas de programação (veja <a href="http://callbackhell.com/">http://callbackhell.com/</a>), utilizar um módulo como <a href="https://www.npmjs.com/package/async">async</a>, <span class="short_text" id="result_box" lang="pt"><span>ou mesmo adotar recursos do ES6, como</span></span> <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promises</a>.</p> +</div> + +<div class="note"> +<p><strong>Dica:</strong> <span id="result_box" lang="pt"><span>Uma convenção comum para Node e Express é usar as devoluções de retorno de erro.</span> <span>Nesta convenção, o primeiro valor em suas funções de retorno de chamada é um valor de erro, enquanto os argumentos subseqüentes contêm dados de sucesso.</span></span> <span id="result_box" lang="pt"><span>Há uma boa explicação de por que essa abordagem é útil neste blog</span></span>: <a href="http://fredkschott.com/post/2014/03/understanding-error-first-callbacks-in-node-js">The Node.js Way - Understanding Error-First Callbacks</a> (fredkschott.com).</p> +</div> + +<h3 id="Criando_manipuladores_de_rotas"><span class="short_text" id="result_box" lang="pt"><span>Criando manipuladores de rotas</span></span></h3> + +<p>No nosso <em>Olá Mundo</em> em Express (veja acima), nós definimos uma (callback) função manipuladora de rota para requisição <code>GET</code> HTTP para a raiz do site (<code>'/'</code>).</p> + +<pre class="brush: js notranslate">app.<strong>get</strong>('/', function(req, res) { + res.send('Olá Mundo'); +}); +</pre> + +<p><span id="result_box" lang="pt"><span>A função de retorno de chamada requer uma solicitação e um objeto de resposta como argumento.</span> <span>Neste caso, o método simplesmente chama </span></span><code><a href="https://expressjs.com/en/4x/api.html#res.send">send()</a></code><span lang="pt"><span> na resposta para retornar a string "Olá Mundo!"</span> <span><a href="https://expressjs.com/en/guide/routing.html#response-methods">Há uma série de outros métodos de resposta</a> para encerrar o ciclo de solicitação / resposta, por exemplo, você poderia chamar </span></span><code><a href="https://expressjs.com/en/4x/api.html#res.json">res.json()</a></code><span lang="pt"><span> para enviar uma resposta JSON ou </span></span><code><a href="https://expressjs.com/en/4x/api.html#res.sendFile">res.sendFile()</a></code> <span lang="pt"><span> para enviar um arquivo.</span></span></p> + +<div class="note"> +<p><strong>Dica JavaScript:</strong> <span id="result_box" lang="pt"><span>Você pode usar qualquer argumento que você gosta nas funções de retorno de chamada.</span> <span>Quando o retorno de chamada é invocado, o primeiro argumento sempre será o pedido e o segundo sempre será a resposta.</span> <span>Faz sentido nomeá-los de tal forma que você possa identificar o objeto que você está trabalhando no corpo do retorno de chamada.</span></span></p> +</div> + +<p><span id="result_box" lang="pt"><span>O Express também fornece métodos para definir manipuladores de rotas para todas as outras requisições HTTP, que são usadas exatamente da mesma maneira: </span></span> <code>post()</code>, <code>put()</code>, <code>delete()</code>, <code>options()</code>, <code>trace()</code>, <code>copy()</code>, <code>lock()</code>, <code>mkcol()</code>, <code>move()</code>, <code>purge()</code>, <code>propfind()</code>, <code>proppatch()</code>, <code>unlock()</code>, <code>report()</code>, <code>mkactivity()</code>, <code>checkout()</code>, <code>merge()</code>, <code>m-</code><code>search()</code>, <code>notify()</code>, <code>subscribe()</code>, <code>unsubscribe()</code>, <code>patch()</code>, <code>search()</code>, e <code>connect()</code>.</p> + +<p><span id="result_box" lang="pt"><span>Há um método de roteamento especial, </span></span><code>app.all()</code><span lang="pt"><span>, que será chamado em resposta a qualquer método HTTP.</span> <span>É usado para carregar funções de middleware em um caminho específico para todos os métodos de solicitação.</span> <span>O exemplo a seguir (da documentação Express) mostra um manipulador que será executado para solicitações </span></span><code>/secret</code><span lang="pt"><span>, independentemente do verbo HTTP usado (desde que seja suportado pelo módulo http).</span></span></p> + +<pre class="brush: js notranslate">app.all('/secret', function(req, res, next) { + console.log('Acessando a sessão secreta...'); + next(); // passa o controle para o próximo manipulador +});</pre> + +<p><span id="result_box" lang="pt"><span>As rotas permitem combinar padrões de caracteres específicos em um URL e extrair alguns valores do URL e passá-los como parâmetros para o manipulador de rotas (como atributos do objeto de solicitação passado como parâmetro).</span></span></p> + +<p><span id="result_box" lang="pt"><span>Muitas vezes, é útil agrupar manipuladores de rotas para uma determinada parte de um site e acessá-los usando um prefixo de rota comum (por exemplo, um site com um Wiki pode ter todas as rotas relacionadas ao wiki em um arquivo e tê-los acessado com um prefixo de rota</span> <span>de / wiki /).</span> <span>Em Express, isso é alcançado usando o objeto </span></span><code><a href="http://expressjs.com/en/guide/routing.html#express-router">express.Router</a></code><span lang="pt"><span>.</span> <span>Por exemplo, podemos criar nossa rota wiki em um módulo chamado wiki.js e, em seguida, exportar o objeto </span></span><code>Router</code><span lang="pt"><span>, conforme mostrado abaixo:</span></span></p> + +<pre class="brush: js notranslate">// wiki.js - Rotas de Wiki + +var express = require('express'); +var router = express.Router(); + +// Home page route +router.get('/', function(req, res) { + res.send('Wiki home page'); +}); + +// About page route +router.get('/about', function(req, res) { + res.send('About this wiki'); +}); + +module.exports = router; +</pre> + +<div class="note"> +<p><strong>Nota:</strong> <span id="result_box" lang="pt"><span>Adicionar rotas ao objeto </span></span><code>Router</code><span lang="pt"><span> é como adicionar rotas ao objeto </span></span><code>app</code><span lang="pt"><span> (como mostrado anteriormente).</span></span></p> +</div> + +<p><span id="result_box" lang="pt"><span>Para usar o roteador em nosso arquivo de aplicativo principal, então, </span></span><code>require()</code><span lang="pt"><span> o módulo de rota (<strong>wiki.js</strong>) e depois </span></span><code>use()</code><span lang="pt"><span> no aplicativo Express para adicionar o Router ao caminho de gerenciamento de middleware.</span> <span>As duas rotas serão acessíveis a partir de </span></span><code style="font-style: normal; font-weight: normal;">/wiki/</code><span lang="pt"><span> e </span></span><code style="font-style: normal; font-weight: normal;">/wiki/about/</code><span lang="pt"><span>.</span></span></p> + +<pre class="brush: js notranslate">var wiki = require('./wiki.js'); +// ... +app.use('/wiki', wiki);</pre> + +<p><span id="result_box" lang="pt"><span>Vamos mostrar-lhe muito mais sobre trabalhar com rotas e, em particular, sobre o uso do </span></span><code>Router</code><span lang="pt"><span>, mais tarde, na seção vinculada <a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Express_Nodejs/routes">Rotas e controladores</a>.</span></span></p> + +<h3 id="Usando_middleware">Usando middleware</h3> + +<p><span id="result_box" lang="pt"><span>O Middleware é usado extensivamente em aplicativos Express para que as tarefas ofereçam arquivos estáticos ao tratamento de erros, a comprensão de respostas HTTP.</span> <span>Enquanto as funções de rota terminam o ciclo de solicitação-resposta HTTP, retornando alguma resposta ao cliente HTTP, as funções de middleware normalmente executam alguma operação na solicitação ou resposta e, em seguida, ligue para a próxima função na "pilha", que pode ser mais um middleware ou uma rota</span> <span>manipuladora.</span> <span>A ordem em que o middleware é chamado depende do desenvolvedor do aplicativo.</span></span></p> + +<div class="note"> +<p><strong>Nota:</strong> <span id="result_box" lang="pt"><span>O middleware pode executar qualquer operação, executar qualquer código, fazer alterações no objeto de solicitação e resposta, e também pode encerrar o ciclo de solicitação-resposta.</span> <span>Se não terminar o ciclo, ele deve chamar o </span></span><code>next()</code><span lang="pt"><span> para passar o controle para a próxima função de middleware (ou a solicitação ficará pendurada).</span></span></p> +</div> + +<p><span id="result_box" lang="pt"><span>A maioria dos aplicativos usará middleware de terceiros para simplificar tarefas comuns de desenvolvimento web, como trabalhar com cookies, sessões, autenticação de usuários, acessar dados </span></span><code>POST</code><span lang="pt"><span> e JSON, log, etc. Você pode encontrar uma<a href="http://expressjs.com/en/resources/middleware.html"> lista de pacotes de middleware</a> mantidos pela equipe Express</span> <span>(que também inclui outros pacotes populares de terceiros).</span> <span>Outros pacotes Express estão disponíveis no gerenciador de pacotes do NPM.</span></span></p> + +<p><span id="result_box" lang="pt"><span>Para usar middleware de terceiros, primeiro você precisa instalá-lo em seu aplicativo usando NPM.</span> <span>Por exemplo, para instalar o logger </span></span><a href="http://expressjs.com/en/resources/middleware/morgan.html">morgan</a><span lang="pt"><span> HTTP, você faria isso:</span></span></p> + +<pre class="brush: bash notranslate"><code>$ npm install morgan +</code></pre> + +<p><span id="result_box" lang="pt"><span>Você pode então chamar </span></span><code>use()</code><span lang="pt"><span> no objeto do aplicativo Express para adicionar o middleware à pilha:</span></span></p> + +<pre class="brush: js notranslate">var express = require('express'); +<strong>var logger = require('morgan');</strong> +var app = express(); +<strong>app.use(logger('dev'));</strong> +...</pre> + +<div class="note"> +<p><strong>Nota:</strong> <span id="result_box" lang="pt"><span>O middleware e as funções de roteamento são chamadas na ordem em que são declaradas.</span> <span>Para alguns middleware, a ordem é importante (por exemplo, se o middleware de sessão depende do middleware de cookies, então o manipulador de cookies deve ser adicionado primeiro).</span> <span>É quase sempre o caso em que o middleware é chamado antes de definir rotas, ou seus manipuladores de rotas não terão acesso à funcionalidade adicionada pelo seu middleware.</span></span></p> +</div> + +<p><span id="result_box" lang="pt"><span>Você pode escrever suas próprias funções de middleware. É provável que você tenha que fazê-lo (somente para criar código de manipulação de erro).</span> <span>A única diferença entre uma função de middleware e um retorno de chamada de manipulador de rotas é que as funções de middleware têm um terceiro argumento </span></span><code>next</code><span lang="pt"><span>, que as funções de middleware devem chamar se não completam o ciclo de solicitação (quando a função de middleware é chamada, isso contém a próxima função</span> <span>que deve ser chamado).</span></span></p> + +<p><span id="result_box" lang="pt"><span>Você pode adicionar uma função de middleware à cadeia de processamento com </span></span><code>app.use()</code><span lang="pt"><span> ou </span></span><code>app.add()</code><span lang="pt"><span>, dependendo se você deseja aplicar o middleware a todas as respostas ou a respostas com um verbo HTTP específico (</span></span><code>GET</code>, <code>POST</code><span lang="pt"><span>, etc.</span> <span>).</span> <span>Você especifica rotas o mesmo em ambos os casos, embora a rota seja opcional ao chamar </span></span><strong>app.use()</strong><span lang="pt"><span>.</span></span></p> + +<p><span id="result_box" lang="pt"><span>O exemplo abaixo mostra como você pode adicionar a função middleware usando ambos os métodos e com/sem rota.</span></span></p> + +<pre class="brush: js notranslate">var express = require('express'); +var app = express(); + +// Um exemplo de função middleware +var a_middleware_function = function(req, res, <em>next</em>) { + // ... Executa alguma operação + next(); // next() Chama o próximo middleware ou função de rotas +} + +// Função adicionada com use() para todas rotas e requisições +app.use(a_middleware_function); + +// Função adicionada com use() para uma rota específica +app.use('/someroute', a_middleware_function); + +// função middleware adicionado para uma rota e requisição específica +app.get('/', a_middleware_function); + +app.listen(3000);</pre> + +<div class="note"> +<p><strong>Dica JavaScript:</strong> <span id="result_box" lang="pt"><span>Acima, declaramos a função de middleware separadamente e, em seguida, configuramos como retorno de chamada.</span> <span>Na nossa função anterior do operador de rotas, declaramos a função de retorno de chamada quando foi utilizada.</span> <span>Em JavaScript, ambas abordagens são válidas.</span></span></p> +</div> + +<p><span id="result_box" lang="pt"><span>A documentação Express possui uma documentação excelente sobre como usar e escrever o middleware Express.</span></span></p> + +<h3 id="Servindo_arquivos_estáticos">Servindo arquivos estáticos</h3> + +<p><span id="result_box" lang="pt"><span>Você pode usar o middleware </span></span><a href="http://expressjs.com/en/4x/api.html#express.static">express.static</a><span lang="pt"><span> para servir arquivos estáticos, incluindo suas imagens, CSS e JavaScript (</span></span><code>static()</code><span lang="pt"><span> é a única função de middleware que é realmente parte do Express).</span> <span>Por exemplo, você usaria a linha abaixo para exibir imagens, arquivos CSS e arquivos JavaScript de um diretório chamado 'public' no mesmo nível onde você chama o nó:</span></span></p> + +<pre class="brush: js notranslate">app.use(express.static('public')); +</pre> + +<p><span id="result_box" lang="pt"><span>Todos os arquivos no diretório público são atendidos adicionando o nome do arquivo (relativo ao diretório "público" base) ao URL base.</span> <span>Então, por exemplo:</span></span></p> + +<pre class="notranslate"><code>http://localhost:3000/images/dog.jpg +http://localhost:3000/css/style.css +http://localhost:3000/js/app.js +http://localhost:3000/about.html +</code></pre> + +<p><span id="result_box" lang="pt"><span>Você pode chamar </span></span><code>static()</code><span lang="pt"><span> várias vezes para atender vários diretórios.</span> <span>Se um arquivo não puder ser encontrado por uma função de middleware, ele simplesmente será transmitido ao middleware subsequente (a ordem em que o middleware é chamado é baseada em sua ordem de declaração).</span></span></p> + +<pre class="brush: js notranslate">app.use(express.static('public')); +app.use(express.static('media')); +</pre> + +<p><span id="result_box" lang="pt"><span>Você também pode criar um prefixo virtual para seus URL estáticos, em vez de ter os arquivos adicionados ao URL base.</span> <span>Por exemplo, aqui <a href="http://expressjs.com/en/4x/api.html#app.use">especificamos um caminho de montagem</a> para que os arquivos sejam carregados com o prefixo "/media":</span></span></p> + +<pre class="brush: js notranslate">app.use('/media', express.static('public')); +</pre> + +<p><span id="result_box" lang="pt"><span>Agora, você pode carregar os arquivos que estão no diretório </span></span><code>public</code><span lang="pt"><span> a partir do prefixo de caminho </span></span><code>/media</code><span lang="pt"><span>.</span></span></p> + +<pre class="notranslate"><code>http://localhost:3000/media/images/dog.jpg +http://localhost:3000/media/video/cat.mp4 +http://localhost:3000/media/cry.mp3</code> +</pre> + +<p><span id="result_box" lang="pt"><span>Para obter mais informações, consulte <a href="Serving static files in Express">Servindo arquivos estáticos no Express</a>.</span></span></p> + +<h3 id="Erros_de_manipulação">Erros de manipulação</h3> + +<p><span id="result_box" lang="pt"><span>Os erros são tratados por uma ou mais funções de middleware especiais que possuem quatro argumentos, em vez dos três habituais: </span></span><code>(err, req, res, next)</code><span lang="pt"><span>.</span> <span>Por exemplo:</span></span></p> + +<pre class="brush: js notranslate">app.use(function(err, req, res, next) { + console.error(err.stack); + res.status(500).send('Something broke!'); +}); +</pre> + +<p><span id="result_box" lang="pt"><span>Isso pode retornar qualquer conteúdo exigido, mas deve ser chamado depois de todas as outras chamadas </span></span><code>app.use()</code><span lang="pt"><span> e rotas para que sejam o último middleware no processo de solicitação de pedidos!</span></span></p> + +<p><span id="result_box" lang="pt"><span>Express vem com um manipulador de erros embutido, que cuida de todos os erros que podem ser encontrados no aplicativo.</span> <span>Essa função de middleware de gerenciamento de erros padrão é adicionada no final da pilha de funções do middleware.</span> <span>Se você passar um erro para </span></span><code>next()</code><span lang="pt"><span> e você não lidar com isso em um manipulador de erro, ele será tratado pelo manipulador de erros incorporado;</span> <span>o erro será gravado no cliente com o rastreamento da pilha.</span></span></p> + +<div class="note"> +<p><strong>Nota:</strong> <span id="result_box" lang="pt"><span>O rastreamento da pilha não está incluído no ambiente de produção.</span> <span>Para executá-lo no modo de produção, você precisa configurar a variável de ambiente </span></span><code>NODE_ENV</code><span lang="pt"><span> para </span></span><code>'production'</code>.</p> +</div> + +<div class="note"> +<p><strong>Nota:</strong> <span id="result_box" lang="pt"><span>HTTP404 e outros códigos de status de "erro" não são tratados como erros.</span> <span>Se você quiser lidar com isso, você pode adicionar uma função de middleware para fazê-lo.</span> <span>Para mais informações, consulte as </span></span><a href="http://expressjs.com/en/starter/faq.html#how-do-i-handle-404-responses">FAQ</a>.</p> +</div> + +<p><span id="result_box" lang="pt"><span>Para obter mais informações, consulte </span></span><a href="http://expressjs.com/en/guide/error-handling.html">Gerenciamento de erros</a><span lang="pt"><span> (Express docs).</span></span></p> + +<h3 id="Usando_Banco_de_Dados">Usando Banco de Dados</h3> + +<p><span id="result_box" lang="pt"><span>Aplicativos Express podem usar qualquer mecanismo de banco de dados suportado pelo Node (o Express em si não define nenhum comportamento/requisitos adicionais específicos para gerenciamento de banco de dados).</span> <span>Existem muitas opções, incluindo PostgreSQL, MySQL, Redis, SQLite, MongoDB, etc.</span></span></p> + +<p><span id="result_box" lang="pt"><span>Para usá-los, você deve primeiro instalar o driver do banco de dados usando NPM.</span> <span>Por exemplo, para instalar o driver para o popular NoSQL MongoDB você usaria o comando:</span></span></p> + +<pre class="brush: bash notranslate"><code>$ npm install mongodb +</code></pre> + +<p><span id="result_box" lang="pt"><span>O próprio banco de dados pode ser instalado localmente ou em um servidor em nuvem.</span> <span>No seu código Express, você precisa do driver, conecte-se ao banco de dados e execute as operações criar, ler, atualizar e excluir (CRUD).</span> <span>O exemplo abaixo (da documentação Express) mostra como você pode encontrar registros de "mamíferos" usando MongoDB.</span></span></p> + +<pre class="brush: js notranslate">var MongoClient = require('mongodb').MongoClient; + +MongoClient.connect('mongodb://localhost:27017/animals', function(err, db) { + if (err) throw err; + + db.collection('mammals').find().toArray(function (err, result) { + if (err) throw err; + + console.log(result); + }); +});</pre> + +<p><span id="result_box" lang="pt"><span>Outra abordagem popular é acessar seu banco de dados indiretamente, através de um Object Relational Mapper ("ORM").</span> <span>Nesta abordagem, você define seus dados como "objetos" ou "modelos" e o ORM mapeia estes para o formato de banco de dados subjacente.</span> <span>Esta abordagem tem o benefício de que, como desenvolvedor, você pode continuar a pensar em termos de objetos JavaScript, em vez de semântica de banco de dados, e que existe um local óbvio para realizar a validação e verificação de dados recebidos.</span> <span>Falaremos mais sobre bancos de dados em um artigo posterior.</span></span></p> + +<p><span id="result_box" lang="pt"><span>Para obter mais informações, consulte </span></span><a href="https://expressjs.com/en/guide/database-integration.html">integração com banco de dados </a><span lang="pt"><span>(documentos express).</span></span></p> + +<h3 id="Renderizando_dados_views">Renderizando dados (views)</h3> + +<p><span id="result_box" lang="pt"><span>Os mecanismos de modelo (referidos como "view engines" por Express) permitem que você especifique a estrutura de um documento de saída em um modelo, usando marcadores de posição para os dados que serão preenchidos quando uma página for gerada.</span> <span>Os modelos geralmente são usados para criar HTML, mas também podem criar outros tipos de documentos.</span> <span>Express tem suporte para uma série de <a href="https://github.com/expressjs/express/wiki#template-engines">mecanismos de modelos</a>, e há uma comparação útil dos motores mais populares aqui: </span></span><a href="https://strongloop.com/strongblog/compare-javascript-templates-jade-mustache-dust/">Comparing JavaScript Templating Engines: Jade, Mustache, Dust and More</a>.</p> + +<p><span id="result_box" lang="pt"><span>No seu código de configurações do aplicativo você configurou o mecanismo do modelo para usar e o local onde Express deve procurar modelos usando as configurações 'visualizações' e 'visualizar mecanismos', conforme mostrado abaixo (você também terá que instalar o pacote que contém a biblioteca do modelo também</span> <span>!)</span></span></p> + +<pre class="brush: js notranslate">var express = require('express'); +var app = express(); + +// <span class="short_text" id="result_box" lang="pt"><span>Definir o diretório para conter os modelos ('views')</span></span> +app.set('views', path.join(__dirname, 'views')); + +<span id="result_box" lang="pt"><span>// Definir o motor de visualização para usar, neste caso 'some_template_engine_name'</span></span> +app.set('view engine', 'some_template_engine_name'); +</pre> + +<p><span id="result_box" lang="pt"><span>A aparência do modelo dependerá do mecanismo que você usa.</span> <span>Supondo que você tenha um arquivo de modelo chamado "índice. <Template_extension>" que contenha espaços reservados para variáveis de dados denominadas 'título' e 'mensagem', você chamaria </span></span><code><a href="http://expressjs.com/en/4x/api.html#res.render">Response.render()</a></code><span lang="pt"><span> em uma função de roteador de rotas para criar e enviar a resposta HTML</span> <span>:</span></span></p> + +<pre class="brush: js notranslate">app.get('/', function(req, res) { + res.render('index', { title: 'About dogs', message: 'Dogs rock!' }); +});</pre> + +<p><span id="result_box" lang="pt"><span>Para obter mais informações, consulte </span></span><a href="http://expressjs.com/en/guide/using-template-engines.html">usando motores de modelo com Express</a><span lang="pt"><span> (Express docs).</span></span></p> + +<h3 id="Estrutura_de_Arquivos">Estrutura de Arquivos</h3> + +<p><span id="result_box" lang="pt"><span>Express não faz suposições em termos de estrutura ou quais os componentes que você usa.</span> <span>Rotas, visualizações, arquivos estáticos e outra lógica específica da aplicação podem viver em qualquer número de arquivos com qualquer estrutura de diretório.</span> <span>Embora seja perfeitamente possível ter todo o aplicativo Express em um único arquivo, geralmente faz sentido dividir seu aplicativo em arquivos com base em função (por exemplo, gerenciamento de contas, blogs, fóruns de discussão) e domínio de problema arquitetônico (por exemplo, modelo, exibição ou controlador se</span> <span>você está usando uma </span></span><a href="/en-US/docs/Web/Apps/Fundamentals/Modern_web_app_architecture/MVC_architecture">arquitetura MVC</a><span lang="pt"><span>).</span></span></p> + +<p><span id="result_box" lang="pt"><span>Em um tópico posterior, usaremos o Express Application Generator, que cria um esqueleto de aplicativo modular que podemos estender facilmente para criar aplicativos da web.</span></span></p> + +<ul> +</ul> + +<h2 id="Sumário">Sumário</h2> + +<p><span id="result_box" lang="pt"><span>Parabéns, você completou o primeiro passo em sua viagem Express/Node!</span> <span>Agora você deve entender os principais benefícios do Express e Node, e aproximadamente o que as principais partes de um aplicativo Express podem ser (rotas, middleware, tratamento de erros e código de modelo).</span> <span>Por ser um framework não opinativo, o Express permite que você defina a maneira como essas partes e essas bibliotecas são integradas.</span></span></p> + +<p><span style="">Claro que Express é deliberadamente uma estrutura de aplicativos web muito leve, tanto seu benefício e potencial vem de bibliotecas e recursos de terceiros.</span><span style=""> </span><span style="">Examinaremos essa questão com mais detalhes nos próximos artigos.</span><span style=""> </span><span style="">No artigo a seguir, vamos analisar a criação de um ambiente de desenvolvimento de Node, para que você possa começar a ver algum código Express em ação.</span></p> + +<h2 id="Veja_também">Veja também</h2> + +<ul> + <li><a href="https://medium.com/@ramsunvtech/manage-multiple-node-versions-e3245d5ede44">Venkat.R - Manage Multiple Node versions</a></li> + <li><a href="https://nodejs.org/api/modules.html#modules_modules">Modules</a> (Node API docs)</li> + <li><a href="https://expressjs.com/">Express</a> (home page)</li> + <li><a href="http://expressjs.com/en/starter/basic-routing.html">Basic routing</a> (Express docs)</li> + <li><a href="http://expressjs.com/en/guide/routing.html">Routing guide</a> (Express docs)</li> + <li><a href="http://expressjs.com/en/guide/using-template-engines.html">Using template engines with Express</a> (Express docs)</li> + <li><a href="https://expressjs.com/en/guide/using-middleware.html">Using middleware</a> (Express docs)</li> + <li><a href="http://expressjs.com/en/guide/writing-middleware.html">Writing middleware for use in Express apps</a> (Express docs)</li> + <li><a href="https://expressjs.com/en/guide/database-integration.html">Database integration</a> (Express docs)</li> + <li><a href="Serving static files in Express">Serving static files in Express</a> (Express docs)</li> + <li><a href="http://expressjs.com/en/guide/error-handling.html">Error handling</a> (Express docs)</li> +</ul> + +<div>{{NextMenu("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs")}}</div> + +<h2 id="Próximos_módulos">Próximos módulos</h2> + +<ul> + <li><a href="/pt-BR/docs/Learn/Server-side/Express_Nodejs/Introduction">Introdução Express/Node </a>- Módulo Atual</li> + <li><a href="/pt-BR/docs/Learn/Server-side/Express_Nodejs/development_environment">Configurando um ambiente de desenvolvimento Node (Express)</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: C</a>riando um esqueleto de website</li> + <li><a href="/pt-BR/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Utilizando Banco de Dados (com Mongoose)</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: R</a>otas e Controladores</li> + <li><a href="/pt-BR/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li> + <li><a href="/pt-BR/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: </a>Trabalhando com formulários</li> + <li><a href="/pt-BR/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li> +</ul> diff --git a/files/pt-br/learn/server-side/express_nodejs/mongoose/index.html b/files/pt-br/learn/server-side/express_nodejs/mongoose/index.html new file mode 100644 index 0000000000..8d733ec077 --- /dev/null +++ b/files/pt-br/learn/server-side/express_nodejs/mongoose/index.html @@ -0,0 +1,838 @@ +--- +title: 'Tutorial Express Parte 3: Usando um banco de dados (com Mongoose)' +slug: Learn/Server-side/Express_Nodejs/mongoose +translation_of: Learn/Server-side/Express_Nodejs/mongoose +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs")}}</div> + +<p class="summary">Este artigo introduz brevemente bancos de dados e como usá-los com aplicativos Node/Express. Depois demonstra como podemos usar o <a href="http://mongoosejs.com/">Mongoose</a> para prover acesso ao banco de dados para o website <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">LocalLibrary</a>. Explica como object schema e modelos são declarados, os principais tipos de campos e validações básicas. Também demonstra brevemente algumas das muitas maneiras em que se pode acessar os dados do modelo.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré-requisitos:</th> + <td><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Tutorial Express Parte 2: Criando o esqueleto de um website</a></td> + </tr> + <tr> + <th scope="row">Objetivo:</th> + <td>Ser capaz de projetar e criar seus próprios modelos usando Mongoose.</td> + </tr> + </tbody> +</table> + +<h2 id="Visão_geral">Visão geral</h2> + +<p>A equipe da biblioteca usará o site da Biblioteca Local para gardar informações sobre livros e empréstimos, enquanto os membros da biblioteca irão utilizá-lo para navegar e pesquisar por livros, descobrir se há alguma cópia disponível, e então reservar ou emprestar eles. Para armazenar e obter informações eficientemente, nós guardaremos elas em um <em>banco de dados</em>.</p> + +<p>Aplicativos <em>Express</em> podem usar muitos bancos de dados diferentes, e existem várias abordagens que você pode usar para fazer operações de Criar, Ler, Atualizar e Apagar (CRUD, na sigla em inglês). Esse tutorial provê uma curta visão geral de algumas das opções disponíveis e então irá mostrar em detalhes os mecanismos particulares selecionados.</p> + +<h3 id="Quais_bancos_de_dados_eu_posso_usar">Quais bancos de dados eu posso usar?</h3> + +<p>Aplicativos <em>Express</em> podem usar qualquer banco de dados suportado pelo <em>Node </em>(O <em>Express</em> por si só não define nenhum requerimento ou comportamento adicional específico para gerenciamento de bancos de dados). Há <a href="https://expressjs.com/en/guide/database-integration.html">muitas<em> </em>opções populares</a>, incluindo PostgreSQL, MySQL, Redis, SQLite, and MongoDB.</p> + +<p>Quando escolher um banco de dados, você deveria considerar coisas como o tempo-para-produtividade/curva de aprendizado, performance, facilidade de replicação/backup, custo, suporte da comunidade, etc. Enquanto não existe o "melhor" banco de dados, praticamente qualquer uma das soluções populares devem ser mais do que aceitáveis para um site de tamanho pequeno a médio como o da nossa Biblioteca Local.</p> + +<p>Para mais informações sobre as opções veja <a href="https://expressjs.com/en/guide/database-integration.html">Integração com o Banco de dados</a> (documentação do Express).</p> + +<h3 id="Qual_o_melhor_jeito_de_interagir_com_um_banco_de_dados">Qual o melhor jeito de interagir com um banco de dados?</h3> + +<p>There are two approaches for interacting with a database: </p> + +<ul> + <li>Using the databases' native query language (e.g. SQL)</li> + <li>Using an Object Data Model ("ODM") / Object Relational Model ("ORM"). An ODM/ORM represents the website's data as JavaScript objects, which are then mapped to the underlying database. Some ORMs are tied to a specific database, while others provide a database-agnostic backend.</li> +</ul> + +<p>The very best <em>performance</em> can be gained by using SQL, or whatever query language is supported by the database. ODM's are often slower because they use translation code to map between objects and the database format, which may not use the most efficient database queries (this is particularly true if the ODM supports different database backends, and must make greater compromises in terms of what database features are supported).</p> + +<p>The benefit of using an ORM is that programmers can continue to think in terms of JavaScript objects rather than database semantics — this is particularly true if you need to work with different databases (on either the same or different websites). They also provide an obvious place to perform validation and checking of data.</p> + +<div class="note"> +<p><strong>Tip:</strong> Using ODM/ORMs often results in lower costs for development and maintenance! Unless you're very familiar with the native query language or performance is paramount, you should strongly consider using an ODM.</p> +</div> + +<h3 id="Qual_ORMODM_eu_devo_usar">Qual ORM/ODM eu devo usar?</h3> + +<p>There are many ODM/ORM solutions available on the NPM package manager site (check out the <a href="https://www.npmjs.com/browse/keyword/odm">odm</a> and <a href="https://www.npmjs.com/browse/keyword/orm">orm</a> tags for a subset!).</p> + +<p>A few solutions that were popular at the time of writing are:</p> + +<ul> + <li><a href="https://www.npmjs.com/package/mongoose">Mongoose</a>: Mongoose is a <a href="https://www.mongodb.org/">MongoDB</a> object modeling tool designed to work in an asynchronous environment.</li> + <li><a href="https://www.npmjs.com/package/waterline">Waterline</a>: An ORM extracted from the Express-based <a href="http://sailsjs.com/">Sails</a> web framework. It provides a uniform API for accessing numerous different databases, including Redis, MySQL, LDAP, MongoDB, and Postgres.</li> + <li><a href="https://www.npmjs.com/package/bookshelf">Bookshelf</a>: Features both promise-based and traditional callback interfaces, providing transaction support, eager/nested-eager relation loading, polymorphic associations, and support for one-to-one, one-to-many, and many-to-many relations. Works with PostgreSQL, MySQL, and SQLite3.</li> + <li><a href="https://www.npmjs.com/package/objection">Objection</a>: Makes it as easy as possible to use the full power of SQL and the underlying database engine (supports SQLite3, Postgres, and MySQL).</li> + <li><a href="https://www.npmjs.com/package/sequelize">Sequelize</a> is a promise-based ORM for Node.js and io.js. It supports the dialects PostgreSQL, MySQL, MariaDB, SQLite, and MSSQL and features solid transaction support, relations, read replication and more.</li> + <li><a href="https://node-orm.readthedocs.io/en/latest/">Node ORM2</a> is an Object Relationship Manager for NodeJS. It supports MySQL, SQLite, and Progress, helping to work with the database using an object-oriented approach.</li> + <li> + <p><a href="http://1602.github.io/jugglingdb/" rel="nofollow">JugglingDB</a> is cross-DB ORM for NodeJS, providing a common interface to access most popular database formats. Currently supporting MySQL, SQLite3, Postgres, MongoDB, Redis and js-memory-storage (self-written engine for test-usage only).</p> + </li> +</ul> + +<p>As a general rule, you should consider both the features provided and the "community activity" (downloads, contributions, bug reports, quality of documentation, etc.) when selecting a solution. At the time of writing Mongoose is by far the most popular ODM, and is a reasonable choice if you're using MongoDB for your database.</p> + +<h3 id="Usando_Mongoose_e_MongoDb_para_a_LocalLibrary">Usando Mongoose e MongoDb para a LocalLibrary</h3> + +<p>Para o exemplo da <em>Local Library</em> (e para o resto do tópico) nós iremos usar o <a href="https://www.npmjs.com/package/mongoose">Mongoose ODM</a> para acessar os dados da nossa aplicação. Mongoose funciona como uma interface para o <a href="https://www.mongodb.com/what-is-mongodb">MongoDB</a>, um banco de dados de código aberto e <a href="https://en.wikipedia.org/wiki/NoSQL">NoSQL</a> que usa um modelo de dados orientado a documentos. Uma “coleção” de “documentos”, em uma base de dados do MongoDB, <a href="https://docs.mongodb.com/manual/core/databases-and-collections/#collections">é semelhante</a> a uma “tabela” com “linhas” em uma base dados relacional.</p> + +<p>Esse ODM (Object Data Model) e banco de dados combinados são extremamente populares na comunidade do Node, particularmente porque os documentos armazenados e os métodos de consultas se parecem muito com JSON, que consequentemente são muito familiares aos desenvolvedores JavaScript.</p> + +<div class="note"> +<p><strong>Dica:</strong> Você não precisa conhecer o MongoDB antes de usar o Mongoose, apesar de que partes da <a href="http://mongoosejs.com/docs/guide.html">documentação do Mongoose</a> <em>são mais fáceis</em> de entender se você já está familiarizado com o MongoDB.</p> +</div> + +<p>O resto desse tutorial mostra como definir e acessar os modelos e schemas no Mongoose para o nosso website da <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">LocalLibrary</a>.</p> + +<h2 id="Projetando_os_modelos_da_aplicação_LocalLibrary">Projetando os modelos da aplicação LocalLibrary</h2> + + + +<p>Antes de pularmos de cabeça na codificação dos modelos, vale a pena pensar uns minutinhos sobre quais dados precisamos armazenar e o relacionamento entre diferentes objetos.</p> + +<p>Nós sabemos que precisamos armazenar informações sobre livros(título, resumo, autor, gênero, ISBN) e que nós podemos ter múltiplas cópias disponíveis (com ids globlamente únicos, status de disponibilidade, etc.). Nós também podemos armazenar mais informações sobre o autor do que apenas seu nome, e podem haver múltiplos autores com o mesmo nome ou um bem parecido. Nós queremos também ser capazes de ordernar informações baseadas no título do livro, autor, gênero e categoria.</p> + +<p>Ao estruturar seus modelos é sempre bom separar modelos para cada "objeto"(um grupo de informações relacionadas). Neste caso, os nossos objetos mais evidentes são os de livros (books), pedidos de livros (book instances), e autores (authors).</p> + +<p>Você pode usar também modelos para representar opções de listagens(por exemplo um menu drop-down com escolhas para o usuário), ao invés de implementar as escolhas diretamente em linhas de códigos dentro do seu website — isso é recomendado quando as escolhas não são conhecidas durante o desenvolvimento ou quando elas podem mudar. O candidato mais evidente para um modelo desse tipo é o de gênero (genre) de livros (por exemplo Ficção Ciêntífica, Poesia Clássica, etc.).</p> + +<p>Uma vez que nós decidimos nossos modelos e os seus atributos, nós precisamos pensar sobre o relacionamento entre eles.</p> + +<p>Com isso em mente, o diagrama UML a seguir mostra os modelos (as caixas) que iremos definir na nossa aplicação. Como discutido acima, criamos modelos para os livros ( com informações genéricas sobre o livro), pedidos de livros(status de cópias físicas de um livro específico disponíveis no sistema), e autor. E também decidimos ter um modelo para o gênero então esses valores poderão ser criados dinamicamente na aplicação. Outra decisão foi de não criarmos um modelo para <code>BookInstance:status </code> — nós deixaremos diretamente no código os valores aceitáveis para o status de pedidos porque nós não esperamos que eles mudem. Dentro de cada caixa, você pode ver o nome do modelo, o nome dos atributos e seus tipos, e também os métodos e seu tipo de retorno.</p> + +<p>O diagrama também mostra o relacionamento entre modelos, incluindo sua cardinalidade. A cardinalidade são os números no diagrama próximos das linhas que conectam as caixas mostrando os números (máximo e mínimo) de cada modelo que pode estar presente no relacionamento. Por exemplo, as linhas que conectam as caixas <code>Book</code>e <code>Genre</code> mostram que as duas coleções têm uma relação. Os números próximos ao modelo <code>Book</code> mostra que Genre pode ter zero ou mais Book (quantos você quiser), enquanto no outro fim da linha de conexão próximo a <code>Genre </code> mostra que ele pode ter zero ou mais livros associados.</p> + +<div class="note"> +<p><strong>Nota</strong>: Assim como discutido abaixo em <a href="#related_documents">Iniciando com Mongoose </a> muitas vezes é melhor ter o atributo que define a relação entre os documentos/modelos em apenas um dos modelos( você ainda pode encontrar o relacionamento reverso pesquisando o <code>_id</code> associado no outro modelo). Abaixo nós escolhemos definir o modelo Book Schema para armazenar o relacionamento entre Book/Genre e Book/Author, e definimos BookInstance Schema para armazenar o relacionamento entre Book/BookInstance. Esta escolha foi um tanto arbitrária — nós poderíamos igualmente ter declarado esses atributos em outro schema.</p> +</div> + +<p><img alt="Mongoose Library Model with correct cardinality" src="https://mdn.mozillademos.org/files/15645/Library%20Website%20-%20Mongoose_Express.png" style="height: 620px; width: 737px;"></p> + +<div class="note"> +<p><strong>Nota</strong>: A próxima seção fornece um guia explicando como os modelos são definidos e usados. Ao ler, considere como iremos construir cada um dos modelos no diagrama acima.</p> +</div> + +<h2 id="Iniciando_com_Mongoose">Iniciando com Mongoose</h2> + +<p>Esta seção fornece uma visão geral de como conectar o Mongoose a um banco de dados do MongoDB, como definir um schema e um modelo, e como fazer consultas básicas.</p> + +<div class="note"> +<p><strong>Nota:</strong> Esse guia é "bastante influenciado" pelo conteúdo encontrado no <a href="https://www.npmjs.com/package/mongoose">Mongoose quick start</a> do <em>npm</em> e pela <a href="http://mongoosejs.com/docs/guide.html">documentação oficial</a>.</p> +</div> + +<h3 id="Instalando_Mongoose_e_MongoDB">Instalando Mongoose e MongoDB</h3> + +<p>O Mongoose é instalado no seu projeto (<strong>package.json</strong>) assim como outra dependência qualquer — usando NPM. Para instalá-lo, use a seguinte linha de comando dentro da pasta do seu projeto:</p> + +<pre class="brush: bash">npm install mongoose +</pre> + +<p>Installing <em>Mongoose</em> adds all its dependencies, including the MongoDB database driver, but it does not install MongoDB itself. If you want to install a MongoDB server then you can <a href="https://www.mongodb.com/download-center">download installers from here</a> for various operating systems and install it locally. You can also use cloud-based MongoDB instances.</p> + +<div class="note"> +<p><strong>Note:</strong> For this tutorial, we'll be using the MongoDB Atlas cloud-based <em>database as a service</em> <a href="https://www.mongodb.com/cloud/atlas/pricing">free tier</a> to provide the database. This is suitable for development and makes sense for the tutorial because it makes "installation" operating system independent (database-as-a-service is also one approach you might well use for your production database).</p> +</div> + +<h3 id="Conectando_ao_MongoDB">Conectando ao MongoDB</h3> + +<p><em>Mongoose</em> requires a connection to a MongoDB database. You can <code>require()</code> and connect to a locally hosted database with <code>mongoose.connect()</code>, as shown below.</p> + +<pre class="brush: js">//Import the mongoose module +var mongoose = require('mongoose'); + +//Set up default mongoose connection +var mongoDB = 'mongodb://127.0.0.1/my_database'; +mongoose.connect(mongoDB, { useNewUrlParser: true }); + +//Get the default connection +var db = mongoose.connection; + +//Bind connection to error event (to get notification of connection errors) +db.on('error', console.error.bind(console, 'MongoDB connection error:'));</pre> + +<p>You can get the default <code>Connection</code> object with <code>mongoose.connection</code>. Once connected, the open event is fired on the <code>Connection</code> instance.</p> + +<div class="note"> +<p><strong>Tip:</strong> If you need to create additional connections you can use <code>mongoose.createConnection()</code>. This takes the same form of database URI (with host, database, port, options etc.) as <code>connect()</code> and returns a <code>Connection</code> object).</p> +</div> + +<h3 id="Definindo_e_criando_modelos">Definindo e criando modelos</h3> + +<p>Models are <em>defined </em>using the <code>Schema</code> interface. The Schema allows you to define the fields stored in each document along with their validation requirements and default values. In addition, you can define static and instance helper methods to make it easier to work with your data types, and also virtual properties that you can use like any other field, but which aren't actually stored in the database (we'll discuss a bit further below).</p> + +<p>Schemas are then "compiled" into models using the <code>mongoose.model()</code> method. Once you have a model you can use it to find, create, update, and delete objects of the given type.</p> + +<div class="note"> +<p><strong>Note:</strong> Each model maps to a <em>collection</em> of <em>documents</em> in the MongoDB database. The documents will contain the fields/schema types defined in the model <code>Schema</code>.</p> +</div> + +<h4 id="Defining_schemas">Defining schemas</h4> + +<p>The code fragment below shows how you might define a simple schema. First you <code>require()</code> mongoose, then use the Schema constructor to create a new schema instance, defining the various fields inside it in the constructor's object parameter.</p> + +<pre class="brush: js">//Require Mongoose +var mongoose = require('mongoose'); + +//Define a schema +var Schema = mongoose.Schema; + +var SomeModelSchema = new Schema({ + a_string: String, + a_date: Date +}); +</pre> + +<p>In the case above we just have two fields, a string and a date. In the next sections, we will show some of the other field types, validation, and other methods.</p> + +<h4 id="Criando_um_modelo">Criando um modelo</h4> + +<p>Models are created from schemas using the <code>mongoose.model()</code> method:</p> + +<pre class="brush: js">// Define schema +var Schema = mongoose.Schema; + +var SomeModelSchema = new Schema({ + a_string: String, + a_date: Date +}); + +<strong>// Compile model from schema +var SomeModel = mongoose.model('SomeModel', SomeModelSchema );</strong></pre> + +<p>The first argument is the singular name of the collection that will be created for your model (Mongoose will create the database collection for the above model <em>SomeModel</em> above), and the second argument is the schema you want to use in creating the model.</p> + +<div class="note"> +<p><strong>Note:</strong> Once you've defined your model classes you can use them to create, update, or delete records, and run queries to get all records or particular subsets of records. We'll show you how to do this in the <a href="#Using_models">Using models</a> section, and when we create our views.</p> +</div> + +<h4 id="Schema_types_fields">Schema types (fields)</h4> + +<p>A schema can have an arbitrary number of fields — each one represents a field in the documents stored in <em>MongoDB</em>. An example schema showing many of the common field types and how they are declared is shown below.</p> + +<pre class="brush: js">var schema = new Schema( +{ + name: <strong>String</strong>, + binary: <strong>Buffer</strong>, + living: <strong>Boolean</strong>, + updated: { type: <strong>Date</strong>, default: Date.now() }, + age: { type: <strong>Number</strong>, min: 18, max: 65, required: true }, + mixed: <strong>Schema.Types.Mixed</strong>, + _someId: <strong>Schema.Types.ObjectId</strong>, + array: <strong>[]</strong>, + ofString: [<strong>String</strong>], // You can also have an array of each of the other types too. + nested: { stuff: { type: <strong>String</strong>, lowercase: true, trim: true } } +})</pre> + +<p>Most of the <a href="http://mongoosejs.com/docs/schematypes.html">SchemaTypes</a> (the descriptors after “type:” or after field names) are self-explanatory. The exceptions are:</p> + +<ul> + <li><code>ObjectId</code>: Represents specific instances of a model in the database. For example, a book might use this to represent its author object. This will actually contain the unique ID (<code>_id</code>) for the specified object. We can use the <code>populate()</code> method to pull in the associated information when needed.</li> + <li><a href="http://mongoosejs.com/docs/schematypes.html#mixed">Mixed</a>: An arbitrary schema type.</li> + <li>[]: An array of items. You can perform JavaScript array operations on these models (push, pop, unshift, etc.). The examples above show an array of objects without a specified type and an array of <code>String</code> objects, but you can have an array of any type of object.</li> +</ul> + +<p>The code also shows both ways of declaring a field:</p> + +<ul> + <li>Field <em>name</em> and <em>type</em> as a key-value pair (i.e. as done with fields <code>name</code>, <code>binary </code>and <code>living</code>).</li> + <li>Field <em>name</em> followed by an object defining the <code>type</code>, and any other <em>options</em> for the field. Options include things like: + <ul> + <li>default values.</li> + <li>built-in validators (e.g. max/min values) and custom validation functions.</li> + <li>Whether the field is required</li> + <li>Whether <code>String</code> fields should automatically be set to lowercase, uppercase, or trimmed (e.g. <code>{ type: <strong>String</strong>, lowercase: true, trim: true }</code>)</li> + </ul> + </li> +</ul> + +<p>For more information about options see <a href="http://mongoosejs.com/docs/schematypes.html">SchemaTypes</a> (Mongoose docs).</p> + +<h4 id="Validação">Validação</h4> + +<p>Mongoose provides built-in and custom validators, and synchronous and asynchronous validators. It allows you to specify both the acceptable range or values and the error message for validation failure in all cases.</p> + +<p>The built-in validators include:</p> + +<ul> + <li>All <a href="http://mongoosejs.com/docs/schematypes.html">SchemaTypes</a> have the built-in <a href="http://mongoosejs.com/docs/api.html#schematype_SchemaType-required">required</a> validator. This is used to specify whether the field must be supplied in order to save a document.</li> + <li><a href="http://mongoosejs.com/docs/api.html#schema-number-js">Numbers</a> have <a href="http://mongoosejs.com/docs/api.html#schema_number_SchemaNumber-min">min</a> and <a href="http://mongoosejs.com/docs/api.html#schema_number_SchemaNumber-max">max</a> validators.</li> + <li><a href="http://mongoosejs.com/docs/api.html#schema-string-js">Strings</a> have: + <ul> + <li><a href="http://mongoosejs.com/docs/api.html#schema_string_SchemaString-enum">enum</a>: specifies the set of allowed values for the field.</li> + <li><a href="http://mongoosejs.com/docs/api.html#schema_string_SchemaString-match">match</a>: specifies a regular expression that the string must match.</li> + <li><a href="http://mongoosejs.com/docs/api.html#schema_string_SchemaString-maxlength">maxlength</a> and <a href="http://mongoosejs.com/docs/api.html#schema_string_SchemaString-minlength">minlength</a> for the string.</li> + </ul> + </li> +</ul> + +<p>The example below (slightly modified from the Mongoose documents) shows how you can specify some of the validator types and error messages:</p> + +<pre class="brush: js">var breakfastSchema = new Schema({ + eggs: { + type: Number, + min: [6, 'Too few eggs'], + max: 12, + required: [true, 'Why no eggs?'] + }, + drink: { + type: String, + enum: ['Coffee', 'Tea', 'Water',] + } +}); +</pre> + +<p>For complete information on field validation see <a href="http://mongoosejs.com/docs/validation.html">Validation</a> (Mongoose docs).</p> + +<h4 id="Propriedades_virtuais">Propriedades virtuais</h4> + +<p>Virtual properties are document properties that you can get and set but that do not get persisted to MongoDB. The getters are useful for formatting or combining fields, while setters are useful for de-composing a single value into multiple values for storage. The example in the documentation constructs (and deconstructs) a full name virtual property from a first and last name field, which is easier and cleaner than constructing a full name every time one is used in a template.</p> + +<div class="note"> +<p><strong>Note:</strong> We will use a virtual property in the library to define a unique URL for each model record using a path and the record's <code>_id</code> value.</p> +</div> + +<p>For more information see <a href="http://mongoosejs.com/docs/guide.html#virtuals">Virtuals</a> (Mongoose documentation).</p> + +<h4 id="Methods_and_query_helpers">Methods and query helpers</h4> + +<p>A schema can also have <a href="http://mongoosejs.com/docs/guide.html#methods">instance methods</a>, <a href="http://mongoosejs.com/docs/guide.html#statics">static methods</a>, and <a href="http://mongoosejs.com/docs/guide.html#query-helpers">query helpers</a>. The instance and static methods are similar, but with the obvious difference that an instance method is associated with a particular record and has access to the current object. Query helpers allow you to extend mongoose's <a href="http://mongoosejs.com/docs/queries.html">chainable query builder API</a> (for example, allowing you to add a query "byName" in addition to the <code>find()</code>, <code>findOne()</code> and <code>findById()</code> methods).</p> + +<h3 id="Usando_modelos">Usando modelos</h3> + +<p>Once you've created a schema you can use it to create models. The model represents a collection of documents in the database that you can search, while the model's instances represent individual documents that you can save and retrieve.</p> + +<p>We provide a brief overview below. For more information see: <a href="http://mongoosejs.com/docs/models.html">Models</a> (Mongoose docs).</p> + +<h4 id="Criando_e_modificando_documentos">Criando e modificando documentos</h4> + +<p>To create a record you can define an instance of the model and then call <code>save()</code>. The examples below assume SomeModel is a model (with a single field "name") that we have created from our schema.</p> + +<pre class="brush: js">// Create an instance of model SomeModel +var awesome_instance = new SomeModel({ name: 'awesome' }); + +// Save the new model instance, passing a callback +awesome_instance.save(function (err) { + if (err) return handleError(err); + // saved! +}); +</pre> + +<p>Creation of records (along with updates, deletes, and queries) are asynchronous operations — you supply a callback that is called when the operation completes. The API uses the error-first argument convention, so the first argument for the callback will always be an error value (or null). If the API returns some result, this will be provided as the second argument.</p> + +<p>You can also use <code>create()</code> to define the model instance at the same time as you save it. The callback will return an error for the first argument and the newly-created model instance for the second argument.</p> + +<pre class="brush: js">SomeModel.create({ name: 'also_awesome' }, function (err, awesome_instance) { + if (err) return handleError(err); + // saved! +});</pre> + +<p>Every model has an associated connection (this will be the default connection when you use <code>mongoose.model()</code>). You create a new connection and call <code>.model()</code> on it to create the documents on a different database.</p> + +<p>You can access the fields in this new record using the dot syntax, and change the values. You have to call <code>save()</code> or <code>update()</code> to store modified values back to the database.</p> + +<pre class="brush: js">// Access model field values using dot notation +console.log(awesome_instance.name); //should log 'also_awesome' + +// Change record by modifying the fields, then calling save(). +awesome_instance.name="New cool name"; +awesome_instance.save(function (err) { + if (err) return handleError(err); // saved! +}); +</pre> + +<h4 id="Pesquisando_por_registros">Pesquisando por registros</h4> + +<p>You can search for records using query methods, specifying the query conditions as a JSON document. The code fragment below shows how you might find all athletes in a database that play tennis, returning just the fields for athlete <em>name</em> and <em>age</em>. Here we just specify one matching field (sport) but you can add more criteria, specify regular expression criteria, or remove the conditions altogether to return all athletes.</p> + +<pre class="brush: js">var Athlete = mongoose.model('Athlete', yourSchema); + +// find all athletes who play tennis, selecting the 'name' and 'age' fields +Athlete.find({ 'sport': 'Tennis' }, 'name age', function (err, athletes) { + if (err) return handleError(err); + // 'athletes' contains the list of athletes that match the criteria. +})</pre> + +<p>If you specify a callback, as shown above, the query will execute immediately. The callback will be invoked when the search completes.</p> + +<div class="note"> +<p><strong>Note:</strong> All callbacks in Mongoose use the pattern <code>callback(error, result)</code>. If an error occurs executing the query, the <code>error</code> parameter will contain an error document and <code>result</code> will be null. If the query is successful, the <code>error</code> parameter will be null, and the <code>result</code> will be populated with the results of the query.</p> +</div> + +<div class="note"> +<p><strong>Note:</strong> It is important to remember that not finding any results is <strong>not an error</strong> for a search —but it may be a fail-case in the context of your application. If your application expects a search to find a value you can either check the result in the callback (<code>results==null</code>) or daisy chain the method <a href="https://mongoosejs.com/docs/api.html#query_Query-orFail">orFail()</a> on the query. </p> +</div> + +<p>If you don't specify a callback then the API will return a variable of type <a href="http://mongoosejs.com/docs/api.html#query-js">Query</a>. You can use this query object to build up your query and then execute it (with a callback) later using the <code>exec()</code> method.</p> + +<pre class="brush: js">// find all athletes that play tennis +var query = Athlete.find({ 'sport': 'Tennis' }); + +// selecting the 'name' and 'age' fields +query.select('name age'); + +// limit our results to 5 items +query.limit(5); + +// sort by age +query.sort({ age: -1 }); + +// execute the query at a later time +query.exec(function (err, athletes) { + if (err) return handleError(err); + // athletes contains an ordered list of 5 athletes who play Tennis +})</pre> + +<p>Above we've defined the query conditions in the <code>find()</code> method. We can also do this using a <code>where()</code> function, and we can chain all the parts of our query together using the dot operator (.) rather than adding them separately. The code fragment below is the same as our query above, with an additional condition for the age.</p> + +<pre class="brush: js">Athlete. + find(). + where('sport').equals('Tennis'). + where('age').gt(17).lt(50). //Additional where query + limit(5). + sort({ age: -1 }). + select('name age'). + exec(callback); // where callback is the name of our callback function.</pre> + +<p>The <a href="http://mongoosejs.com/docs/api.html#query_Query-find">find()</a> method gets all matching records, but often you just want to get one match. The following methods query for a single record:</p> + +<ul> + <li><code><a href="http://mongoosejs.com/docs/api.html#model_Model.findById">findById()</a></code>: Finds the document with the specified <code>id</code> (every document has a unique <code>id</code>).</li> + <li><code><a href="http://mongoosejs.com/docs/api.html#query_Query-findOne">findOne()</a></code>: Finds a single document that matches the specified criteria.</li> + <li><code><a href="http://mongoosejs.com/docs/api.html#model_Model.findByIdAndRemove">findByIdAndRemove()</a></code>, <code><a href="http://mongoosejs.com/docs/api.html#model_Model.findByIdAndUpdate">findByIdAndUpdate()</a></code>, <code><a href="http://mongoosejs.com/docs/api.html#query_Query-findOneAndRemove">findOneAndRemove()</a></code>, <code><a href="http://mongoosejs.com/docs/api.html#query_Query-findOneAndUpdate">findOneAndUpdate()</a></code>: Finds a single document by <code>id</code> or criteria and either update or remove it. These are useful convenience functions for updating and removing records.</li> +</ul> + +<div class="note"> +<p><strong>Note:</strong> There is also a <code><a href="http://mongoosejs.com/docs/api.html#model_Model.count">count()</a></code> method that you can use to get the number of items that match conditions. This is useful if you want to perform a count without actually fetching the records.</p> +</div> + +<p>There is a lot more you can do with queries. For more information see: <a href="http://mongoosejs.com/docs/queries.html">Queries</a> (Mongoose docs).</p> + +<h4 id="Working_with_related_documents_—_population">Working with related documents — population</h4> + +<p>You can create references from one document/model instance to another using the <code>ObjectId</code> schema field, or from one document to many using an array of <code>ObjectIds</code>. The field stores the id of the related model. If you need the actual content of the associated document, you can use the <code><a href="http://mongoosejs.com/docs/api.html#query_Query-populate">populate()</a></code> method in a query to replace the id with the actual data.</p> + +<p>For example, the following schema defines authors and stories. Each author can have multiple stories, which we represent as an array of <code>ObjectId</code>. Each story can have a single author. The "ref" (highlighted in bold below) tells the schema which model can be assigned to this field.</p> + +<pre class="brush: js">var mongoose = require('mongoose') + , Schema = mongoose.Schema + +var authorSchema = Schema({ + name : String, + stories : [{ type: Schema.Types.ObjectId, <strong>ref</strong>: 'Story' }] +}); + +var storySchema = Schema({ + author : { type: Schema.Types.ObjectId, <strong>ref</strong>: 'Author' }, + title : String +}); + +var Story = mongoose.model('Story', storySchema); +var Author = mongoose.model('Author', authorSchema);</pre> + +<p>We can save our references to the related document by assigning the <code>_id</code> value. Below we create an author, then a story, and assign the author id to our stories author field.</p> + +<pre class="brush: js">var bob = new Author({ name: 'Bob Smith' }); + +bob.save(function (err) { + if (err) return handleError(err); + + //Bob now exists, so lets create a story + var story = new Story({ + title: "Bob goes sledding", + author: bob._id // assign the _id from the our author Bob. This ID is created by default! + }); + + story.save(function (err) { + if (err) return handleError(err); + // Bob now has his story + }); +});</pre> + +<p>Our story document now has an author referenced by the author document's ID. In order to get the author information in the story results we use <code>populate()</code>, as shown below.</p> + +<pre class="brush: js">Story +.findOne({ title: 'Bob goes sledding' }) +.populate('author') //This populates the author id with actual author information! +.exec(function (err, story) { + if (err) return handleError(err); + console.log('The author is %s', story.author.name); + // prints "The author is Bob Smith" +});</pre> + +<div class="note"> +<p><strong>Note:</strong> Astute readers will have noted that we added an author to our story, but we didn't do anything to add our story to our author's <code>stories</code> array. How then can we get all stories by a particular author? One way would be to add our author to the stories array, but this would result in us having two places where the information relating authors and stories needs to be maintained.</p> + +<p>A better way is to get the <code>_id</code> of our <em>author</em>, then use <code>find()</code> to search for this in the author field across all stories.</p> + +<pre class="brush: js">Story +.find({ author : bob._id }) +.exec(function (err, stories) { + if (err) return handleError(err); + // returns all stories that have Bob's id as their author. +}); +</pre> +</div> + +<p>This is almost everything you need to know about working with related items<em> for this tutorial</em>. For more detailed information see <a href="http://mongoosejs.com/docs/populate.html">Population</a> (Mongoose docs).</p> + +<h3 id="One_schemamodel_per_file">One schema/model per file</h3> + +<p>While you can create schemas and models using any file structure you like, we highly recommend defining each model schema in its own module (file), exporting the method to create the model. This is shown below:</p> + +<pre class="brush: js">// File: ./models/somemodel.js + +//Require Mongoose +var mongoose = require('mongoose'); + +//Define a schema +var Schema = mongoose.Schema; + +var SomeModelSchema = new Schema({ + a_string : String, + a_date : Date, +}); + +<strong>//Export function to create "SomeModel" model class +module.exports = mongoose.model('SomeModel', SomeModelSchema );</strong></pre> + +<p>You can then require and use the model immediately in other files. Below we show how you might use it to get all instances of the model.</p> + +<pre class="brush: js">//Create a SomeModel model just by requiring the module +var SomeModel = require('../models/somemodel') + +// Use the SomeModel object (model) to find all SomeModel records +SomeModel.find(callback_function);</pre> + +<h2 id="Configurando_o_banco_de_dados_MongoDB">Configurando o banco de dados MongoDB</h2> + +<p>Now that we understand something of what Mongoose can do and how we want to design our models, it's time to start work on the <em>LocalLibrary</em> website. The very first thing we want to do is set up a MongoDb database that we can use to store our library data.</p> + +<p>For this tutorial, we're going to use the <a href="https://www.mongodb.com/cloud/atlas">MongoDB Atlas</a> free cloud-hosted <a href="https://www.mongodb.com/cloud/atlas/pricing">sandbox</a> database. This database tier is not considered suitable for production websites because it has no redundancy, but it is great for development and prototyping. We're using it here because it is free and easy to set up, and because MongoDB Atlas is a popular <em>database as a service</em> vendor that you might reasonably choose for your production database (other popular choices at the time of writing include <a href="https://www.compose.com/">Compose</a>, <a href="https://scalegrid.io/pricing.html">ScaleGrid</a> and <a href="https://www.mongodb.com/cloud/atlas">ObjectRocket</a>).</p> + +<div class="note"> +<p><strong>Note:</strong> If you prefer you can set up a MongoDb database locally by downloading and installing the <a href="https://www.mongodb.com/download-center/community">appropriate binaries for your system</a>. The rest of the instructions in this article would be similar, except for the database URL you would specify when connecting.</p> +</div> + +<p>You will first need to <a href="https://www.mongodb.com/cloud/atlas/register">create an account</a> with MongoDB Atlas (this is free, and just requires that you enter basic contact details and acknowledge their terms of service). </p> + +<p>After logging in, you'll be taken to the <a href="https://cloud.mongodb.com/v2">home</a> screen:</p> + +<ol> + <li>Click <strong>Buid a Cluster</strong> button in the Clusters Overview section.<br> + <img alt="Create a cluster on MongoDB Atlas." src="https://mdn.mozillademos.org/files/16516/MongoDB_Atlas_-_CreateCluster.jpg" style="border-style: solid; border-width: 1px; height: 549px; width: 742px;"></li> + <li>This will open the <em>Create New Cluster</em> screen.<br> + <img alt="Choose a cloud provider when using MongoDB Atlas." src="https://mdn.mozillademos.org/files/16511/MongoDB_Atlas_-_ChooseProviderRegion.jpg" style="border-style: solid; border-width: 1px; height: 656px; width: 742px;"> + <ul> + <li>Select any provider from the <em>Cloud Provider & Region </em>section. Different providers offer different regions.</li> + <li>Select any region marked "FREE TIER AVAILABLE".</li> + <li>Click the <strong>Create Cluster</strong> button (creation of the cluster will take some minutes).</li> + </ul> + </li> + <li> + <p>You will return to the <em>Cluster Overview</em> screen.<br> + <img alt="Setup a collection on MongoDB Atlas." src="https://mdn.mozillademos.org/files/16517/MongoDB_Atlas_-_CreateCollection.jpg" style="border-style: solid; border-width: 1px; height: 399px; width: 742px;"></p> + + <ul> + <li> + <p>Click the <strong>Collections</strong> button.</p> + </li> + </ul> + </li> + <li>This will open the <em>Collections</em> section.<br> + <img alt="Create a database on MongoDB Atlas." src="https://mdn.mozillademos.org/files/16518/MongoDB_Atlas_-_CreateDatabase.jpg" style="border-style: solid; border-width: 1px; height: 412px; width: 742px;"> + <ul> + <li>Click the <strong>Create Database</strong> button.</li> + </ul> + </li> + <li>This will open the <em>Create Database</em> screen.<br> + <img alt="Details during database creation on MongoDB Atlas." src="https://mdn.mozillademos.org/files/16520/MongoDB_Atlas_-_DatabaseDetails.jpg" style="border-style: solid; border-width: 1px; height: 441px; width: 416px;"> + <ul> + <li>Enter the name for the new database as <code>local_library</code>.</li> + <li>Enter the name of the collection as <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">Collection0</span></font>.</li> + <li>Click the <strong>Create</strong> button to create the database.</li> + </ul> + </li> + <li>You will return to the Collection screen with your database created.<br> + <img alt="Database creation confirmation on MongoDB Atlas." src="https://mdn.mozillademos.org/files/16519/MongoDB_Atlas_-_DatabaseCreated.jpg" style="border-style: solid; border-width: 1px; height: 305px; width: 742px;"> + <ul> + <li>Click the <em>Overview</em> tab to return the cluster overview.</li> + </ul> + </li> + <li>From the Cluster0 Overview screen click the <strong>Connect</strong> button.<br> + <img alt="Configure a connection when after setting up a cluster in MongoDB Atlas." src="https://mdn.mozillademos.org/files/16512/MongoDB_Atlas_-_Connectbutton.jpg" style="border-style: solid; border-width: 1px; height: 308px; width: 742px;"></li> + <li>This will open the Connect to Cluster screen.<br> + <img alt="Setup a connection when using MongoDB Atlas." src="https://mdn.mozillademos.org/files/16513/MongoDB_Atlas_-_ConnectCluster.jpg" style="border-style: solid; border-width: 1px; height: 771px; width: 690px;"> + <ul> + <li>Click the <strong>Add a Different IP Address</strong> button, enter <code>0.0.0.0/0</code> for the IP Address and click <strong>Add IP Address</strong> button. + <div class="blockIndicator note"> + <p><strong>Note:</strong> It is a best practice to limit the IP addresses that can connect to your database and other resources. Here we allow a connection from anywhere because we don't know where the request will come from after deployment.</p> + </div> + </li> + <li>Enter a username and password and click <strong>Create MongoDB User</strong> button. + <div class="blockIndicator note"> + <p><strong>Note:</strong> Avoid using special characters in your MongoDB user password as mongoose may not parse the connection string properly.</p> + </div> + </li> + <li>If you have completed the 2 previous steps, the button <strong>Choose a connection method </strong>will turn green.</li> + <li>Click the <strong>Choose a connection method</strong> button.</li> + </ul> + </li> + <li>This will access the <em>Choose a connection</em> method tab.<br> + <img alt="Choose a connection type when connecting with MongoDB Atlas." src="https://mdn.mozillademos.org/files/16510/MongoDB_Atlas_-_ChooseAConnectionMethod.jpg" style="border-style: solid; border-width: 1px; height: 606px; width: 691px;"> + <ul> + <li>Click the <strong>Connect Your Application</strong> option.</li> + </ul> + </li> + <li>This will open the <em>Connect</em> screen.<br> + <img alt="Choose the Short SRV connection when settinup a connection on MongoDB Atalas." src="https://mdn.mozillademos.org/files/16514/MongoDB_Atlas_-_ConnectForShortSRV.jpg" style="border-style: solid; border-width: 1px; height: 604px; width: 693px;"> + <ul> + <li>Click the <strong>Short SRV connection string</strong> option to copy the connection string.</li> + </ul> + </li> + <li>This will open the connection string URL.<br> + <img alt="Copy the Short SRV connection string when setting up a connection on MongoDB Atlas" src="https://mdn.mozillademos.org/files/16515/MongoDB_Atlas_-_CopyShortSRV.jpg" style="border-style: solid; border-width: 1px; height: 741px; width: 690px;"> + <ul> + <li>Choose <strong>Copy</strong> button to copy the string.</li> + <li>Save this string somewhere safe.</li> + <li>Update the password with your users password.</li> + <li>Replace test with <code>local_library</code>.</li> + </ul> + </li> +</ol> + +<p>You have now created the database, and have an URL (with username and password) that can be used to access it. This will look something like: <code>mongodb+srv://your_user_name:your_password@cluster0-mbdj7.mongodb.net/local_library?retryWrites=true</code></p> + +<h2 id="Instalando_Mongoose">Instalando Mongoose</h2> + +<p>Open a command prompt and navigate to the directory where you created your <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">skeleton Local Library website</a>. Enter the following command to install Mongoose (and its dependencies) and add it to your <strong>package.json</strong> file, unless you have already done so when reading the <a href="#Installing_Mongoose_and_MongoDB">Mongoose Primer</a> above.</p> + +<pre class="brush: bash">npm install mongoose +</pre> + +<h2 id="Conectando_ao_MongoDB_2">Conectando ao MongoDB</h2> + +<p>Open <strong>/app.js</strong> (in the root of your project) and copy the following text below where you declare the <em>Express application object</em> (after the line <code>var app = express();</code>). Replace the database url string ('<em>insert_your_database_url_here</em>') with the location URL representing your own database (i.e. using the information from <em>mongoDB Atlas</em>).</p> + +<pre class="brush: js">//Set up mongoose connection +var mongoose = require('mongoose'); +var mongoDB = '<em>insert_your_database_url_here</em>'; +mongoose.connect(mongoDB, { useNewUrlParser: true }); +var db = mongoose.connection; +db.on('error', console.error.bind(console, 'MongoDB connection error:'));</pre> + +<p>As discussed <a href="#Connecting_to_MongoDB">in the Mongoose primer above</a>, this code creates the default connection to the database and binds to the error event (so that errors will be printed to the console). </p> + +<h2 id="Defining_the_LocalLibrary_Schema">Defining the LocalLibrary Schema</h2> + +<p>We will define a separate module for each model, as <a href="#One_schemamodel_per_file">discussed above</a>. Start by creating a folder for our models in the project root (<strong>/models</strong>) and then create separate files for each of the models:</p> + +<pre>/express-locallibrary-tutorial //the project root + <strong>/models</strong> + <strong>author.js</strong> + <strong>book.js</strong> + <strong>bookinstance.js</strong> + <strong>genre.js</strong> +</pre> + +<h3 id="Author_model">Author model</h3> + +<p>Copy the <code>Author</code> schema code shown below and paste it into your <strong>./models/author.js</strong> file. The scheme defines an author has having <code>String</code> SchemaTypes for the first and family names, that are required and have a maximum of 100 characters, and <code>Date</code> fields for the date of birth and death.</p> + +<pre class="brush: js">var mongoose = require('mongoose'); + +var Schema = mongoose.Schema; + +var AuthorSchema = new Schema( + { + first_name: {type: String, required: true, max: 100}, + family_name: {type: String, required: true, max: 100}, + date_of_birth: {type: Date}, + date_of_death: {type: Date}, + } +); + +<strong>// Virtual for author's full name +AuthorSchema +.virtual('name') +.get(function () { + return this.family_name + ', ' + this.first_name; +}); + +// Virtual for author's lifespan +AuthorSchema +</strong>.virtual('lifespan') +.get(function () { + return (this.date_of_death.getYear() - this.date_of_birth.getYear()).toString(); +}); + +// Virtual for author's URL +AuthorSchema +.virtual('url') +.get(function () { + return '/catalog/author/' + this._id; +}); + +//Export model +module.exports = mongoose.model('Author', AuthorSchema); + +</pre> + +<p>We've also declared a <a href="#Virtual_properties">virtual</a> for the AuthorSchema named "url" that returns the absolute URL required to get a particular instance of the model — we'll use the property in our templates whenever we need to get a link to a particular author.</p> + +<div class="note"> +<p><strong>Note:</strong> Declaring our URLs as a virtual in the schema is a good idea because then the URL for an item only ever needs to be changed in one place.<br> + At this point, a link using this URL wouldn't work, because we haven't got any routes handling code for individual model instances. We'll set those up in a later article!</p> +</div> + +<p>At the end of the module, we export the model.</p> + +<h3 id="Book_model">Book model</h3> + +<p>Copy the <code>Book</code> schema code shown below and paste it into your <strong>./models/book.js</strong> file. Most of this is similar to the author model — we've declared a schema with a number of string fields and a virtual for getting the URL of specific book records, and we've exported the model.</p> + +<pre class="brush: js">var mongoose = require('mongoose'); + +var Schema = mongoose.Schema; + +var BookSchema = new Schema( + { + title: {type: String, required: true}, + <strong> author: {type: Schema.Types.ObjectId, ref: 'Author', required: true},</strong> + summary: {type: String, required: true}, + isbn: {type: String, required: true}, + <strong> genre: [{type: Schema.Types.ObjectId, ref: 'Genre'}]</strong> + } +); + +// Virtual for book's URL +BookSchema +.virtual('url') +.get(function () { + return '/catalog/book/' + this._id; +}); + +//Export model +module.exports = mongoose.model('Book', BookSchema); +</pre> + +<p>The main difference here is that we've created two references to other models:</p> + +<ul> + <li>author is a reference to a single <code>Author</code> model object, and is required.</li> + <li>genre is a reference to an array of <code>Genre</code> model objects. We haven't declared this object yet!</li> +</ul> + +<h3 id="BookInstance_model">BookInstance model</h3> + +<p>Finally, copy the <code>BookInstance</code> schema code shown below and paste it into your <strong>./models/bookinstance.js</strong> file. The <code>BookInstance</code> represents a specific copy of a book that someone might borrow and includes information about whether the copy is available or on what date it is expected back, "imprint" or version details.</p> + +<pre class="brush: js">var mongoose = require('mongoose'); + +var Schema = mongoose.Schema; + +var BookInstanceSchema = new Schema( + { + book: { type: Schema.Types.ObjectId, ref: 'Book', required: true }, //reference to the associated book + imprint: {type: String, required: true}, + status: {type: String, required: true, <strong>enum: ['Available', 'Maintenance', 'Loaned', 'Reserved']</strong>, <strong>default: 'Maintenance'</strong>}, + due_back: {type: Date, <strong>default: Date.now</strong>} + } +); + +// Virtual for bookinstance's URL +BookInstanceSchema +.virtual('url') +.get(function () { + return '/catalog/bookinstance/' + this._id; +}); + +//Export model +module.exports = mongoose.model('BookInstance', BookInstanceSchema);</pre> + +<p>The new things we show here are the field options:</p> + +<ul> + <li><code>enum</code>: This allows us to set the allowed values of a string. In this case, we use it to specify the availability status of our books (using an enum means that we can prevent mis-spellings and arbitrary values for our status)</li> + <li><code>default</code>: We use default to set the default status for newly created bookinstances to maintenance and the default <code>due_back</code> date to <code>now</code> (note how you can call the Date function when setting the date!)</li> +</ul> + +<p>Everything else should be familiar from our previous schema.</p> + +<h3 id="Genre_model_-_challenge!">Genre model - challenge!</h3> + +<p>Open your <strong>./models/genre.js</strong> file and create a schema for storing genres (the category of book, e.g. whether it is fiction or non-fiction, romance or military history, etc).</p> + +<p>The definition will be very similar to the other models:</p> + +<ul> + <li>The model should have a <code>String</code> SchemaType called <code>name</code> to describe the genre.</li> + <li>This name should be required and have between 3 and 100 characters.</li> + <li>Declare a <a href="#Virtual_properties">virtual</a> for the genre's URL, named <code>url</code>.</li> + <li>Export the model.</li> +</ul> + +<h2 id="Testando_—_criando_alguns_itens">Testando — criando alguns itens</h2> + +<p>That's it. We now have all models for the site set up!</p> + +<p>In order to test the models (and to create some example books and other items that we can use in our next articles) we'll now run an <em>independent</em> script to create items of each type:</p> + +<ol> + <li>Download (or otherwise create) the file <a href="https://raw.githubusercontent.com/hamishwillee/express-locallibrary-tutorial/master/populatedb.js">populatedb.js</a> inside your <em>express-locallibrary-tutorial</em> directory (in the same level as <code>package.json</code>). + + <div class="note"> + <p><strong>Note:</strong> You don't need to know how <a href="https://raw.githubusercontent.com/hamishwillee/express-locallibrary-tutorial/master/populatedb.js">populatedb.js</a> works; it just adds sample data into the database.</p> + </div> + </li> + <li>Enter the following commands in the project root to install the <em>async</em> module that is required by the script (we'll discuss this in later tutorials, ) + <pre class="brush: bash">npm install async</pre> + </li> + <li>Run the script using node in your command prompt, passing in the URL of your <em>MongoDB</em> database (the same one you replaced the <em>insert_your_database_url_here </em>placeholder with, inside <code>app.js</code> earlier): + <pre class="brush: bash">node populatedb <your mongodb url></pre> + + <div class="blockIndicator note"> + <p><strong>Note for Windows operating system users</strong>: If the above command results in the error <code>DeprecationWarning: current URL string parser is deprecated</code>, change the <code>mongoose.connect(mongoDB);</code> line in <code>populatedb.js</code> file with <code>mongoose.connect(mongoDB, { useNewUrlParser:true });</code></p> + </div> + </li> + <li>The script should run through to completion, displaying items as it creates them in the terminal.</li> +</ol> + +<div class="note"> +<p><strong>Tip:</strong> Go to your database on mongoDB Atlas (in the <em>Collections</em> tab). You should now be able to drill down into individual collections of Books, Authors, Genres and BookInstances, and check out individual documents.</p> +</div> + +<h2 id="Resumo">Resumo</h2> + +<p>In this article, we've learned a bit about databases and ORMs on Node/Express, and a lot about how Mongoose schema and models are defined. We then used this information to design and implement <code>Book</code>, <code>BookInstance</code>, <code>Author</code> and <code>Genre</code> models for the <em>LocalLibrary</em> website.</p> + +<p>Last of all we tested our models by creating a number of instances (using a standalone script). In the next article we'll look at creating some pages to display these objects.</p> + +<h2 id="Veja_também">Veja também</h2> + +<ul> + <li><a href="https://expressjs.com/en/guide/database-integration.html">Database integration</a> (Express docs)</li> + <li><a href="http://mongoosejs.com/">Mongoose website</a> (Mongoose docs)</li> + <li><a href="http://mongoosejs.com/docs/guide.html">Mongoose Guide</a> (Mongoose docs)</li> + <li><a href="http://mongoosejs.com/docs/validation.html">Validation</a> (Mongoose docs)</li> + <li><a href="http://mongoosejs.com/docs/schematypes.html">Schema Types</a> (Mongoose docs)</li> + <li><a href="http://mongoosejs.com/docs/models.html">Models</a> (Mongoose docs)</li> + <li><a href="http://mongoosejs.com/docs/queries.html">Queries</a> (Mongoose docs)</li> + <li><a href="http://mongoosejs.com/docs/populate.html">Population</a> (Mongoose docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs")}}</p> + +<h2 id="Neste_módulo">Neste módulo</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Setting up a Node (Express) development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li> +</ul> diff --git a/files/pt-br/learn/server-side/express_nodejs/skeleton_website/index.html b/files/pt-br/learn/server-side/express_nodejs/skeleton_website/index.html new file mode 100644 index 0000000000..c6cc459141 --- /dev/null +++ b/files/pt-br/learn/server-side/express_nodejs/skeleton_website/index.html @@ -0,0 +1,509 @@ +--- +title: 'Express Tutorial Parte 2: Criando a estrutura do website' +slug: Learn/Server-side/Express_Nodejs/skeleton_website +translation_of: Learn/Server-side/Express_Nodejs/skeleton_website +--- +<div>{{LearnSidebar}}</div> + +<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs/mongoose", "Learn/Server-side/Express_Nodejs")}}</p> + +<p class="summary">Neste segundo <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial</a> , mostrará como criar a estrutura do website que depois você poderá colocar <em>templates,</em> chamadas de banco de dados ou rotas específicas.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré-requisitos:</th> + <td><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Preparar o ambiente de desenvolvimento do Node </a>. Revise o Tutorial Express.</td> + </tr> + <tr> + <th scope="row">Objetivo:</th> + <td>Iniciar nosso website usando o "<em>Express Application Generator"</em>.</td> + </tr> + </tbody> +</table> + +<h2 id="Visão_Geral">Visão Geral</h2> + +<p>Nesse artigo mostraremos como criar a estrutura do website usando a ferramenta "<a href="https://expressjs.com/en/starter/generator.html">Express Application Generator</a> ". Neste caso, usaremos a ferramenta para criar o framework para nosso <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">website "LocalLibrary" </a>, tpara o qual adicionaremos mais tarde todo o outro código necessário para o site. O processo é extremamente simples, com apenas a requisição de invocar o "Generator" na linha de comando com um novo nome de projeto, e, se quiser, especificar o <em>template </em>do site e o gerador de CSS. </p> + +<p><span style="line-height: 1.5;">As seguintes sessões mostrará como chamar o "Application Generator", e prover uma pequena explicação sobre as diferentes opções de CSS. Também aprenderemos como a estrutura do site é definida. No final, será mostrado como podemos rodar o site para ver se funciona.</span></p> + +<div class="note"> +<p><span style="line-height: 1.5;"><strong>Nota</strong>: O "<em>Express Application Generator"</em> não é o único gerador para as aplicações do Express, e o projeto gerado não é a única maneira viável de estruturar seus arquivos e diretórios. O site gerado, entretanto, tem um estrutura modular que é fácil de extender e ser entendida. Para aprender melhor sobre a aplicação do "<em>minimal</em> Express", veja <a href="https://expressjs.com/en/starter/hello-world.html">Exemplo"Hello world" </a>.</span></p> +</div> + +<h2 id="Usando_o_Application_Generator">Usando o "Application Generator"</h2> + +<p>Você já deve ter instalado o gerador como requisito.Como um lembrete rápido, você instala a ferramenta de gerador em todo o site usando o Gerenciador de pacotes NPM, como mostrado:</p> + +<pre class="brush: bash"><code>npm install express-generator -g</code></pre> + +<p>O gerador tem algumas opções que podem ser visualizadas usando o comando <code>--help</code> (or <code>-h</code>):</p> + +<pre class="brush: bash">> express --help + + Usage: express [options] [dir] + + + Options: + + --version output the version number + -e, --ejs add ejs engine support + --pug add pug engine support + --hbs add handlebars engine support + -H, --hogan add hogan.js engine support + -v, --view <engine> add view <engine> support (dust|ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade) + --no-view use static html instead of view engine + -c, --css <engine> add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css) + --git add .gitignore + -f, --force force on non-empty directory + -h, --help output usage information +</pre> + +<p>Você pode simplesmente especificar <code>express</code> para criar um projeto dentro do diretório atual usando <em>Jade</em> view e CSS simples (se você especificar um nome de diretório, o projeto será criado em uma subpasta com esse nome).</p> + +<pre class="brush: bash"><code>express</code></pre> + +<p>Também pode ser escolhido um "view" (<em>template)</em> usando<code>--view</code> e/ou um gerador de CSS usando <code>--css</code>.</p> + +<div class="note"> +<p><strong>Nota:</strong> As outras opções para escolher os mecanismos de modelo (e.g. <code>--hogan</code>, <code>--ejs</code>, <code>--hbs</code> etc.) são preteridas. Use <code>--view</code> (ou<code> -v</code>)!</p> +</div> + +<h3 id="Qual_engine_de_view_devo_usar">Qual <em>engine</em> de "view" devo usar?</h3> + +<p>The <em>Express Application Generator</em> allows you to configure a number of popular view/templating engines, including <a href="https://www.npmjs.com/package/ejs">EJS</a>, <a href="http://github.com/donpark/hbs">Hbs</a>, <a href="https://pugjs.org/api/getting-started.html">Pug</a> (Jade), <a href="https://www.npmjs.com/package/twig">Twig</a>, and <a href="https://www.npmjs.com/package/vash">Vash</a>, although it chooses Jade by default if you don't specify a view option. Express itself can also support a large number of other templating languages <a href="https://github.com/expressjs/express/wiki#template-engines">out of the box</a>.</p> + +<div class="note"> +<p><strong>Note:</strong> If you want to use a template engine that isn't supported by the generator then see <a href="https://expressjs.com/en/guide/using-template-engines.html">Using template engines with Express</a> (Express docs) and the documentation for your target view engine.</p> +</div> + +<p>Generally speaking, you should select a templating engine that delivers all the functionality you need and allows you to be productive sooner — or in other words, in the same way that you choose any other component! Some of the things to consider when comparing template engines:</p> + +<ul> + <li>Time to productivity — If your team already has experience with a templating language then it is likely they will be productive faster using that language. If not, then you should consider the relative learning curve for candidate templating engines.</li> + <li>Popularity and activity — Review the popularity of the engine and whether it has an active community. It is important to be able to get support for the engine when you have problems over the lifetime of the website.</li> + <li>Style — Some template engines use specific markup to indicate inserted content within "ordinary" HTML, while others construct the HTML using a different syntax (for example, using indentation and block names).</li> + <li>Performance/rendering time.</li> + <li>Features — you should consider whether the engines you look at have the following features available: + <ul> + <li>Layout inheritance: Allows you to define a base template and then "inherit" just the parts of it that you want to be different for a particular page. This is typically a better approach than building templates by including a number of required components or building a template from scratch each time.</li> + <li>"Include" support: Allows you to build up templates by including other templates.</li> + <li>Concise variable and loop control syntax.</li> + <li>Ability to filter variable values at template level (e.g. making variables upper-case, or formatting a date value).</li> + <li>Ability to generate output formats other than HTML (e.g. JSON or XML).</li> + <li>Support for asynchronous operations and streaming.</li> + <li>Can be used on the client as well as the server. If a templating engine can be used on the client this allows the possibility of serving data and having all or most of the rendering done client-side.</li> + </ul> + </li> +</ul> + +<div class="note"> +<p><strong>Tip:</strong> There are many resources on the Internet to help you compare the different options!</p> +</div> + +<p>For this project, we'll use the <a href="https://pugjs.org/api/getting-started.html">Pug</a> templating engine (this is the recently-renamed Jade engine), as this is one of the most popular Express/JavaScript templating languages and is supported out of the box by the generator.</p> + +<h3 id="What_CSS_stylesheet_engine_should_I_use">What CSS stylesheet engine should I use?</h3> + +<p>The <em>Express Application Generator</em> allows you to create a project that is configured to use the most common CSS stylesheet engines: <a href="http://lesscss.org/">LESS</a>, <a href="http://sass-lang.com/">SASS</a>, <a href="http://compass-style.org/">Compass</a>, <a href="http://stylus-lang.com/">Stylus</a>.</p> + +<div class="note"> +<p><strong>Note: </strong>CSS has some limitations that make certain tasks difficult. CSS stylesheet engines allow you to use more powerful syntax for defining your CSS and then compile the definition into plain-old CSS for browsers to use.</p> +</div> + +<p>As with templating engines, you should use the stylesheet engine that will allow your team to be most productive. For this project, we'll use the ordinary CSS (the default) as our CSS requirements are not sufficiently complicated to justify using anything else.</p> + +<h3 id="What_database_should_I_use">What database should I use?</h3> + +<p>The generated code doesn't use/include any databases. <em>Express</em> apps can use any <a href="https://expressjs.com/en/guide/database-integration.html">database mechanism</a> supported by <em>Node</em> (<em>Express</em> itself doesn't define any specific additional behavior/requirements for database management).</p> + +<p>We'll discuss how to integrate with a database in a later article.</p> + +<h2 id="Creating_the_project">Creating the project</h2> + +<p>For the sample <em>Local Library</em> app we're going to build, we'll create a project named <em>express-locallibrary-tutorial </em>using the <em>Pug</em> template library and no CSS stylesheet engine.</p> + +<p>First, navigate to where you want to create the project and then run the <em>Express Application Generator</em> in the command prompt as shown:</p> + +<pre class="brush: bash">express express-locallibrary-tutorial --view=pug +</pre> + +<p>The generator will create (and list) the project's files.</p> + +<pre class="brush: bash"> create : express-locallibrary-tutorial\ + create : express-locallibrary-tutorial\public\ + create : express-locallibrary-tutorial\public\javascripts\ + create : express-locallibrary-tutorial\public\images\ + create : express-locallibrary-tutorial\public\stylesheets\ + create : express-locallibrary-tutorial\public\stylesheets\style.css + create : express-locallibrary-tutorial\routes\ + create : express-locallibrary-tutorial\routes\index.js + create : express-locallibrary-tutorial\routes\users.js + create : express-locallibrary-tutorial\views\ + create : express-locallibrary-tutorial\views\error.pug + create : express-locallibrary-tutorial\views\index.pug + create : express-locallibrary-tutorial\views\layout.pug + create : express-locallibrary-tutorial\app.js + create : express-locallibrary-tutorial\package.json + create : express-locallibrary-tutorial\bin\ + create : express-locallibrary-tutorial\bin\www + + change directory: + > cd express-locallibrary-tutorial + + install dependencies: + > npm install + + run the app: + > SET DEBUG=express-locallibrary-tutorial:* & npm start</pre> + +<p>At the end of the output, the generator provides instructions on how you install the dependencies (as listed in the <strong>package.json</strong> file) and then how to run the application (the instructions above are for Windows; on Linux/macOS they will be slightly different).</p> + +<div class="blockIndicator note"> +<p><strong>Note:</strong> When using Windows, the && and & assumes you are using the Command Prompt. If you are using the new default PowerShell terminal do not concatenate the commands with && and &. Instead set the DEBUG environment variable with $ENV:DEBUG = "express-locallibrary-tutorial:*";. The npm start can be followed by the npm start. </p> +</div> + +<h2 id="Running_the_skeleton_website">Running the skeleton website</h2> + +<p>At this point, we have a complete skeleton project. The website doesn't actually <em>do</em> very much yet, but it's worth running it to show how it works.</p> + +<ol> + <li>First, install the dependencies (the <code>install</code> command will fetch all the dependency packages listed in the project's<strong> package.json</strong> file). + + <pre class="brush: bash">cd express-locallibrary-tutorial +npm install</pre> + </li> + <li>Then run the application. + <ul> + <li>On Windows, use this command: + <pre class="brush: bash">SET DEBUG=express-locallibrary-tutorial:* & npm start</pre> + </li> + <li>On macOS or Linux, use this command: + <pre class="brush: bash">DEBUG=express-locallibrary-tutorial:* npm start +</pre> + </li> + </ul> + </li> + <li>Then load <a href="http://localhost:3000/">http://localhost:3000/</a> in your browser to access the app.</li> +</ol> + +<p>You should see a browser page that looks like this:</p> + +<p><img alt="Browser for default Express app generator website" src="https://mdn.mozillademos.org/files/14375/ExpressGeneratorSkeletonWebsite.png" style="display: block; height: 403px; margin: 0px auto; width: 576px;"></p> + +<p>You have a working Express application, serving itself to <em>localhost:3000</em>.</p> + +<div class="note"> +<p><strong>Note:</strong> You could also start the app just using the <code>npm start</code> command. Specifying the DEBUG variable as shown enables console logging/debugging. For example, when you visit the above page you'll see debug output like this:</p> + +<pre class="brush: bash">>SET DEBUG=express-locallibrary-tutorial:* & npm start + +> express-locallibrary-tutorial@0.0.0 start D:\github\mdn\test\exprgen\express-locallibrary-tutorial +> node ./bin/www + + express-locallibrary-tutorial:server Listening on port 3000 +0ms +GET / 304 490.296 ms - - +GET /stylesheets/style.css 200 4.886 ms - 111 +</pre> +</div> + +<h2 id="Enable_server_restart_on_file_changes">Enable server restart on file changes</h2> + +<p>Any changes you make to your Express website are currently not visible until you restart the server. It quickly becomes very irritating to have to stop and restart your server every time you make a change, so it is worth taking the time to automate restarting the server when needed.</p> + +<p>One of the easiest such tools for this purpose is <a href="https://github.com/remy/nodemon">nodemon</a>. This is usually installed globally (as it is a "tool"), but here we'll install and use it locally as a <em>developer dependency</em>, so that any developers working with the project get it automatically when they install the application. Use the following command in the root directory for the skeleton project:</p> + +<pre class="brush: bash">npm install --save-dev nodemon</pre> + +<p>If you still choose to install <a href="https://github.com/remy/nodemon">nodemon</a> globally to your machine, and not only to your project's <strong>package.json</strong> file:</p> + +<pre class="brush: bash">npm install -g nodemon</pre> + +<p>If you open your project's <strong>package.json</strong> file you'll now see a new section with this dependency:</p> + +<pre class="brush: json"> "devDependencies": { + "nodemon": "^1.18.10" +} +</pre> + +<p>Because the tool isn't installed globally we can't launch it from the command line (unless we add it to the path) but we can call it from an NPM script because NPM knows all about the installed packages. Find the the <code>scripts</code> section of your package.json. Initially, it will contain one line, which begins with <code>"start"</code>. Update it by putting a comma at the end of that line, and adding the <code>"devstart"</code> line seen below:</p> + +<pre class="brush: json"> "scripts": { + "start": "node ./bin/www"<strong>,</strong> +<strong> "devstart": "nodemon ./bin/www"</strong> + }, +</pre> + +<p>We can now start the server in almost exactly the same way as previously, but with the <code>devstart</code> command specified:</p> + +<ul> + <li>On Windows, use this command: + <pre class="brush: bash">SET DEBUG=express-locallibrary-tutorial:* & npm <strong>run devstart</strong></pre> + </li> + <li>On macOS or Linux, use this command: + <pre class="brush: bash">DEBUG=express-locallibrary-tutorial:* npm <strong>run devstart</strong> +</pre> + </li> +</ul> + +<div class="note"> +<p><strong>Note:</strong> Now if you edit any file in the project the server will restart (or you can restart it by typing <code>rs</code> on the command prompt at any time). You will still need to reload the browser to refresh the page.</p> + +<p>We now have to call "<code>npm run <em><scriptname></em></code>" rather than just <code>npm start</code>, because "start" is actually an NPM command that is mapped to the named script. We could have replaced the command in the <em>start</em> script but we only want to use <em>nodemon</em> during development, so it makes sense to create a new script command.</p> +</div> + +<h2 id="The_generated_project">The generated project</h2> + +<p>Let's now take a look at the project we just created.</p> + +<h3 id="Directory_structure">Directory structure</h3> + +<p>The generated project, now that you have installed dependencies, has the following file structure (files are the items <strong>not</strong> prefixed with "/"). The <strong>package.json</strong> file defines the application dependencies and other information. It also defines a startup script that will call the application entry point, the JavaScript file <strong>/bin/www</strong>. This sets up some of the application error handling and then loads <strong>app.js</strong> to do the rest of the work. The app routes are stored in separate modules under the <strong>routes/</strong> directory. The templates are stored under the /<strong>views</strong> directory.</p> + +<pre>/express-locallibrary-tutorial + <strong>app.js</strong> + /bin + <strong>www</strong> + <strong>package.json</strong> + <strong>package-lock.json</strong> + /node_modules + [about 6700 subdirectories and files] + /public + /images + /javascripts + /stylesheets + <strong>style.css</strong> + /routes + <strong>index.js</strong> + <strong>users.js</strong> + /views + <strong>error.pug</strong> + <strong>index.pug</strong> + <strong>layout.pug</strong> + +</pre> + +<p>The following sections describe the files in a little more detail.</p> + +<h3 id="package.json">package.json</h3> + +<p>The <strong>package.json </strong>file defines the application dependencies and other information:</p> + +<pre class="brush: json">{ + "name": "express-locallibrary-tutorial", + "version": "0.0.0", + "private": true, + "scripts": { + "start": "node ./bin/www", + "devstart": "nodemon ./bin/www" + }, + "dependencies": { + "cookie-parser": "~1.4.3", + "debug": "~2.6.9", + "express": "~4.16.0", + "http-errors": "~1.6.2", + "morgan": "~1.9.0", + "pug": "2.0.0-beta11" + }, + "devDependencies": { + "nodemon": "^1.18.10" + } +} +</pre> + +<p>The dependencies include the <em>express</em> package and the package for our selected view engine (<em>pug</em>). In addition, we have the following packages that are useful in many web applications:</p> + +<ul> + <li><a href="https://www.npmjs.com/package/cookie-parser">cookie-parser</a>: Used to parse the cookie header and populate <code>req.cookies</code> (essentially provides a convenient method for accessing cookie information).</li> + <li><a href="https://www.npmjs.com/package/debug">debug</a>: A tiny node debugging utility modeled after node core's debugging technique.</li> + <li><a href="https://www.npmjs.com/package/morgan">morgan</a>: An HTTP request logger middleware for node.</li> + <li><a href="https://www.npmjs.com/package/http-errors">http-errors</a>: Create HTTP errors where needed (for express error handling).</li> +</ul> + +<p>The scripts section defines a "<em>start</em>" script, which is what we are invoking when we call <code>npm start</code> to start the server. From the script definition, you can see that this actually starts the JavaScript file <strong>./bin/www</strong> with <em>node</em>. It also defines a "<em>devstart</em>" script, which we invoke when calling <code>npm run devstart</code> instead. This starts the same <strong>./bin/www</strong> file, but with <em>nodemon</em> rather than <em>node</em>.</p> + +<pre class="brush: json"> "scripts": { + "start": "node ./bin/www", + "devstart": "nodemon ./bin/www" + }, +</pre> + +<h3 id="www_file">www file</h3> + +<p>The file <strong>/bin/www</strong> is the application entry point! The very first thing this does is <code>require()</code> the "real" application entry point (<strong>app.js</strong>, in the project root) that sets up and returns the <code><a href="http://expressjs.com/en/api.html">express()</a></code> application object.</p> + +<pre class="brush: js">#!/usr/bin/env node + +/** + * Module dependencies. + */ + +<strong>var app = require('../app');</strong> +</pre> + +<div class="note"> +<p><strong>Note:</strong> <code>require()</code> is a global node function that is used to import modules into the current file. Here we specify <strong>app.js</strong> module using a relative path and omitting the optional (.<strong>js</strong>) file extension.</p> +</div> + +<p>The remainder of the code in this file sets up a node HTTP server with <code>app</code> set to a specific port (defined in an environment variable or 3000 if the variable isn't defined), and starts listening and reporting server errors and connections. For now you don't really need to know anything else about the code (everything in this file is "boilerplate"), but feel free to review it if you're interested.</p> + +<h3 id="app.js">app.js</h3> + +<p>This file creates an <code>express</code> application object (named <code>app</code>, by convention), sets up the application with various settings and middleware, and then exports the app from the module. The code below shows just the parts of the file that create and export the app object:</p> + +<pre class="brush: js"><code>var express = require('express'); +var app = express(); +... +</code>module.exports = app; +</pre> + +<p>Back in the <strong>www</strong> entry point file above, it is this <code>module.exports</code> object that is supplied to the caller when this file is imported.</p> + +<p>Let's work through the <strong>app.js</strong> file in detail. First, we import some useful node libraries into the file using <code>require()</code>, including http-errors, <em>express</em>, <em>morgan</em> and <em>cookie-parser</em> that we previously downloaded for our application using NPM; and <em>path</em>, which is a core Node library for parsing file and directory paths.</p> + +<pre class="brush: js">var createError = require('http-errors'); +var express = require('express'); +var path = require('path'); +var cookieParser = require('cookie-parser'); +var logger = require('morgan'); +</pre> + +<p>Then we <code>require()</code> modules from our routes directory. These modules/files contain code for handling particular sets of related "routes" (URL paths). When we extend the skeleton application, for example to list all books in the library, we will add a new file for dealing with book-related routes.</p> + +<pre class="brush: js">var indexRouter = require('./routes/index'); +var usersRouter = require('./routes/users'); +</pre> + +<div class="note"> +<p><strong>Note:</strong> At this point, we have just <em>imported</em> the module; we haven't actually used its routes yet (this happens just a little bit further down the file).</p> +</div> + +<p>Next, we create the <code>app</code> object using our imported <em>express</em> module, and then use it to set up the view (template) engine. There are two parts to setting up the engine. First, we set the '<code>views</code>' value to specify the folder where the templates will be stored (in this case the subfolder <strong>/views</strong>). Then we set the '<code>view engine</code>' value to specify the template library (in this case "pug").</p> + +<pre class="brush: js">var app = express(); + +// view engine setup +app.set('views', path.join(__dirname, 'views')); +app.set('view engine', 'pug'); +</pre> + +<p>The next set of functions call <code>app.use()</code> to add the <em>middleware</em> libraries into the request handling chain. In addition to the 3rd party libraries we imported previously, we use the <code>express.static</code> middleware to get <em>Express</em> to serve all the static files in the <strong>/public</strong> directory in the project root.</p> + +<pre class="brush: js">app.use(logger('dev')); +app.use(express.json()); +app.use(express.urlencoded({ extended: false })); +app.use(cookieParser()); +<strong>app.use(express.static(path.join(__dirname, 'public')));</strong> +</pre> + +<p>Now that all the other middleware is set up, we add our (previously imported) route-handling code to the request handling chain. The imported code will define particular routes for the different <em>parts</em> of the site:</p> + +<pre class="brush: js">app.use('/', indexRouter); +app.use('/users', usersRouter); +</pre> + +<div class="note"> +<p><strong>Note:</strong> The paths specified above ('/' and '<code>/users'</code>) are treated as a prefix to routes defined in the imported files. So for example, if the imported <strong>users</strong> module defines a route for <code>/profile</code>, you would access that route at <code>/users/profile</code>. We'll talk more about routes in a later article.</p> +</div> + +<p id="error_handling">The last middleware in the file adds handler methods for errors and HTTP 404 responses.</p> + +<pre class="brush: js">// catch 404 and forward to error handler +app.use(function(req, res, next) { + next(createError(404)); +}); + +// error handler +app.use(function(err, req, res, next) { + // set locals, only providing error in development + res.locals.message = err.message; + res.locals.error = req.app.get('env') === 'development' ? err : {}; + + // render the error page + res.status(err.status || 500); + res.render('error'); +}); +</pre> + +<p>The Express application object (app) is now fully configured. The last step is to add it to the module exports (this is what allows it to be imported by <strong>/bin/www</strong>).</p> + +<pre class="brush: js">module.exports = app;</pre> + +<h3 id="Routes">Routes</h3> + +<p>The route file <strong>/routes/users.js</strong> is shown below (route files share a similar structure, so we don't need to also show <strong>index.js</strong>). First, it loads the <em>express</em> module and uses it to get an <code>express.Router</code> object. Then it specifies a route on that object and lastly exports the router from the module (this is what allows the file to be imported into <strong>app.js</strong>).</p> + +<pre class="brush: js">var express = require('express'); +var router = express.Router(); + +/* GET users listing. */ +<strong>router.get('/', function(req, res, next) { + res.send('respond with a resource');</strong> +}); + +module.exports = router; +</pre> + +<p>The route defines a callback that will be invoked whenever an HTTP <code>GET</code> request with the correct pattern is detected. The matching pattern is the route specified when the module is imported ('<code>/users</code>') plus whatever is defined in this file ('<code>/</code>'). In other words, this route will be used when an URL of <code>/users/</code> is received.</p> + +<div class="note"> +<p><strong>Tip:</strong> Try this out by running the server with node and visiting the URL in your browser: <a href="http://localhost:3000/users/">http://localhost:3000/users/</a>. You should see a message: 'respond with a resource'.</p> +</div> + +<p>One thing of interest above is that the callback function has the third argument '<code>next</code>', and is hence a middleware function rather than a simple route callback. While the code doesn't currently use the <code>next</code> argument, it may be useful in the future if you want to add multiple route handlers to the <code>'/'</code> route path.</p> + +<h3 id="Views_(templates)">Views (templates)</h3> + +<p>The views (templates) are stored in the <strong>/views</strong> directory (as specified in <strong>app.js</strong>) and are given the file extension <strong>.pug</strong>. The method <code><a href="http://expressjs.com/en/4x/api.html#res.render">Response.render()</a></code> is used to render a specified template along with the values of named variables passed in an object, and then send the result as a response. In the code below from <strong>/routes/index.js</strong> you can see how that route renders a response using the template "index" passing the template variable "title".</p> + +<pre class="brush: js">/* GET home page. */ +router.get('/', function(req, res, next) { + res.render('index', { title: 'Express' }); +}); +</pre> + +<p>The corresponding template for the above route is given below (<strong>index.pug</strong>). We'll talk more about the syntax later. All you need to know for now is that the <code>title</code> variable (with value <code>'Express'</code>) is inserted where specified in the template.</p> + +<pre>extends layout + +block content + h1= title + p Welcome to #{title} +</pre> + +<h2 id="Challenge_yourself">Challenge yourself</h2> + +<p>Create a new route in <strong>/routes/users.js</strong> that will display the text "<em>You're so cool"</em> at URL <code>/users/cool/</code>. Test it by running the server and visiting <a href="http://localhost:3000/users/cool/">http://localhost:3000/users/cool/</a> in your browser</p> + +<ul> +</ul> + +<h2 id="Summary">Summary</h2> + +<p>You have now created a skeleton website project for the <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Local Library</a> and verified that it runs using <em>node</em>. Most importantly, you also understand how the project is structured, so you have a good idea where we need to make changes to add routes and views for our local library.</p> + +<p>Next, we'll start modifying the skeleton so that it works as a library website.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="https://expressjs.com/en/starter/generator.html">Express application generator</a> (Express docs)</li> + <li><a href="https://expressjs.com/en/guide/using-template-engines.html">Using template engines with Express</a> (Express docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs/mongoose", "Learn/Server-side/Express_Nodejs")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Setting up a Node (Express) development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li> +</ul> diff --git a/files/pt-br/learn/server-side/express_nodejs/tutorial_local_library_website/index.html b/files/pt-br/learn/server-side/express_nodejs/tutorial_local_library_website/index.html new file mode 100644 index 0000000000..718e207e86 --- /dev/null +++ b/files/pt-br/learn/server-side/express_nodejs/tutorial_local_library_website/index.html @@ -0,0 +1,93 @@ +--- +title: 'Express: Tutorial para criar o site de uma Biblioteca Local' +slug: Learn/Server-side/Express_Nodejs/Tutorial_local_library_website +tags: + - Express + - Iniciante + - Introdução + - Node + - desenvolvimento-web + - nodejs + - server-side +translation_of: Learn/Server-side/Express_Nodejs/Tutorial_local_library_website +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs")}}</div> + +<p class="summary">Este artigo tem como objetivo explicar o que você vai aprender ao longo dos próximo tutoriais e dar uma visão geral do projeto que vamos desenvolver: um site de "local library" (Biblioteca Local, em tradução livre).</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré-requisitos:</th> + <td>Leia a <a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Express_Nodejs/Introdu%C3%A7%C3%A3o">Indrodução ao Express</a>. Para os próximos artigos, você também precisa ler <a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Express_Nodejs/ambiente_de_desenvolvimento">Conhecendo Node como ambiente de desenvolvimento</a>. </td> + </tr> + <tr> + <th scope="row">Objetivos:</th> + <td>Apresentar a aplicação que será desenvolvida ao longo deste tutorial e permitir aos leitores entender quais tópicos serão abordados.</td> + </tr> + </tbody> +</table> + +<h2 id="Visão_Geral">Visão Geral</h2> + +<p>Bem-vindo ao tutorial MDN "Express: Tutorial para criar o site de uma Biblioteca Local", no qual vamos desenvolver um website para gerenciar o catálogo de uma biblioteca. </p> + +<p>Neste passo a passo você vai: </p> + +<ul> + <li>Usar a ferramenta <em>Express Aplication Generator (Gerador de Aplicações Express) </em>para<em> </em>criar a estrutura do site e da aplicação. </li> + <li>Iniciar e encerrar o Web Server do Node.</li> + <li>Usar um banco de dados para armazenar os dados de sua aplicação.</li> + <li>Criar caminhos para a requisição de diferentes informações e templates ("views") para renderizar os dados em arquivos HTML no browser.</li> + <li>Trabalhar com formulários.</li> + <li>Subir sua aplicação para o ambiente de produção (deploy).</li> +</ul> + +<p>Alguns dos itens acima você já conhecebe bem, outros você sabe apenas um pouco. Não se preocupe. Ao final do tutorial, você saberá o sucifiente para desenvolver, por conta própria, um simples app Express.</p> + +<h2 id="O_site_da_Biblioteca_Local">O site da Biblioteca Local</h2> + +<p><em>LocalLibrary</em> ou Biblioteca Local é o nome do website que vamos criar durante os tutoriais. O objetivo do site é prover um catálogo para uma pequena biblioteca, onde usuários podem pesquisar livros disponíveis e gerenciar suas contas. </p> + +<p>Esse exemplo foi escolhido cuidadosamente. Isso porque para construir a "biblioteca" vamos utilizar recursos básicos e fundamentais do Express, além de funcionalidades e conceitos que você poderá aplicar em qualquer outro website:</p> + +<ul> + <li>Em nossos primeiros artigos vamos criar uma biblioteca virtual na qual os usuários poderão procurar quais livros estão disponíveis para empréstimo. Tal funcionalidade nos exigirá entender operações padrões em sites web, como leituras e visualizações de conteúdos registrados em banco de dados.</li> + <li>Durante nosso trabalho, o exemplo da biblioteca se estenderá naturalmente para mais funcionalidades e informações disponíveis na biblioteca. Por exemplo: permitir que novos livros sejam adicionados aos catálogos. Somente essa <em>feature</em> nos permitirá aprender sobre o uso de formulários e autenticação de usuários.</li> +</ul> + +<p>Apesar de ser um exemplo bem extenso, nossa Biblioteca Local apresentará o mínimo de informações para ajudar você a entender e se desenvolver melhor no uso do Express. A aplicação terá informações sobre livros, cópias de livros, autores e outras informações-chave. Nós não vamos, no entanto, armazenar informações sobre outros itens que a biblioteca pode emprestar e nem vamos oferecer a infraestrutura necessária para suportar os serviços de uma biblioteca grande (de verdade).</p> + +<h2 id="Estou_perdido_onde_encontro_o_código-fonte">Estou perdido, onde encontro o código-fonte?</h2> + +<p>Com o avanço nos tutoriais, forneceremos trechos de códigos para você copiar e colar. Você também receberá trechos apenas com códigos iniciais para completá-los e aprimorá-los por conta própria.</p> + +<p>Dica: Em vez de simplesmente copiar e colar todos os códigos, a sugestão é digitá-los. Isso ajuda você a se familiarizar com a sintaxe, melhorando o nível de aprendizado.</p> + +<p>Se ficar perdido no meio do caminho, fique calmo. Você pode acessar o código inteiro pelo<a href="https://github.com/mdn/express-locallibrary-tutorial"> Github</a>.</p> + +<div class="note"> +<p><strong>Nota:</strong> As versões específicas do Node, Express e outros módulos que adotados no tutorial estão listados no arquivo <a href="https://github.com/mdn/express-locallibrary-tutorial/blob/master/package.json">package.json</a>.</p> +</div> + +<h2 id="Sumário">Sumário</h2> + +<p>Agora que você entedeu o que é o site "Biblioteca Local " e o que vamos aprender ao longo do projeto, é hora de criar nossa estrutura de pastas e arquivos.</p> + +<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs")}}</p> + +<h2 id="Neste_módulo">Neste módulo</h2> + +<ul> + <li><a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Express_Nodejs/Introdu%C3%A7%C3%A3o">Indrodução ao Express</a></li> + <li><a href="https://developer.mozilla.org/pt-BR/docs/Learn/Server-side/Express_Nodejs/ambiente_de_desenvolvimento">Conhecendo Node como ambiente de desenvolvimento</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li> +</ul> diff --git a/files/pt-br/learn/server-side/first_steps/client-server_overview/index.html b/files/pt-br/learn/server-side/first_steps/client-server_overview/index.html new file mode 100644 index 0000000000..57dd82946d --- /dev/null +++ b/files/pt-br/learn/server-side/first_steps/client-server_overview/index.html @@ -0,0 +1,333 @@ +--- +title: Visão geral do cliente-servidor +slug: Learn/Server-side/First_steps/Client-Server_overview +tags: + - Desenvolvimento Web + - Iniciante + - servidores + - site dinâmico + - site estatico +translation_of: Learn/Server-side/First_steps/Client-Server_overview +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/First_steps/Introduction", "Learn/Server-side/First_steps/Web_frameworks", "Learn/Server-side/First_steps")}}</div> + +<p class="summary">Agora que você conhece o propósito e os benefícios potenciais da programação do lado do servidor, examinaremos em detalhes o que acontece quando um servidor recebe uma "solicitação dinâmica" de um navegador. Como a maioria dos códigos do lado servidor do site lida com solicitações e respostas de maneiras semelhantes, isso o ajudará a entender o que você precisa fazer ao escrever a maior parte do seu próprio código.</p> + +<p class="summary"></p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré requisitos:</th> + <td>Conhecimento básico em informática. Uma compreensão básica do que é um servidor web.</td> + </tr> + <tr> + <th scope="row">Objetivos:</th> + <td>Entender as interações entre cliente e servidor em um website dinâmico e, em particular, quais operações precisam ser realizadas pelo código no servidor.</td> + </tr> + </tbody> +</table> + +<p>Não há código real em discussão porque ainda não escolhemos um framework web para escrever nosso código. No entanto essa discussão é muito relevante, porque o comportamento descrito deve ser implementado pelo seu código no servidor, independentemente de qual linguagem de programação ou framework web você escolha.</p> + +<h2 id="Web_servers_e_HTTP_uma_introdução">Web servers e HTTP (uma introdução)</h2> + +<p>Navegadores Web se comunicam com <a href="https://developer.mozilla.org/en-US/docs/Learn/Common_questions/What_is_a_web_server">servidores Web</a> usando o <strong>H</strong>yper<strong>T</strong>ext<strong>T</strong>ransfer <strong>P</strong>rotocol (<a href="https://wiki.developer.mozilla.org/en-US/docs/Web/HTTP">HTTP</a>). Quando você clica em um link em uma página web, envia um formulário, ou faz uma pesquisa, o browser envia uma Requisição HTTP para o servidor.</p> + +<p>A requisição inclui:</p> + +<ul> + <li>Uma URL que identifica o servidor e o recurso de destino(e.g. por exemplo, um arquivo HTML, um determinado ponto de dados no servidor ou uma ferramenta a ser executada).</li> + <li>Um método que define a ação necessária(por exemplo, para obter um arquivo ou para salvar ou atualizar alguns dados). Os diferentes métodos e suas ações associadas estão listados abaixo : + <ul> + <li><code>GET</code>: Obtenha um recurso específico(por exemplo, um arquivo contendo informações sobre um produto ou uma lista de produtos) .</li> + <li><code>POST</code>: Crie um novo recurso(por exemplo, adicione um novo artigo a uma wiki, adicione um novo contato a um banco de dados e entre outros) .</li> + <li><code>HEAD</code>: Obtenha as informações de metadados sobre um recurso específico, sem obter o corpo, como o GET faria. Você pode, por exemplo, usar uma solicitação HEAD para descobrir a última vez que um recurso foi atualizado e, em seguida, usar a solicitação GET(mais "CARA") para baixar o recurso se ele tiver sido alterado.</li> + <li><code>PUT</code>: Atualize um recurso existente(ou crie um novo se ele não existir).</li> + <li><code>DELETE</code>: Apague um recurso específico.</li> + <li><code>TRACE</code>, <code>OPTIONS</code>, <code>CONNECT</code>, <code>PATCH</code>: Esses métodos são para tarefas menos comuns/avançadas, não os cobriremos por aqui.</li> + </ul> + </li> + <li>Informações adicionais podem ser codificadas com a solicitação(por exemplo, dados de formulário HTML). As informações podem ser codificadas como : + <ul> + <li>Paramêtros de URL : Solicitações <code>GET</code> codificam dados na URL enviada ao servidor, adicionando pares de nome/valor ao final dela— por exemplo, <code>http://mysite.com<strong>?name=Fred&age=11</strong></code>. Você sempre tem um ponto de interrogação (<code>?</code>) separando o resto da URL dos paramêtros de URL, um sinal de igual (<code>=</code>) separando cada nome de seu valor associado , e um "E" comercial (<code>&</code>) separando cada par. Os paramêtros URL são inerentemente inseguros, pois podem ser alterados pelos usuários e reenviados. Como resultado, os parâmetros de URL/ solicitações GET não são usados para solicitações que atualizam dados no servidor.</li> + <li><code>POST</code> data(dados de postagem). As solicitações POST adicionam novos recursos, cujos dados são codificados no corpo da solicitação.</li> + <li>Cookies do lado do cliente. Os cookies contêm dados de sessão sobre o cliente, incluindo chaves que o servidor pode usar para determinar seu status de login e permissões aos recursos.</li> + </ul> + </li> +</ul> + +<p>Os servidores da web aguardam as mensagens de solicitação do cliente, processam-nas quando chegam e respondem ao navegador da web com uma mensagem de resposta HTTP. A resposta contém( <a href="/en-US/docs/Web/HTTP/Status">HTTP Response status code</a>) um código de status de resposta HTTP que indica se a solicitação foi bem sucedida ou não (e.g. "<code>200 OK</code>" para sucesso, "<code>404 Not Found</code>" se o recurso não puder ser encontrado, "<code>403 Forbidden</code>" se o usuário não estiver autorizado para ver o recurso, etc). O corpo de uma resposta bem sucedida a uma solicitação <code>GET</code> conteria o recurso solicitado.</p> + +<p>Quando uma página HTML é retornada, ela é processada pelo navegador da web. Como parte do processamento, o navegador pode descobrir links para outros recursos (por exemplo, uma página HTML geralmente faz referência a páginas JavaScript e CSS) e enviará solicitações HTTP separadas para baixar esses arquivos.</p> + +<p>Os sites estáticos e dinâmicos (discutidos nas seções a seguir) usam exatamente o mesmo protocolo / padrões de comunicação.</p> + +<h3 id="Exemplo_de_requisiçãoresposta_GET">Exemplo de requisição/resposta GET</h3> + +<p>Você pode fazer uma simples requisição GET clicando em um link ou buscando em um site (como uma simples ferramenta de pesquisa). Por exemplo, a requisição HTTP enviada quando você realiza uma busa na MDN pelo termo "cliente servidor visão geral" será muito parecido com o texto mostrado abaixo (não será identico porque partes da mensagem depente de seu navegador/configuração.</p> + +<div class="note"> +<p>O formato das mensagens HTTP é definido em um "padrão da web" (<a href="http://www.rfc-editor.org/rfc/rfc7230.txt">RFC7230</a>). Você não precisa saber esse nível de detalhe, mas pelo menos agora você sabe de onde vem tudo isso.</p> +</div> + +<h4 id="A_requisição">A requisição</h4> + +<p>Cada linha da solicitação contém informações sobre ela. A primeira parte é chamada de <strong>header</strong>, e contém informações úteis sobre o pedido, Da mesma forma que um <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML">HTML head</a> contém informações úteis sobre um documento HTML(mas não o conteúdo real em si, que está no corpo):</p> + +<pre class="notranslate">GET https://developer.mozilla.org/en-US/search?q=client+server+overview&topic=apps&topic=html&topic=css&topic=js&topic=api&topic=webdev HTTP/1.1 +Host: developer.mozilla.org +Connection: keep-alive +Pragma: no-cache +Cache-Control: no-cache +Upgrade-Insecure-Requests: 1 +User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 +Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 +Referer: https://developer.mozilla.org/en-US/ +Accept-Encoding: gzip, deflate, sdch, br +<code>Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7</code> +Accept-Language: en-US,en;q=0.8,es;q=0.6 +Cookie: sessionid=6ynxs23n521lu21b1t136rhbv7ezngie; csrftoken=zIPUJsAZv6pcgCBJSCj1zU6pQZbfMUAT; dwf_section_edit=False; dwf_sg_task_completion=False; _gat=1; _ga=GA1.2.1688886003.1471911953; ffo=true +</pre> + +<p>A primeira e a segunda linhas contêm a maioria das informações sobre as quais falamos acima:</p> + +<ul> + <li>O tipo de requisição (<code>GET</code>).</li> + <li>A URL do recurso de destino (<code>/en-US/search</code>).</li> + <li>Os parâmetros de URL (<code>q=client%2Bserver%2Boverview&topic=apps&topic=html&topic=css&topic=js&topic=api&topic=webdev</code>).</li> + <li>O site de destino(developer.mozilla.org).</li> + <li>O final da primeira linha inclui uma string curta que identifica a versão e especifica o protocolo (<code>HTTP/1.1</code>).</li> +</ul> + +<p>A linha final contém informações sobre os cookies do lado do cliente - você pode ver neste caso que o cookie inclui um id para gerenciar as sessões (<code>Cookie: sessionid=6ynxs23n521lu21b1t136rhbv7ezngie; ...</code>).</p> + +<p>As linhas restantes contêm informações sobre o navegador usado e o tipo de respostas que ele pode manipular. Por exemplo, você pode ver aqui que:</p> + +<ul> + <li>Meu navegador(<code>User-Agent</code>) é o Mozilla Firefox (<code>Mozilla/5.0</code>).</li> + <li>Pode aceitar informações comprimidas gzip(<code>Accept-Encoding: gzip</code>).</li> + <li>Pode aceitar o conjunto específico de caracteres (<code>Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7</code>) e idiomas (<code>Accept-Language: de,en;q=0.7,en-us;q=0.3</code>).</li> + <li>The <code>Referer</code> line indica o endereço da página web que continha o link para este recurso (i.e. a origem da requisição, <code>https://developer.mozilla.org/en-US/</code>).</li> +</ul> + +<p>As solicitações HTTP também podem ter um corpo, mas está vazio neste caso</p> + +<h4 id="A_resposta">A resposta</h4> + +<p>A primeira parte da resposta para esta solicitação é mostrada abaixo. O header(cabeçalho) contém informações, como as seguintes:</p> + +<ul> + <li>A primeira linha contém o código de resposta <code>200 OK</code>, o que nos diz que a solicitação foi bem sucedida.</li> + <li>Podemos ver que a resposta é <code>text/html</code> formatada (<code>Content-Type</code>).</li> + <li>Também podemos ver que ele usa o conjunto de caracteres UTF-8 (<code>Content-Type: text/html; charset=utf-8</code>).</li> + <li>O head também nos diz o quão grande é (<code>Content-Length: 41823</code>).</li> +</ul> + +<p>No final da mensagem vemos o conteúdo do corpo( <strong>body</strong> content) — que contém o HTML real retornado pela solicitação.</p> + +<pre class="brush: html notranslate">HTTP/1.1 200 OK +Server: Apache +X-Backend-Server: developer1.webapp.scl3.mozilla.com +Vary: Accept,Cookie, Accept-Encoding +Content-Type: text/html; charset=utf-8 +Date: Wed, 07 Sep 2016 00:11:31 GMT +Keep-Alive: timeout=5, max=999 +Connection: Keep-Alive +X-Frame-Options: DENY +Allow: GET +X-Cache-Info: caching +Content-Length: 41823 + + + +<!DOCTYPE html> +<html lang="en-US" dir="ltr" class="redesign no-js" data-ffo-opensanslight=false data-ffo-opensans=false > +<head prefix="og: http://ogp.me/ns#"> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=Edge"> + <script>(function(d) { d.className = d.className.replace(/\bno-js/, ''); })(document.documentElement);</script> + ... +</pre> + +<p>O restante do header da resposta inclui informações sobre a resposta (por exemplo, quando ela foi gerada), o servidor e como ele espera que o navegador manipule a página(e.g. A linha <code>X-Frame-Options: DENY</code> diz ao navegador para não permitir que esta página seja incorporada em outros sites {{htmlelement("iframe")}} ).</p> + +<h3 id="Exemplo_de_requestsolicitaçãoresponseresposta_POST">Exemplo de request(solicitação)/response(resposta) POST</h3> + +<p>Um HTTP <code>POST</code> é feito quando você envia um formulário contendo informações a serem salvas no servidor.</p> + +<h4 id="A_requisição_2">A requisição</h4> + +<p>O texto abaixo mostra a solicitação HTTP feita quando um usuário envia novos detalhes de perfil neste site. O formato de requisição é quase o mesmo que o exemplo de solicitação <code>GET</code> mostrado anteriormente, embora a primeira linha reconheça esta solicitação como um <code>POST</code>. </p> + +<pre class="brush: html notranslate">POST https://developer.mozilla.org/en-US/profiles/hamishwillee/edit HTTP/1.1 +Host: developer.mozilla.org +Connection: keep-alive +Content-Length: 432 +Pragma: no-cache +Cache-Control: no-cache +Origin: https://developer.mozilla.org +Upgrade-Insecure-Requests: 1 +User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 +Content-Type: application/x-www-form-urlencoded +Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 +Referer: https://developer.mozilla.org/en-US/profiles/hamishwillee/edit +Accept-Encoding: gzip, deflate, br +Accept-Language: en-US,en;q=0.8,es;q=0.6 +Cookie: sessionid=6ynxs23n521lu21b1t136rhbv7ezngie; _gat=1; csrftoken=zIPUJsAZv6pcgCBJSCj1zU6pQZbfMUAT; dwf_section_edit=False; dwf_sg_task_completion=False; _ga=GA1.2.1688886003.1471911953; ffo=true + +csrfmiddlewaretoken=zIPUJsAZv6pcgCBJSCj1zU6pQZbfMUAT&user-username=hamishwillee&user-fullname=Hamish+Willee&user-title=&user-organization=&user-location=Australia&user-locale=en-US&user-timezone=Australia%2FMelbourne&user-irc_nickname=&user-interests=&user-expertise=&user-twitter_url=&user-stackoverflow_url=&user-linkedin_url=&user-mozillians_url=&user-facebook_url=</pre> + +<p>A principal diferença é que o URL não possui parâmetros. Como você pode ver, as informações do formulário são codificadas no corpo da solicitação (por exemplo, o novo nome completo do usuário é definido usando: <code>&user-fullname=Hamish+Willee</code>).</p> + +<h4 id="A_resposta_2">A resposta</h4> + +<p>A resposta de solicitação é mostrada abaixo. O código de status "<code>302 Found</code>" diz ao navegador que a postagem foi bem sucedida, e que deve emitir uma segunda solicitação HTTP para carregar a página especificada no campo determinado( <code>Location</code> field). As informações são semelhantes às da resposta a uma solicitação <code>GET</code> .</p> + +<pre class="brush: html notranslate">HTTP/1.1 302 FOUND +Server: Apache +X-Backend-Server: developer3.webapp.scl3.mozilla.com +Vary: Cookie +Vary: Accept-Encoding +Content-Type: text/html; charset=utf-8 +Date: Wed, 07 Sep 2016 00:38:13 GMT +Location: https://developer.mozilla.org/en-US/profiles/hamishwillee +Keep-Alive: timeout=5, max=1000 +Connection: Keep-Alive +X-Frame-Options: DENY +X-Cache-Info: not cacheable; request wasn't a GET or HEAD +Content-Length: 0 +</pre> + +<div class="note"> +<p><strong>Note</strong>: As respostas e solicitações HTTP mostradas nesse exemplo foram capturadas utilizando o aplicativo <a href="https://www.telerik.com/download/fiddler">Fiddler</a> , mas você pode obter informações semelhantes utilizando web sniffers (e.g. <a href="http://websniffer.cc/">Websniffer</a>) ou extensões de navegador como o <a href="https://addons.mozilla.org/en-US/firefox/addon/httpfox/">HttpFox</a>. Você pode tentar isso sozinho. Use qualquer uma das ferramentas vinculadas e navegue por um site e edite as informações de perfil para ver os diferentes tipos de solicitações e respostas. A maioria dos navegadores possuem ferramentas que monitoram solicitações de rede(por exemplo, a ferramenta <a href="/en-US/docs/Tools/Network_Monitor">Network Monitor</a> no Firefox).</p> +</div> + +<h2 id="Sites_estáticos">Sites estáticos</h2> + +<p dir="ltr" id="tw-target-text">Um site estático é aquele que retorna o mesmo conteúdo codificado do servidor sempre que um recurso específico é solicitado. Por exemplo, se você tiver uma página sobre um produto em <code>/static/myproduct1.html</code>, esta mesma página será devolvida a todos os usuários. Se você adicionar outro produto semelhante ao seu site, você precisará adicionar outra página (e.g. <code>myproduct2.html</code>) e assim por diante. Isso pode começar a ficar realmente ineficiente - o que acontece quando você chega a milhares de páginas de produtos? Você repetiria muitos códigos em cada página (o modelo básico de página, estrutura, etc.) e, se quisesse alterar qualquer coisa na estrutura da página - como adicionar uma nova seção de "produtos relacionados", por exemplo -, tem que mudar cada página individualmente.</p> + +<div class="note"> +<p><strong>Note</strong>: Os sites estáticos são excelentes quando você tem um pequeno número de páginas e deseja enviar o mesmo conteúdo para todos os usuários. No entanto, eles podem ter um custo significativo para manter à medida que o número de páginas aumenta.</p> +</div> + +<p>Vamos recapitular como isso funciona, olhando novamente para o diagrama de arquitetura de site estático que vimos no último artigo.</p> + +<p><img alt="A simplified diagram of a static web server." src="https://mdn.mozillademos.org/files/13841/Basic%20Static%20App%20Server.png"></p> + +<p>Quando o usuário deseja navegar em uma página, O navegador envia uma solicitação HTTP <code>GET</code> especificando o URL dessa página HTML. O servidor recupera o documento solicitado de seu sistema de arquivos e retorna uma resposta HTTP contendo o documento e um <a href="/en-US/docs/Web/HTTP/Status">HTTP Response status code</a> de "<code>200 OK</code>" (indicando). O servidor pode retornar um diferente código de status, por exemplo "<code>404 Not Found</code>" se o arquivo não estiver presente no servidor, ou "<code>301 Moved Permanently</code>" se o arquivo existe, mas foi redirecionado para um local diferente.</p> + +<p>O servidor de um site estático sempre precisará processar solicitações GET, porque o servidor não armazena nenhum dado modificável. Ele também não altera suas respostas com base nos dados de solicitação HTTP (por exemplo, parâmetros de URL ou cookies).</p> + +<p>No entanto, entender como os sites estáticos funcionam é útil ao aprender a programação do lado do servidor, porque os sites dinâmicos lidam com solicitações de arquivos estáticos (CSS, JavaScript, imagens estáticas etc.) exatamente da mesma maneira.</p> + +<h2 id="Sites_dinâmicos">Sites dinâmicos</h2> + +<p>Um site dinâmico é aquele que pode gerar e retornar conteúdo com base no URL e nos dados de solicitação específicos (em vez de sempre retornar o mesmo arquivo embutido em código para um URL específico). Usando o exemplo de um site de produto, o servidor armazenaria "dados" do produto em um banco de dados em vez de arquivos HTML individuais. Ao receber uma solicitação HTTP <code>GET</code> para o produto , o servidor determina o ID do produto, busca os dados do banco de dados e, em seguida, constrói a página HTML para a resposta inserindo os dados em um modelo HTML. Isso tem grandes vantagens em relação a um site estático:</p> + +<p>O uso de um banco de dados permite que as informações do produto sejam armazenadas com eficiência de uma forma facilmente extensível, modificável e pesquisável</p> + +<p>O uso de modelos HTML torna muito fácil alterar a estrutura HTML, porque isso só precisa ser feito em um lugar, em um único modelo, e não em potencialmente milhares de páginas estáticas.</p> + +<h3 id="Anatomia_de_uma_solicitação_dinâmica">Anatomia de uma solicitação dinâmica</h3> + +<p dir="ltr" id="tw-target-text">Esta seção fornece uma visão geral passo a passo da solicitação HTTP "dinâmica" e do ciclo de resposta, com base no que vimos no último artigo com muito mais detalhes. Para "manter as coisas reais", usaremos o contexto de um site de gerente de equipe esportiva, onde um treinador pode selecionar o nome e o tamanho da equipe em um formulário HTML e receber uma sugestão de "melhor escalação" para o próximo jogo.</p> + +<p>O diagrama abaixo mostra os principais elementos do site do "treinador de equipe", juntamente com rótulos numerados para a sequência de operações quando o treinador acessa sua lista de "melhores equipes". As partes do site que o tornam dinâmico são o Web application(é assim que nos referiremos ao código do lado do servidor que processa solicitações HTTP e retorna respostas HTTP), o Banco de Dados, que contém informações sobre jogadores, times, treinadores e seus relacionamentos e os modelos HTML.</p> + +<p><img alt="This is a diagram of a simple web server with step numbers for each of step of the client-server interaction." src="https://mdn.mozillademos.org/files/13829/Web%20Application%20with%20HTML%20and%20Steps.png" style="height: 584px; width: 1226px;"></p> + +<p dir="ltr" id="tw-target-text">Após o treinador enviar o formulário com o nome da equipe e número de jogadores, a sequência de operações é:</p> + +<ol> + <li>O navegador cria uma solicitação HTTP <code>GET</code> para o servidor usando a URL base para o recurso(<code>/best</code>) e codifica o número do time e do jogador como parâmetros de URL (e.g. <code>/best?team=my_team_name&show=11)</code> ou como parte do padrão de URL (e.g. <code>/best/my_team_name/11/</code>). A solicitação <code>GET</code>é usada porque a solicitação está apenas buscando dados (não modificando dados).</li> + <li>O servidor da Web detecta que a solicitação é "dinâmica" e a encaminha ao Web application para o processamento (o servidor da Web determina como lidar com URLs diferentes com base nas regras de correspondência de padrões definidas em sua configuração).</li> + <li>O <em>Web Application</em> identifica que a intenção da solicitação é obter a "lista da melhor equipe" com base no URL<span>(</span><code>/best/</code><span>)</span>e descobre o nome da equipe necessária e o número de jogadores no URL. O Web application então obtém as informações necessárias do banco de dados (usando parâmetros "internos" adicionais para definir quais jogadores são os "melhores" e, possivelmente, também obtendo a identidade do treinador conectado a partir de um cookie do lado do cliente).</li> + <li>O Web application cria dinamicamente uma página HTML colocando os dados (do banco de dados) em espaços reservados dentro de um modelo HTML.</li> + <li> + <p dir="ltr" id="tw-target-text">O Web application retorna o HTML gerado para o navegador da Web (por meio do servidor da Web), junto com um código de status HTTP de 200 ("sucesso"). Se alguma coisa impedir que o HTML seja retornado, o Web application retornará outro código - por exemplo, "404" para indicar que a equipe não existe.</p> + </li> + <li>O navegador da Web começará a processar o HTML retornado, enviando solicitações separadas para obter qualquer outro arquivo CSS ou JavaScript ao qual faça referência (consulte a etapa 7).</li> + <li>O servidor da Web carrega arquivos estáticos do sistema de arquivos e os retorna ao navegador diretamente (novamente, o tratamento correto do arquivo é baseado nas regras de configuração e correspondência de padrão de URL).</li> +</ol> + +<p dir="ltr" id="tw-target-text">Uma operação para atualizar um registro no banco de dados seria tratada de forma semelhante, exceto que, como qualquer atualização de banco de dados, a solicitação HTTP do navegador deve ser codificada como uma solicitação <code>POST</code>. </p> + +<h3 id="Fazendo_outro_trabalho">Fazendo outro trabalho</h3> + +<p>O trabalho de um Web application é receber solicitações HTTP e retornar respostas HTTP. Embora interagir com um banco de dados para obter ou atualizar informações sejam tarefas muito comuns, o código pode fazer outras coisas ao mesmo tempo ou não interagir com um banco de dados.</p> + +<p dir="ltr" id="tw-target-text">Um bom exemplo de uma tarefa adicional que um Web application pode realizar seria enviar um e-mail aos usuários para confirmar seu registro no site. O site também pode realizar registro ou outras operações.</p> + +<h3 id="Retornando_algo_diferente_de_HTML">Retornando algo diferente de HTML</h3> + +<p dir="ltr" id="tw-target-text">O código do site do lado do servidor não precisa retornar snippets / arquivos HTML na resposta. Em vez disso, ele pode criar e retornar dinamicamente outros tipos de arquivos (texto, PDF, CSV, etc.) ou mesmo dados (JSON, XML, etc.).</p> + +<p>A ideia de retornar dados a um navegador da web para que ele possa atualizar dinamicamente seu próprio conteúdo ({{glossary("AJAX")}}) já existe há um bom tempo. Mais recentemente, os "aplicativos de página única" se tornaram populares, em que todo o site é escrito com um único arquivo HTML que é atualizado dinamicamente quando necessário. Os sites criados com esse estilo de aplicativo geram muitos custos computacionais do servidor para o navegador da web e podem resultar em sites que parecem se comportar muito mais como aplicativos nativos (altamente responsivos etc.).</p> + +<h2 id="Web_frameworks_simplificam_a_programação_da_Web_do_lado_do_servidor"><br> + Web frameworks simplificam a programação da Web do lado do servidor</h2> + +<p dir="ltr" id="tw-target-text">Os frameworks web do lado do servidor tornam a escrita de código para lidar com as operações descritas acima muito mais fácil.</p> + +<p dir="ltr" id="tw-target-text">Uma das operações mais importantes que eles executam é fornecer mecanismos simples para mapear URLs de diferentes recursos / páginas para funções de manipulador específicas. Isso torna mais fácil manter o código associado a cada tipo de recurso separado. Também traz benefícios em termos de manutenção, pois você pode alterar a URL usada para entregar um determinado recurso em um único local, sem ter que alterar a função do manipulador.</p> + +<p>Por exemplo, considere o seguinte código Django (Python) que mapeia dois padrões de URL para duas funções de visualização. O primeiro padrão garante que uma solicitação HTTP com um URL de recurso de <code>/best</code> será passado para uma função chamada <code>index()</code> no módulo <code>views</code>. Uma solicitação que tem o padrão "<code>/best/junior</code>", será passada para a fução view <code>junior()</code> .</p> + +<pre class="brush: python notranslate"># file: best/urls.py +# + +from django.conf.urls import url + +from . import views + +urlpatterns = [ + # example: /best/ + url(r'^$', views.index), + # example: /best/junior/ + url(r'^junior/$', views.junior), +]</pre> + +<div class="note"> +<p><strong>Nota </strong>: Os primeiros parâmetros da função <code>url()</code> pode parecer um pouco estranho (e.g. <code>r'^junior/$'</code>) porque eles usam uma técnica de correspondência de padrões chamada "expressões regulares"(RegEx, or RE). Você não precisa saber como as expressões regulares funcionam neste ponto, a não ser que elas nos permitam combinar padrões na URL (em vez dos valores codificados acima) e usá-los como parâmetros em nossas funções de visualização. Por exemplo, um RegEx realmente simples pode dizer "corresponde a uma única letra maiúscula, seguida por entre 4 e 7 letras minúsculas."</p> +</div> + +<p>O framework web também torna mais fácil para uma função de visualização buscar informações do banco de dados. A estrutura de nossos dados é definida em modelos, que são classes Python que definem os campos a serem armazenados no banco de dados subjacente. Se tivermos um modelo denominado Team com um campo de "team_type", então podemos usar uma sintaxe de consulta simples para recuperar todas as equipes que possuem um tipo específico.</p> + +<p>O exemplo abaixo obtém uma lista de todas as equipes que têm o exato (diferencia maiúsculas de minúsculas) <code>team_type</code> de "junior" —Observe o formato field name (<code>team_type</code>) seguido por sublinhado duplo e, em seguida, o tipo de correspondência a usar (neste caso <code>exact</code>). Existem muitos outros tipos de casos e podemos conectá-los em cadeia. Também podemos controlar a ordem e o número de resultados retornados.</p> + +<pre class="brush: python notranslate">#best/views.py + +from django.shortcuts import render + +from .models import Team + + +def junior(request): + list_teams = Team.objects.filter(team_type__exact="junior") + context = {'list': list_teams} + return render(request, 'best/index.html', context) +</pre> + +<p><code><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">Depois da função </span></font>junior()</code> obter a lista de junior teams, é chamada a função <code>render()</code> , passando o original <code>HttpRequest</code>, um modelo HTML e um objeto de "contexto" que define as informações a serem incluídas no modelo. A função <code>render()</code> é uma função de conveniência que gera HTML usando um contexto e um modelo HTML e o retorna em um objeto <code>HttpResponse</code> .</p> + +<p dir="ltr" id="tw-target-text">Obviamente, os frameworks da Web podem ajudá-lo em muitas outras tarefas. Discutiremos muitos outros benefícios e algumas opções populares de estrutura da web no próximo artigo.</p> + +<h2 id="Resumo">Resumo</h2> + +<p dir="ltr" id="tw-target-text">Neste ponto, você deve ter uma boa visão geral das operações que o código do lado do servidor deve realizar e conhecer algumas das maneiras pelas quais uma framework Web do lado do servidor pode tornar isso mais fácil.</p> + +<p dir="ltr" id="tw-target-text">Em um módulo a seguir, vamos ajudá-lo a escolher o melhor Web Framework para seu primeiro site.</p> + +<p>{{PreviousMenuNext("Learn/Server-side/First_steps/Introduction", "Learn/Server-side/First_steps/Web_frameworks", "Learn/Server-side/First_steps")}}</p> + +<h2 id="Neste_módulo">Neste módulo</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/First_steps/Introduction">Introduction to the server side</a></li> + <li><a href="/en-US/docs/Learn/Server-side/First_steps/Client-Server_overview">Client-Server overview</a></li> + <li><a href="/en-US/docs/Learn/Server-side/First_steps/Web_frameworks">Server-side web frameworks</a></li> + <li><a href="/en-US/docs/Learn/Server-side/First_steps/Website_security">Website security</a></li> +</ul> diff --git a/files/pt-br/learn/server-side/first_steps/index.html b/files/pt-br/learn/server-side/first_steps/index.html new file mode 100644 index 0000000000..fface84a77 --- /dev/null +++ b/files/pt-br/learn/server-side/first_steps/index.html @@ -0,0 +1,57 @@ +--- +title: Primeiros passos programando o site no servidor +slug: Learn/Server-side/First_steps +tags: + - Beginner + - CodingScripting + - Guide + - Intro + - Landing + - Learn + - NeedsTranslation + - Server-side programming + - TopicStub +translation_of: Learn/Server-side/First_steps +--- +<div>{{LearnSidebar}}</div> + +<p>Neste módulo nós iremos responder uma pergunta fundamental sobre programção server-side —"O que é?","Quão diferente é da programação client-side?", e "Por que é tão útil?".</p> + +<p>Em seguida vamos fornecer uma visão geral de alguns dos mais populares server-side web framworks juntamente com orientações sobre como selecionar o mais adequado framwork para criar seu primeiro website.</p> + +<p>Por fim, fornecemos um artigo introdutório de alto nível sobre segurança do servidor da web</p> + +<p>Finalmente,nós iremos fornecer uma introdução de alto nível. </p> + +<h2 id="Pré-requisitos">Pré-requisitos</h2> + +<p>Antes de começarmos este módulo,você não precisa ter nenhum conhecimento de programação server-side,ou mesmo qualquer outro tipo de programção.</p> + +<p>Entretanto,você precisa saber como a web funciona.Nós recomendamos que você leia primeiro os seguintes tópicos:</p> + +<ul> + <li>O que é um servidor?</li> + <li>Qual o software eu preciso para construir um website?</li> + <li>Como eu faço o upload de arquivos para um webserver?</li> +</ul> + +<p>Com o entendimento básico disso, você estará pronto para trabalhar nos módulos desta seção.</p> + +<h2 id="Guias">Guias</h2> + +<dl> + <dt> Introdução ao serve-side</dt> + <dd>Bem-vindo ao curso para iniciante de programação server-side do MDN! Neste primeiro artigo, examinaremos a programação server-side de alto nível, respondendo a perguntas como "O que é?", "Como ela difere da programação do lado do cliente?" E "Por que é tão útil?". Depois de ler este artigo, você entenderá o poder adicional disponível para sites por meio de codificação server-side.</dd> + <dt><a href="/en-US/docs/Learn/Server-side/First_steps/Client-Server_overview">Visão geral do cliente-servidor</a></dt> + <dd>Agora que você conhece a finalidade e os benefícios potenciais da programação server-side , examinaremos em detalhes o que acontece quando um servidor recebe uma "solicitação dinâmica" de um navegador. Como o código server-side da maioria dos sites lida com solicitações e respostas de maneira semelhante, isso ajudará você a entender o que precisa fazer ao escrever seu próprio código.</dd> + <dt>Framework <a href="/en-US/docs/Learn/Server-side/First_steps/Web_frameworks"> server-side</a></dt> + <dd>No último artigo foi mostrado o que uma aplicação server-side precisa fazer para responder as solicitações de um navegador da web. Agora mostramos como as estruturas da Web podem simplificar essas tarefas e ajudá-lo a escolher o framework para seu primeiro aplicativo da Web server-side.</dd> + <dt>Segurança do website</dt> + <dd>A segurança do website exige vigilância em todos os aspectos,do desenvolvimento ao uso. Este artigo introdutório não fará de você um guru em segurança de website, mas ajudará você a entender quais as primeiras medidas importantes que você deve tomar para proteger seu aplicativo da Web contra as ameaças mais comuns.</dd> +</dl> + +<h2 id="Avaliação">Avaliação</h2> + + + +<p>Este módulo de "visão geral" não tem nenhuma avaliação porque ainda não mostramos nenhum código. Esperamos que, a esta altura, você tenha um bom entendimento dos tipos de funcionalidade que pode oferecer usando a programação do lado do servidor e que tenha tomado uma decisão sobre qual estrutura da web do lado do servidor usará para criar seu primeiro site.</p> diff --git a/files/pt-br/learn/server-side/first_steps/introdução/index.html b/files/pt-br/learn/server-side/first_steps/introdução/index.html new file mode 100644 index 0000000000..e5cc0b991c --- /dev/null +++ b/files/pt-br/learn/server-side/first_steps/introdução/index.html @@ -0,0 +1,237 @@ +--- +title: Introdução ao lado servidor +slug: Learn/Server-side/First_steps/Introdução +tags: + - Desenvolvimento Web + - Iniciante + - Introdução + - Programação + - Programação do lado do servidor + - Servidor + - programação do lado do cliente +translation_of: Learn/Server-side/First_steps/Introduction +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/Server-side/First_steps/Client-Server_overview", "Learn/Server-side/First_steps")}}</div> + +<p dir="ltr" id="tw-target-text">Bem-vindo ao curso de programação do lado do servidor para iniciantes do MDN! Neste primeiro artigo, examinamos a programação do lado do servidor de um alto nível, respondendo a perguntas como "o que é?", "Como ela difere da programação do lado do cliente?" E "por que é tão útil?" . Depois de ler este artigo, você entenderá o poder adicional disponível para sites por meio da codificação do lado do servidor.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré-requisitos :</th> + <td>Conhecimento básico de informática. Uma compreensão básica do que é um servidor web</td> + </tr> + <tr> + <th scope="row"> + <p>Objetivo :</p> + </th> + <td>Ganhar familiaridade com o que é programação do lado do servidor, o que ela pode fazer e como ela difere da programação do lado do cliente.</td> + </tr> + </tbody> +</table> + +<p dir="ltr" id="tw-target-text">A maioria dos sites de grande escala usa código do lado do servidor para exibir dinamicamente diferentes dados quando necessário, geralmente retirados de um banco de dados armazenado em um servidor e enviados ao cliente para serem exibidos por meio de algum código (por exemplo, HTML e JavaScript).</p> + +<p>Talvez o benefício mais significativo do código do lado do servidor seja que ele permite personalizar o conteúdo do site para usuários individuais. Os sites dinâmicos podem destacar o conteúdo que é mais relevante com base nas preferências e hábitos do usuário. Ele também pode tornar os sites mais fáceis de usar, armazenando preferências e informações pessoais - por exemplo, reutilizando os detalhes armazenados do cartão de crédito para agilizar os pagamentos subsequentes.</p> + +<p>Pode até permitir a interação com os usuários do site, enviando notificações e atualizações por e-mail ou por outros canais. Todos esses recursos permitem um envolvimento muito mais profundo com os usuários.</p> + +<p>No mundo moderno do desenvolvimento web, aprender sobre desenvolvimento do lado do servidor é extremamente recomendado.</p> + +<h2 id="O_que_é_programação_de_site_do_lado_do_servidor">O que é programação de site do lado do servidor ?</h2> + +<p>Navegadores comunicam-se com <a href="/en-US/docs/Learn/Common_questions/What_is_a_web_server">web servers</a> utilizando o <strong>H</strong>yper<strong>T</strong>ext <strong>T</strong>ransfer <strong>P</strong>rotocol ({{glossary("HTTP")}}). Quando você clica em um link em uma página da web, envia um formulário ou faz uma pesquisa, uma <strong>HTTP request(solicitação HTTP)</strong> é enviada do seu navegador para o servidor de destino.</p> + +<p dir="ltr" id="tw-target-text">A solicitação inclui uma URL que identifica o recurso afetado, um método que define a ação necessária (por exemplo, para obter, excluir ou postar o recurso) e pode incluir informações adicionais codificadas em parâmetros de URL(Os pares field-value(campo-valor) são enviados por meio de uma <a href="https://en.wikipedia.org/wiki/Query_string">query string</a>), como dados POST (dados enviados pelo método <a href="/en-US/docs/Web/HTTP/Methods/POST">HTTP POST </a>), ou em associado {{glossary("Cookie", "cookies")}} .</p> + +<p>Os servidores da web esperam por mensagens de solicitação do cliente, processam-nas quando chegam e respondem ao navegador da web com uma mensagem <strong>HTTP response</strong> . A resposta contém uma linha de status indicando se a solicitação foi bem-sucedida ou não (e.g. "HTTP/1.1 200 OK" for success). </p> + +<p dir="ltr" id="tw-target-text">O corpo de uma resposta bem-sucedida a uma solicitação conteria o recurso solicitado (por exemplo, uma nova página HTML ou uma imagem, etc ...), que poderia então ser exibido pelo navegador.</p> + +<h3 id="Sites_estáticos">Sites estáticos</h3> + +<p>O diagrama abaixo mostra uma arquitetura básica de servidor da web para um site estático (um site estático é aquele que retorna o mesmo conteúdo embutido em código do servidor sempre que um determinado recurso é solicitado). Quando um usuário deseja navegar para uma página, o navegador envia uma solicitação HTTP "GET" especificando seu URL.</p> + +<p>O servidor recupera o documento solicitado de seu sistema de arquivos e retorna uma resposta HTTP contendo o documento e um <a href="/en-US/docs/Web/HTTP/Status#Successful_responses">success status</a> (geralmente, 200 OK). Se o arquivo não puder ser recuperado por algum motivo, um status de erro será retornado(Veja <a href="/en-US/docs/Web/HTTP/Status#Client_error_responses">client error responses</a> e <a href="/en-US/docs/Web/HTTP/Status#Server_error_responses">server error responses</a>).</p> + +<p><img alt="A simplified diagram of a static web server." src="https://mdn.mozillademos.org/files/13841/Basic%20Static%20App%20Server.png" style="height: 223px; width: 800px;"></p> + +<h3 id="Sites_dinâmicos">Sites dinâmicos</h3> + +<p>Um site dinâmico é aquele em que parte do conteúdo da resposta é gerado dinamicamente, apenas quando necessário. Em um site dinâmico, as páginas HTML são normalmente criadas inserindo dados de um banco de dados em espaços reservados em modelos HTML (essa é uma maneira muito mais eficiente de armazenar grandes quantidades de conteúdo do que usar sites estáticos). </p> + +<p>Um site dinâmico pode retornar dados diferentes para um URL com base nas informações fornecidas pelo usuário ou preferências armazenadas e pode realizar outras operações como parte do retorno de uma resposta (e.g. enviando notificações).</p> + +<p>A maior parte do código para oferecer suporte a um site dinâmico deve ser executado no servidor. A criação desse código é denominado "<strong>server-side programming</strong>" (ou às vezes "<strong>back-end scripting</strong>").</p> + +<p>O diagrama abaixo mostra uma arquitetura simples para um site dinâmico. Como no diagrama anterior, os navegadores enviam solicitações HTTP para o servidor, então o servidor processa as solicitações e retorna as respostas HTTP apropriadas.</p> + +<p>As solicitações de recursos estáticos são tratadas da mesma maneira que para sites estáticos (recursos estáticos são quaisquer arquivos que não mudam - normalmente: CSS, JavaScript, imagens, arquivos PDF pré-criados etc.).</p> + +<p><img alt="A simplified diagram of a web server that uses server-side programming to get information from a database and construct HTML from templates. This is the same diagram as is in the Client-Server overview." src="https://mdn.mozillademos.org/files/13839/Web%20Application%20with%20HTML%20and%20Steps.png"></p> + +<p>As solicitações de recursos dinâmicos são encaminhadas (2) para o código do lado do servidor (mostrado no diagrama como uma web application). Para "solicitações dinâmicas", o servidor interpreta a solicitação, lê as informações necessárias do banco de dados (3), combina os dados recuperados com modelos HTML (4) e envia de volta uma resposta contendo o HTML gerado (5,6).</p> + +<div> +<h2 id="A_programação_do_lado_do_servidor_e_do_lado_cliente_são_iguais">A programação do lado do servidor e do lado cliente são iguais ?</h2> +</div> + +<p>Vamos agora voltar nossa atenção para o código envolvido na programação do lado do servidor e do lado do cliente. Em cada caso, o código é significativamente diferente:</p> + +<ul> + <li>Eles têm objetivos e propósitos diferentes.</li> + <li>Eles geralmente não usam as mesmas linguagens de programação (exceto JavaScript, que pode ser utilizado tanto no lado do servidor quanto no lado do cliente).</li> + <li>Eles são executados em diferentes ambientes do sistema operacional.</li> +</ul> + +<p>O código em execução no navegador é conhecido como <strong>client-side code </strong>e se preocupa principalmente em melhorar a aparência e o comportamento de uma página da web renderizada. Isso inclui selecionar e definir o estilo dos componentes da IU, criação de layouts, navegação, validação de formulário etc. Por outro lado, a programação do site do lado do servidor envolve principalmente a escolha de qual conteúdo é retornado ao navegador em resposta às solicitações. O código do lado do servidor lida com tarefas como validação de dados e solicitações enviadas, usando bancos de dados para armazenar e recuperar dados e enviar os dados corretos para o cliente conforme necessário.</p> + +<p>O código do lado do cliente é geralmente escrito em <a href="/en-US/docs/Learn/HTML">HTML</a>, <a href="/en-US/docs/Learn/CSS">CSS</a>, e <a href="/en-US/docs/Learn/JavaScript">JavaScript</a> — ele é executado dentro de um navegador da web e tem pouco ou nenhum acesso ao sistema operacional subjacente (incluindo acesso limitado ao sistema de arquivos)</p> + +<p>Os desenvolvedores da Web não podem controlar qual navegador cada usuário pode estar usando para visualizar um site - os navegadores fornecem níveis inconsistentes de compatibilidade com recursos de código do lado do cliente, e parte do desafio da programação do lado do cliente é lidar com as diferenças no suporte do navegador de maneira elegante.</p> + +<p>O código do lado do servidor pode ser escrito algumas linguagens de programação - exemplos de linguagens da web do lado do servidor populares incluem PHP, Python, Ruby, C # e NodeJS (JavaScript). O código do lado do servidor tem acesso total ao sistema operacional do servidor e o desenvolvedor pode escolher qual linguagem de programação (e versão específica) deseja usar.</p> + +<p>Desenvolvedores geralmente escrevem seus códigos utilizando <strong>web frameworks</strong>. Frameworks Web são coleções de funções, objetos, regras e outras construções de código projetadas para resolver problemas comuns, acelerar o desenvolvimento e simplificar os diferentes tipos de tarefas enfrentadas em um domínio específico.</p> + +<p>Novamente, embora o código do lado do cliente e do servidor usem frameworks, os domínios são muito diferentes e, portanto, os frameworks também são. Os frameworks web do lado do cliente simplificam as tarefas de layout e apresentação, enquanto os frameworks web do lado do servidor fornecem muitas funcionalidades de servidor da web "comuns" que você mesmo poderia ter que implementar (por exemplo, suporte para sessões, suporte para usuários e autenticação, fácil acesso ao banco de dados, bibliotecas de modelos, etc.).</p> + +<div class="note"> +<p><strong>Nota </strong>: Os frameworks do lado do cliente costumam ser usados para ajudar a acelerar o desenvolvimento do código do lado do cliente, mas você também pode escolher escrever todo o código manualmente; na verdade, escrever seu código manualmente pode ser mais rápido e eficiente se você precisar apenas de uma IU de site da Web pequena e simples.</p> + +<p>Em contraste, você quase nunca pensaria em escrever o componente do lado do servidor de um web application sem um framework - implementar um recurso vital como um servidor HTTP é realmente difícil de fazer do zero em, digamos, Python, mas frameworks web em Python como Django fornecem essa ferramenta , junto com outras ferramentas muito úteis.</p> +</div> + +<div> +<h2 id="O_que_você_pode_fazer_no_lado_do_servidor">O que você pode fazer no lado do servidor ?</h2> + +<p dir="ltr" id="tw-target-text">A programação do lado do servidor é muito útil porque nos permite fornecer com eficiência informações personalizadas para usuários individuais e, assim, criar uma experiência de usuário muito melhor.</p> +</div> + +<p>Empresas como a Amazon usam programação do lado do servidor para construir resultados de pesquisa de produtos, fazer sugestões de produtos direcionados com base nas preferências do cliente e hábitos de compra anteriores, simplificar as compras, etc.</p> + +<p>Os bancos usam a programação do lado do servidor para armazenar informações de contas e permitir que apenas usuários autorizados visualizem e façam transações. Outros serviços como Facebook, Twitter, Instagram e Wikipedia usam programação do lado do servidor para destacar, compartilhar e controlar o acesso ao conteúdo .</p> + +<p>Alguns dos usos e benefícios comuns da programação do lado do servidor estão listados abaixo. Você notará que há alguma sobreposição!</p> + +<h3 id="Armazenamento_eficiente_e_entrega_de_informações">Armazenamento eficiente e entrega de informações</h3> + +<p>Imagine quantos produtos estão disponíveis na Amazon e quantas postagens foram escritas no Facebook? Criar uma página estática separada para cada produto ou postagem seria completamente impraticável.</p> + +<p>A programação do lado do servidor nos permite, em vez disso, armazenar as informações em um banco de dados e construir e retornar dinamicamente HTML e outros tipos de arquivos (por exemplo, PDFs, imagens, etc.). Também é possível simplesmente retornar dados ({{glossary("JSON")}}, {{glossary("XML")}}, etc.) para renderização por frameworks web do lado do cliente apropriados (isso reduz a carga de processamento em um servidor e a quantidade de dados que precisa ser enviada).</p> + +<p>O servidor não se limita a enviar informações de bancos de dados e pode, alternativamente, retornar o resultado de ferramentas de software ou dados de serviços de comunicação. O conteúdo pode até ser direcionado para o tipo de dispositivo que o cliente está recebendo.</p> + +<p>Como as informações estão em um banco de dados, elas também podem ser mais facilmente compartilhadas e atualizadas com outros sistemas de negócios (por exemplo, quando os produtos são vendidos online ou em uma loja, a loja pode atualizar seu banco de dados de estoque).</p> + +<div class="note"> +<p><strong>Nota </strong>: Sua imaginação não precisa trabalhar muito para ver os benefícios do código do lado do servidor para armazenamento e entrega eficientes de informações:</p> + +<ol> + <li>Vá em <a href="https://www.amazon.com">Amazon</a> ou em outro site comercial.</li> + <li>Pesquise várias palavras-chave e observe como a estrutura da página não muda, embora os resultados mudem.</li> + <li>Abra dois ou três produtos diferentes. Observe novamente como eles têm uma estrutura e layout comuns, mas o conteúdo de diferentes produtos foi retirado do banco de dados.</li> +</ol> + +<p>Para um termo de pesquisa comum ("peixe", digamos), você pode ver literalmente milhões de valores retornados. O uso de um banco de dados permite que sejam armazenados e compartilhados de forma eficiente, além de permitir que a apresentação das informações seja controlada em um só lugar.</p> +</div> + +<h3 id="Experiência_de_usuário_personalizada">Experiência de usuário personalizada</h3> + +<p>Os servidores podem armazenar e usar informações sobre clientes para fornecer uma experiência de usuário conveniente e personalizada. Por exemplo, muitos sites armazenam cartões de crédito para que os detalhes não tenham que ser inseridos novamente. Sites como o Google Maps podem usar locais salvos ou atuais para fornecer informações de rota e pesquisar o histórico de viagens para destacar empresas locais nos resultados de pesquisa.</p> + +<p>Uma análise mais profunda dos hábitos do usuário pode ser usada para antecipar seus interesses e personalizar ainda mais as respostas e notificações, por exemplo, fornecendo uma lista de locais visitados anteriormente ou que você pode querer ver em um mapa.</p> + +<div class="note"> +<p><strong>Nota: </strong><a href="https://maps.google.com/">Google Maps</a> salva sua pesquisa e histórico de visitas. Locais visitados ou pesquisados com frequência são destacados mais do que outros.</p> + +<p>Os resultados de pesquisa do Google são otimizados com base em pesquisas anteriores.</p> + +<ol> + <li> Vá em <a href="https:\\google.com">Google search</a>.</li> + <li> Pesquise por "futeboll".</li> + <li>Agora tente digitar "favorito" na caixa de pesquisa e observe as previsões de pesquisa do preenchimento automático.</li> +</ol> + +<p>Coincidência ? Nada!</p> +</div> + +<h3 id="Acesso_controlado_ao_conteúdo">Acesso controlado ao conteúdo</h3> + +<p>A programação do lado do servidor permite que os sites restrinjam o acesso a usuários autorizados e forneçam apenas as informações que um usuário tem permissão para ver.</p> + +<p>Exemplos do mundo real, incluem :</p> + +<ul> + <li>Redes sociais como o Facebook permitem que os usuários controlem totalmente seus próprios dados, mas apenas permitem que seus amigos os visualizem ou comentem. O usuário determina quem pode ver seus dados e, por extensão, quais dados aparecem em seu feed - a autorização é uma parte central da experiência do usuário!</li> + <li> + <p>O site em que você está agora controla o acesso ao conteúdo: os artigos são visíveis para todos, mas apenas os usuários que efetuaram login podem editá-los. Para tentar fazer isso, clique no botão Editar no topo desta página - se você estiver conectado, será exibida a visualização de edição; se você não estiver logado, será direcionado para a página de inscrição.</p> + </li> +</ul> + +<div class="note"> +<p><strong>Nota </strong>: Considere outros exemplos reais em que o acesso ao conteúdo é controlado. Por exemplo, o que você pode ver se acessar o site online do seu banco? Faça login em sua conta - quais informações adicionais você pode ver e modificar? Quais informações você pode ver que somente o banco pode alterar?</p> +</div> + +<h3 id="Sessão_de_armazenamento_informações_de_estado">Sessão de armazenamento / informações de estado</h3> + +<p>A programação do lado do servidor permite que os desenvolvedores façam uso de sessões - basicamente, um mecanismo que permite a um servidor armazenar informações sobre o usuário atual de um site e enviar diferentes respostas com base nessas informações.</p> + +<p>Isso permite, por exemplo, que um site saiba que um usuário fez login anteriormente e exiba links para seus e-mails ou histórico de pedidos, ou talvez salve o estado de um jogo simples para que o usuário possa ir a um site novamente e continuar onde eles deixaram.</p> + +<div class="note"> +<p><strong>Note</strong>:Visite um site de jornal que tem um modelo de assinatura e abra várias guias (por exemplo, The Age). Continue a visitar o site por algumas horas / dias. Eventualmente, você começará a ser redirecionado para páginas que explicam como se inscrever e não conseguirá acessar os artigos. Essas informações são um exemplo de informações de sessão armazenadas em cookies.</p> +</div> + +<h3 id="Notificações_e_comunicação">Notificações e comunicação</h3> + +<p>Os servidores podem enviar notificações gerais ou específicas do usuário por meio do próprio site ou por e-mail, SMS, mensagens instantâneas, conversas por vídeo ou outros serviços de comunicação.</p> + +<p>Alguns exemplos, incluem :</p> + +<ul> + <li>Facebook e Twitter enviam e-mails e mensagens SMS para notificá-lo de novas comunicações.</li> + <li>A Amazon envia regularmente e-mails de produtos que sugerem produtos semelhantes aos já comprados ou vistos nos quais você possa estar interessado.</li> + <li>Um servidor da web pode enviar mensagens de aviso aos administradores do site alertando-os sobre a memória insuficiente no servidor ou atividade suspeita do usuário.</li> +</ul> + +<div class="note"> +<p><strong>Nota</strong>: O tipo mais comum de notificação é uma "confirmação de registro". Escolha quase todos os grandes sites de seu interesse (Google, Amazon, Instagram, etc.) e crie uma nova conta usando seu endereço de e-mail. Em breve, você receberá um e-mail confirmando seu registro ou solicitando confirmação para ativar sua conta.</p> +</div> + +<h3 id="Análise_de_dados">Análise de dados</h3> + +<p>Um site pode coletar muitos dados sobre os usuários: o que procuram, o que compram, o que recomendam, quanto tempo permanecem em cada página. A programação do lado do servidor pode ser usada para refinar as respostas com base na análise desses dados.</p> + +<p>Por exemplo, Amazon e Google anunciam produtos com base em pesquisas anteriores (e compras).</p> + +<div class="note"> +<p><strong>Nota</strong>:Se você é um usuário do Facebook, vá para o seu feed principal e veja o fluxo de postagens. Observe como algumas das postagens estão fora da ordem numérica - em particular, as postagens com mais "curtidas" geralmente estão no topo da lista do que as postagens mais recentes.</p> + +<p>Observe também que tipo de anúncio está sendo mostrado - você pode ver anúncios de coisas que já viu em outros sites. O algoritmo do Facebook para destacar conteúdo e publicidade pode ser um pouco misterioso, mas é claro que depende de seus gostos e hábitos de visualização!</p> +</div> + +<h2 id="Resumo">Resumo</h2> + +<p>Parabéns, você chegou ao final do primeiro artigo sobre programação do lado do servidor.</p> + +<p>Agora você aprendeu que o código do lado do servidor é executado em um servidor da web e que sua função principal é controlar quais informações são enviadas ao usuário (enquanto o código do lado do cliente lida principalmente com a estrutura e apresentação desses dados para o usuário) .</p> + +<p>Você também deve entender que é útil porque nos permite criar sites que fornecem informações sob medida para usuários individuais de forma eficiente e têm uma boa ideia de algumas das coisas que você pode fazer quando for um programador do lado do servidor.</p> + +<p>Por último, você deve entender que o código do lado do servidor pode ser escrito em várias linguagens de programação e que você deve usar um framewoek web para tornar todo o processo mais fácil.</p> + +<p>Em um artigo futuro, ajudaremos você a escolher o melhor framework web para seu primeiro site. Aqui, vamos levá-lo pelas principais interações cliente-servidor com um pouco mais de detalhes.</p> + +<p>{{NextMenu("Learn/Server-side/First_steps/Client-Server_overview", "Learn/Server-side/First_steps")}}</p> + +<h2 id="Nesse_módulo">Nesse módulo</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/First_steps/Introduction">Introduction to the server side</a></li> + <li><a href="/en-US/docs/Learn/Server-side/First_steps/Client-Server_overview">Client-Server overview</a></li> + <li><a href="/en-US/docs/Learn/Server-side/First_steps/Web_frameworks">Server-side web frameworks</a></li> + <li><a href="/en-US/docs/Learn/Server-side/First_steps/Website_security">Website security</a></li> +</ul> diff --git a/files/pt-br/learn/server-side/first_steps/seguranca_site/index.html b/files/pt-br/learn/server-side/first_steps/seguranca_site/index.html new file mode 100644 index 0000000000..12a11cf641 --- /dev/null +++ b/files/pt-br/learn/server-side/first_steps/seguranca_site/index.html @@ -0,0 +1,175 @@ +--- +title: Segurança em aplicação web +slug: Learn/Server-side/First_steps/Seguranca_site +tags: + - Aprendizagem + - Guía + - Iniciante + - Introdução + - Programação do server + - Segurança + - Segurança em aplicações web + - Segurança web +translation_of: Learn/Server-side/First_steps/Website_security +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenu("Learn/Server-side/First_steps/Web_frameworks", "Learn/Server-side/First_steps")}}</div> + +<p class="summary">A segurança do site requer vigilância em todos os aspectos do design e uso do site. Este artigo introdutório não fará de você um guru da segurança de sites, mas ajudará a entender de onde vem as ameaças e o que você pode fazer para proteger sua aplicação web contra os ataques mais comuns.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Pré-requisitos:</th> + <td>Conhecimento básico em informática.</td> + </tr> + <tr> + <th scope="row">Objetivo:</th> + <td>Entender as ameaças mais comuns à segurança de aplicações web e o que você pode fazer para reduzir o risco de invasão do site.</td> + </tr> + </tbody> +</table> + +<h2 id="O_que_é_segurança_no_site">O que é segurança no site?</h2> + +<p>A Internet é um lugar perigoso! Com grande regularidade, ouvimos sobre a indisponibilidade de sites devido a ataques de negação de serviço ou a exibição de informações modificadas (e muitas vezes prejudiciais) em suas páginas iniciais. Em outros casos de alto perfil, milhões de senhas, endereços de email e detalhes de cartão de crédito foram vazados para o domínio público, expondo os usuários do site a vergonha pessoal e risco financeiro.</p> + +<p>O objetivo da segurança do site é impedir esse (ou qualquer) tipo de ataque. A definição mais formal de segurança do site é o ato ou prática de proteger sites contra acesso, uso, modificação, destruição ou interrupção não autorizados.</p> + +<p>A segurança efetiva do site requer um esforço de design em todo o site: em sua aplicação web, na configuração do servidor da web, em suas políticas para criar e renovar senhas e no código do cliente. Embora tudo isso pareça muito ameaçador, a boa notícia é que, se você estiver usando <em>framework </em>(uma estrutura da web) no servidor, é provável que ele habilitará "por padrão" mecanismos de defesa robustos e bem pensados contra vários ataques mais comuns. Outros ataques podem ser mitigados através da configuração do servidor da web, por exemplo, ativando o HTTPS. Por fim, existem ferramentas de scanner de vulnerabilidades disponíveis publicamente que podem ajudá-lo a descobrir se você cometeu algum erro óbvio.</p> + +<p>O restante deste artigo fornece mais detalhes sobre algumas ameaças comuns e algumas das etapas simples que você pode executar para proteger seu site.</p> + +<div class="note"> +<p><strong>Nota</strong>: Este é um tópico introdutório projetado para ajudá-lo a começar a pensar na segurança do site, mas não é exaustivo.</p> +</div> + +<h2 id="Ameaças_à_segurança_do_site">Ameaças à segurança do site</h2> + +<p>Esta seção lista apenas algumas das ameaças mais comuns do site e como elas são mitigadas. Enquanto você lê, observe como as ameaças são mais bem-sucedidas quando a aplicação web confia ou <em>não é paranóico o suficiente</em> sobre os dados provenientes do navegador.</p> + +<h3 id="Cross-Site_Scripting_XSS">Cross-Site Scripting (XSS)</h3> + +<p>XSS é um termo usado para descrever uma classe de ataques que permitem que um invasor injete scripts do lado do cliente <em>através </em>do site nos navegadores de outros usuários. Como o código injetado chega ao navegador a partir do site, o código é <em>confiável </em>e pode fazer coisas como enviar o cookie de autorização do site do usuário ao invasor. Quando o invasor possui o cookie, ele pode fazer login em um site como se fosse o usuário e fazer tudo que o usário pode, como acessar os detalhes do cartão de crédito, ver detalhes do contato ou alterar senhas.</p> + +<div class="note"> +<p><strong>Nota</strong>: As vulnerabilidades XSS têm sido historicamente mais comuns do que qualquer outro tipo de ameaça à segurança.</p> +</div> + +<p>As vulnerabilidades do XSS são divididas em <em>refletidas </em>e <em>persistentes</em>, de acordo como o site retorna os scripts injetados para um navegador.</p> + +<ul> + <li>Uma vulnerabilidade XSS <em>refletida </em>ocorre quando o conteúdo do usuário passado para o servidor é retornado <em>imediatamente </em>e <em>não é modificado</em> para exibição no navegador. Quaisquer scripts no conteúdo original do usuário serão executados quando a nova página for carregada. Por exemplo, considere uma função de pesquisa no site em que os termos de pesquisa são codificados como parâmetros de URL e esses termos são exibidos junto com os resultados. Um invasor pode construir um link de pesquisa que contenha um script malicioso como parâmetro (por exemplo, <code>http://sitedecompra.com?q=produto<script%20src="http://sitedomal.com/trapaca.js"></code>) e enviar por e-mail para outro usuário. Se o usuário alvo clicar nesse "link interessante", o script será executado quando os resultados da pesquisa forem exibidos. Conforme discutido anteriormente, isso fornece ao invasor todas as informações necessárias para entrar no site como usuário alvo, potencialmente fazendo compras como o usuário ou compartilhando suas informações de contato.</li> + <li> Uma vulnerabilidade <em>persistente </em>do XSS ocorre quando o script mal-intencionado é armazenado no site e posteriormente exibido novamente sem modificação para que outros usuários executem sem querer. Por exemplo, um quadro de discussão que aceita comentários que contêm HTML não modificado pode armazenar um script mal-intencionado de um invasor. Quando os comentários são exibidos, o script é executado e pode enviar ao invasor as informações necessárias para acessar a conta do usuário. Esse tipo de ataque é extremamente popular e poderoso, porque o invasor pode até não ter nenhum envolvimento direto com as vítimas.</li> +</ul> + +<p>Embora os dados das solicitações <code>POST</code> ou <code>GET</code> sejam a fonte mais comum de vulnerabilidades XSS, qualquer dado do navegador é potencialmente vulnerável, como dados de cookies renderizados pelo navegador ou arquivos de usuário que são carregados e exibidos.</p> + +<p>A melhor defesa contra as vulnerabilidades do XSS é remover ou desativar qualquer marcação que possa conter instruções para executar o código. Para HTML, isso inclui elementos, como <code><script></code>, <code><object></code>, <code><embed></code> e <code><link></code> .</p> + +<p>O processo de modificação de dados do usuário para que não possa ser usado para executar scripts ou afetar a execução do código do servidor é conhecido como limpeza de entrada. Muitas estruturas da Web limpam automaticamente a entrada do usuário de formulários HTML por padrão.</p> + +<h3 id="Injeção_de_SQL">Injeção de SQL</h3> + +<p>As vulnerabilidades de injeção de SQL permitem que usuários mal-intencionados executem código SQL arbitrário em um banco de dados, permitindo que os dados sejam acessados, modificados ou excluídos, independentemente das permissões do usuário. Um ataque de injeção bem-sucedido pode falsificar identidades, criar novas identidades com direitos de administração, acessar todos os dados no servidor ou destruir/modificar os dados para torná-los inutilizáveis.</p> + +<p>Os tipos de injeção SQL incluem injeção SQL baseada em erro, injeção SQL baseada em erros booleanos e injeção SQL baseada em tempo.</p> + +<p>Esta vulnerabilidade está presente se a entrada do usuário que é passada para uma instrução SQL subjacente puder alterar o significado da instrução. Por exemplo, o código a seguir tem como objetivo listar todos os usuários com um nome específico (<code>nomeUsuario)</code> fornecido a partir de um formulário HTML:</p> + +<pre class="brush: sql">statement = "SELECT * FROM usuarios WHERE name = '" + <strong>nomeUsuario</strong> + "';"</pre> + +<p>Se o usuário especificar um nome real, a instrução funcionará como pretendido. No entanto, um usuário mal-intencionado pode alterar completamente o comportamento dessa instrução SQL para a nova instrução no exemplo a seguir, simplesmente especificando o texto em negrito para o <code>nomeUsuario.</code></p> + +<pre class="brush: sql">SELECT * FROM usuarios WHERE name = '<strong>a';DROP TABLE usuarios; SELECT * FROM userinfo WHERE 't' = 't</strong>'; +</pre> + +<p>A instrução modificada cria uma instrução SQL válida que exclui a tabela de <code>usuarios</code> e seleciona todos os dados da tabela <code>userinfo</code> (que revela as informações de cada usuário). Isso funciona porque a primeira parte do texto injetado ( <code>a';</code>) completa a declaração original.</p> + +<p>Para evitar esse tipo de ataque, você deve garantir que os dados do usuário passados para uma consulta SQL não possam alterar a natureza da consulta. Uma maneira de fazer isso é utilizar '<a href="https://pt.wikipedia.org/wiki/Caractere_de_escape">escape</a>' em todos os caracteres na entrada do usuário que tenham um significado especial no SQL.</p> + +<div class="note"> +<p><strong>Nota</strong>: A instrução SQL trata o caractere <strong>'</strong> como o início e o final de uma cadeia de caracteres literal. Ao colocar uma barra invertida na frente desse caractere (<strong>\'</strong>), "escapamos" do símbolo e dizemos ao SQL para tratá-lo como um caractere (apenas uma parte da string).</p> +</div> + +<p>Na declaração a seguir, escapamos o caractere <strong>'</strong>. O SQL agora interpretará o nome como toda a string em negrito (que é um nome muito estranho, mas não prejudicial).</p> + +<pre class="brush: sql">SELECT * FROM usarios WHERE name = '<strong>a\';DROP TABLE usuarios; SELECT * FROM userinfo WHERE \'t\' = \'t'</strong>; + +</pre> + +<p><em>Frameworks web</em> geralmente cuidam do caractere que está escapando para você. O Django, por exemplo, garante que todos os dados do usuário passados para os conjuntos de consultas (consultas de modelo) sejam escapados.</p> + +<div class="note"> +<p><strong>Nota</strong>: Esta seção baseia-se fortemente nas informações da <a href="https://en.wikipedia.org/wiki/SQL_injection">Wikipedia</a>.</p> +</div> + +<h3 id="Cross-Site_Request_Forgery_CSRF">Cross-Site Request Forgery (CSRF)</h3> + +<p>Os ataques de CSRF permitem que um usuário mal-intencionado execute ações usando as credenciais de outro usuário sem o conhecimento ou consentimento desse usuário.</p> + +<p>Esse tipo de ataque é melhor explicado por exemplo. John é um usuário mal-intencionado que sabe que um site específico permite que usuários conectados enviem dinheiro para uma conta especificada usando uma solicitação HTTP <code>POST</code> que inclui o nome da conta e uma quantia em dinheiro. John cria um formulário que inclui seus dados bancários e uma quantia de dinheiro como campos ocultos e o envia por e-mail a outros usuários do site (com o botão <em>Enviar</em>, disfarçado como um link para um site "fique rico rapidamente").</p> + +<p>Se um usuário clicar no botão enviar, uma solicitação HTTP <code>POST</code> será enviada ao servidor contendo os detalhes da transação e quaisquer cookies do lado do cliente que o navegador associou ao site (adicionar cookies do site associados a solicitações é um comportamento normal do navegador). O servidor irá verificar os cookies e usá-los para determinar se o usuário está ou não conectado e tem permissão para fazer a transação.</p> + +<p>O resultado é que qualquer usuário que clicar no botão <em>Enviar </em>enquanto estiver conectado ao site de negociação fará a transação. John fica rico.</p> + +<div class="note"> +<p><strong>Nota</strong>: O truque aqui é que John não precisa ter acesso aos cookies do usuário (ou credenciais de acesso). O navegador do usuário armazena essas informações e as inclui automaticamente em todas as solicitações ao servidor associado.</p> +</div> + +<p>Uma maneira de impedir esse tipo de ataque é o servidor exigir que as solicitações <code>POST</code> incluam um segredo gerado pelo site específico do usuário. O segredo seria fornecido pelo servidor ao enviar o formulário da web usado para fazer transferências. Essa abordagem impede John de criar seu próprio formulário, uma vez que ele precisaria conhecer o segredo que o servidor está fornecendo ao usuário. Mesmo se descobrisse o segredo e criasse um formulário para um usuário específico, ele não seria mais capaz de usar o mesmo formulário para atacar todos os usuários.</p> + +<p><em>Frameworks web</em> geralmente incluem esses mecanismos de prevenção para CSRF.</p> + +<h3 id="Outras_ameaças">Outras ameaças</h3> + +<p>Outros ataques e vulnerabilidades comuns incluem:</p> + +<ul> + <li><em><a href="https://www.owasp.org/index.php/Clickjacking">Clickjacking</a></em>. Nesse ataque, um usuário mal-intencionado seqüestra cliques destinados a um site de nível superior visível e os direciona para uma página oculta abaixo. Essa técnica pode ser usada, por exemplo, para exibir um site bancário legítimo, mas capturar as credenciais de logon em um invisível controlado pelo invasor. O clickjacking também pode ser usado para fazer com que o usuário clique em um botão em um site visível, mas, ao fazer isso, clique inconscientemente em um botão completamente diferente. Como defesa, seu site pode impedir que ele seja incorporado em um iframe em outro site, definindo os cabeçalhos HTTP apropriados.</li> + <li><a href="https://pt.wikipedia.org/wiki/Ataque_de_nega%C3%A7%C3%A3o_de_servi%C3%A7o">Negação de Serviço</a> (DoS, em inglês). O DoS geralmente é atingido inundando um site de destino com solicitações falsas para que o acesso a um site seja interrompido por usuários legítimos. As solicitações podem ser simplesmente numerosas ou podem consumir grandes quantidades de recursos individualmente (por exemplo, leituras lentas ou upload de arquivos grandes). As defesas de DoS geralmente funcionam identificando e bloqueando o tráfego "ruim" e permitindo a passagem de mensagens legítimas. Essas defesas geralmente estão localizadas antes ou no servidor da web (elas não fazem parte da própria aplicação web).</li> + <li><em><a href="https://en.wikipedia.org/wiki/Directory_traversal_attack">Directory Traversal</a> </em> (arquivo e divulgação). Nesse ataque, um usuário mal-intencionado tenta acessar partes do sistema de arquivos do servidor da web que ele não deve acessar. Essa vulnerabilidade ocorre quando o usuário consegue passar nomes de arquivos que incluem caracteres de navegação do sistema de arquivos (por exemplo, <code>../../</code>). A solução é limpar a entrada antes de usá-la.</li> + <li><a href="/pt-BR/docs/">Inclusão de arquivo</a>. Nesse ataque, um usuário pode especificar um arquivo "não intencional" para exibição ou execução nos dados passados para o servidor. Quando carregado, esse arquivo pode ser executado no servidor da web ou no lado do cliente (levando a um ataque XSS). A solução é limpar a entrada antes de usá-la.</li> + <li><a href="/pt-BR/docs/">Injeção de comando</a>. Os ataques de injeção de comando permitem que um usuário mal-intencionado execute comandos arbitrários do sistema no sistema operacional host. A solução é limpar a entrada do usuário antes que ela possa ser usada nas chamadas do sistema.</li> +</ul> + +<p>Para obter uma lista abrangente das ameaças à segurança do site, consulte <a href="/pt-BR/docs/">Categoria: explorações de segurança da Web </a>(Wikipedia) e <a href="/pt-BR/docs/">Categoria: Ataque</a> (Projeto de Segurança para Aplicações Web Abertos).</p> + +<h2 id="Algumas_mensagens-chave">Algumas mensagens-chave</h2> + +<p>Quase todas as explorações de segurança nas seções anteriores são bem-sucedidas quando a aplicação web confia nos dados do navegador. Tudo o que você fizer para melhorar a segurança do seu site, você deve limpar todos os dados originados pelo usuário antes de serem exibidos no navegador, usados em consultas SQL ou passados para um sistema operacional ou para uma chamada do sistema de arquivos.</p> + +<div class="warning"> +<p>Importante: A lição mais importante que você pode aprender sobre segurança do site é nunca confiar nos dados do navegador. Isso inclui, mas não se limita a dados nos parâmetros de URL de solicitações <code>GET</code>, <code>POST</code>, cabeçalhos HTTP, cookies e arquivos enviados por usuários. Sempre verifique e limpe todos os dados recebidos. Sempre assuma o pior.</p> +</div> + +<p>Uma série de outras etapas concretas que você pode executar são:</p> + +<ul> + <li>Use um gerenciamento de senhas mais eficaz. Incentive senhas fortes que são alteradas regularmente. Considere a autenticação de dois fatores para o seu site, para que, além de uma senha, o usuário insira outro código de autenticação (geralmente um código fornecido com algum hardware físico que somente o usuário terá, como um código em um SMS enviado para seu telefone).</li> + <li>Configure seu servidor da web para usar <a href="/pt-BR/docs/">HTTPS </a>e <a href="/pt-BR/docs/">HTTP Strict Transport Security</a> (HSTS). O HTTPS criptografa os dados enviados entre seu cliente e servidor. Isso garante que credenciais de login, cookies, dados de solicitações <code>POST</code> e informações de cabeçalho não estejam facilmente disponíveis para os invasores.</li> + <li>Acompanhe as ameaças mais populares (<a href="/pt-BR/docs/">a lista atual do OWASP está aqui</a>) e resolva as vulnerabilidades mais comuns primeiro.</li> + <li>Use as <a href="https://www.owasp.org/index.php/Category:Vulnerability_Scanning_Tools">ferramentas de verificação de vulnerabilidades</a> para executar testes de segurança automatizados em seu site. Posteriormente, seu site bem-sucedido também poderá encontrar bugs oferecendo uma recompensa de bugs, <a href="https://www.mozilla.org/en-US/security/bug-bounty/faq-webapp/">como a Mozilla faz aqui</a>.</li> + <li>Armazene e exiba apenas os dados necessários. Por exemplo, se seus usuários precisam armazenar informações confidenciais, como detalhes do cartão de crédito, exiba apenas o número do cartão suficiente para que possa ser identificado pelo usuário e não o suficiente para que possa ser copiado por um invasor e usado em outro site. O padrão mais comum no momento é exibir apenas os últimos 4 dígitos de um número de cartão de crédito.</li> +</ul> + +<p><em>Frameworks web</em> podem ajudar a mitigar muitas das vulnerabilidades mais comuns.</p> + +<h2 id="Resumo">Resumo</h2> + +<p>Este artigo explicou o conceito de segurança na web e algumas das ameaças mais comuns contra as quais o site deve tentar se proteger. Mais importante, você deve entender que uma aplicação web não pode confiar em nenhum dado do navegador. Todos os dados do usuário devem ser limpos antes de serem exibidos ou usados em consultas SQL e chamadas do sistema de arquivos.</p> + +<p>Com este artigo, você chegou ao final <a href="https://wiki.developer.mozilla.org/pt-BR/docs/Learn/Server-side/First_steps">deste módulo</a>, abordando seus primeiros passos na programação de sites em relação ao servidor. Esperamos que você tenha gostado de aprender esses conceitos fundamentais e agora esteja pronto para selecionar um <em>Framework web</em> e iniciar a programação.</p> + +<p>{{PreviousMenu("Learn/Server-side/First_steps/Web_frameworks", "Learn/Server-side/First_steps")}}</p> + +<h2 id="Neste_módulo">Neste módulo</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/First_steps/Introduction">Introduction to the server side</a></li> + <li><a href="/en-US/docs/Learn/Server-side/First_steps/Client-Server_overview">Client-Server overview</a></li> + <li><a href="/en-US/docs/Learn/Server-side/First_steps/Web_frameworks">Server-side web frameworks</a></li> + <li><a href="/en-US/docs/Learn/Server-side/First_steps/Website_security">Website security</a></li> +</ul> diff --git a/files/pt-br/learn/server-side/index.html b/files/pt-br/learn/server-side/index.html new file mode 100644 index 0000000000..2c7759aa89 --- /dev/null +++ b/files/pt-br/learn/server-side/index.html @@ -0,0 +1,52 @@ +--- +title: Programação de site do lado do servidor +slug: Learn/Server-side +tags: + - Beginner + - CodingScripting + - Intro + - Landing + - Learn + - NeedsTranslation + - Server + - Server-side programming + - Topic + - TopicStub +translation_of: Learn/Server-side +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">O tópico de <em><strong>Websites Dinâmicos - Programação do lado do servidor</strong></em> é uma série de módulos que mostram como criar sites dinâmicos; sites que fornecem informações personalizadas em resposta a solicitações HTTP. Os módulos fornecem uma introdução genérica à programação do lado do servidor, juntamente com guias específicos de nível iniciante sobre como usar os frameworks web Django (Python) e Express (Node.js / JavaScript) para criar aplicativos básicos.</p> + +<p>A maioria dos principais sites utilizam algum tipo de tecnologia do lado do servidor para exibir dinamicamente dados diferentes conforme necessário. Por exemplo, imagine quantos produtos estão disponíveis na Amazon e imagine quantos posts foram escritos no Facebook? Exibir tudo isso usando páginas estáticas completamente diferentes seria completamente ineficiente, então, em vez disso, esses sites exibem modelos estáticos (construídos usando <a href="/en-US/docs/Learn/HTML">HTML</a>, <a href="/en-US/docs/Learn/CSS">CSS</a>, e <a href="/en-US/docs/Learn/JavaScript">JavaScript</a>), e então atualizam dinamicamente os dados exibidos dentro desses modelos quando necessário, por exemplo, quando você quiser ver um produto diferente na Amazon.</p> + +<p>No mundo moderno do desenvolvimento web, aprender sobre o desenvolvimento do lado do servidor é altamente recomendado.</p> + +<h2 id="Caminho_de_aprendizagem">Caminho de aprendizagem</h2> + +<p>Começar a usar a programação do lado do servidor geralmente é mais fácil do que com o desenvolvimento do lado do cliente, porque sites dinâmicos tendem a executar muitas operações similares (recuperando dados de um banco de dados e exibindo-os em uma página, validando dados inseridos pelo usuário e salvando-os em um banco de dados, verificando permissões de usuários e registrando usuários, etc.) e são construídos usando estruturas da Web que facilitam essas e outras operações comuns de servidor da Web.</p> + +<p>Um conhecimento básico de conceitos de programação (ou de uma linguagem de programação específica) é útil, mas não essencial. Semelhantemente, a especialização em codificação do lado do cliente não é necessária, mas um conhecimento básico ajudará você a trabalhar melhor com os desenvolvedores criando seu "front end" da Web do lado do cliente.</p> + +<p>Você precisará entender "como a web funciona". Recomendamos que você leia primeiro os seguintes tópicos:</p> + +<ul> + <li><a href="/en-US/docs/Learn/Common_questions/What_is_a_web_server">O que é um servidor web?</a></li> + <li><a href="/en-US/docs/Learn/Common_questions/What_software_do_I_need">Qual software eu preciso para construir um website?</a></li> + <li><a href="/en-US/docs/Learn/Common_questions/Upload_files_to_a_web_server">Como você faz o upload de arquivos para um servidor web?</a></li> +</ul> + +<p>Com essa compreensão básica, você estará pronto para percorrer os módulos desta seção.</p> + +<h2 id="Modulos">Modulos</h2> + +<p>Este tópico contém os seguintes módulos. Você deve começar com o primeiro módulo e depois seguir para um dos módulos seguintes, que mostram como trabalhar com duas linguagens do lado do servidor muito populares usando estruturas da Web apropriadas.</p> + +<dl> + <dt><a href="/en-US/docs/Learn/Server-side/First_steps">Primeiros passos de programação do site do lado do servidor</a></dt> + <dd>Este módulo fornece informações agnósticas sobre a tecnologia do servidor sobre programação de sites do lado do servidor, incluindo respostas a perguntas fundamentais de programação do lado do servidor — "o que é isso", "como ela difere da programação do lado do cliente", e "porque é tão útil" — e uma visão geral de alguns dos mais populares frameworks do lado do servidor e orientações sobre como selecionar o mais adequado para o seu site. Por fim, fornecemos uma seção introdutória sobre segurança do servidor da web.</dd> + <dt><a href="/pt-BR/docs/Learn/Server-side/Django">Framework Web Django (Python)</a></dt> + <dd>O Django é um framework web do lado do servidor extremamente popular e cheio de recursos, escrito em Python. O módulo explica por que o Django é uma estrutura de servidor da Web tão boa, como configurar um ambiente de desenvolvimento e como executar tarefas comuns com ele.</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs">Framework Web Express (Node.js/JavaScript)</a></dt> + <dd>O Express é um framwork web popular, escrito em JavaScript e hospedado no ambiente de tempo de execução node.js. O módulo explica alguns dos principais benefícios dessa estrutura, como configurar seu ambiente de desenvolvimento e como executar tarefas comuns de desenvolvimento e implantação da web.</dd> +</dl> |