From 074785cea106179cb3305637055ab0a009ca74f2 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:42:52 -0500 Subject: initial commit --- .../learn/server-side/django/admin_site/index.html | 364 ++++++++ .../django/ambiente_de_desenvolvimento/index.html | 431 ++++++++++ .../server-side/django/authentication/index.html | 692 +++++++++++++++ .../learn/server-side/django/forms/index.html | 679 +++++++++++++++ .../server-side/django/generic_views/index.html | 617 ++++++++++++++ .../learn/server-side/django/home_page/index.html | 420 +++++++++ .../learn/server-side/django/hospedagem/index.html | 692 +++++++++++++++ files/pt-br/learn/server-side/django/index.html | 75 ++ .../django/introdu\303\247\303\243o/index.html" | 346 ++++++++ .../learn/server-side/django/models/index.html | 459 ++++++++++ .../server-side/django/sess\303\265es/index.html" | 205 +++++ .../server-side/django/skeleton_website/index.html | 393 +++++++++ .../learn/server-side/django/testing/index.html | 944 +++++++++++++++++++++ .../tutorial_website_biblioteca_local/index.html | 98 +++ .../django/web_application_security/index.html | 187 ++++ .../ambiente_de_desenvolvimento/index.html | 387 +++++++++ .../express_nodejs/deployment/index.html | 527 ++++++++++++ .../flow_control_using_async/index.html | 135 +++ .../express_nodejs/displaying_data/index.html | 87 ++ .../learn/server-side/express_nodejs/index.html | 65 ++ .../introdu\303\247\303\243o/index.html" | 519 +++++++++++ .../server-side/express_nodejs/mongoose/index.html | 838 ++++++++++++++++++ .../express_nodejs/skeleton_website/index.html | 509 +++++++++++ .../tutorial_local_library_website/index.html | 93 ++ .../first_steps/client-server_overview/index.html | 333 ++++++++ .../pt-br/learn/server-side/first_steps/index.html | 57 ++ .../introdu\303\247\303\243o/index.html" | 237 ++++++ .../first_steps/seguranca_site/index.html | 175 ++++ files/pt-br/learn/server-side/index.html | 52 ++ 29 files changed, 10616 insertions(+) create mode 100644 files/pt-br/learn/server-side/django/admin_site/index.html create mode 100644 files/pt-br/learn/server-side/django/ambiente_de_desenvolvimento/index.html create mode 100644 files/pt-br/learn/server-side/django/authentication/index.html create mode 100644 files/pt-br/learn/server-side/django/forms/index.html create mode 100644 files/pt-br/learn/server-side/django/generic_views/index.html create mode 100644 files/pt-br/learn/server-side/django/home_page/index.html create mode 100644 files/pt-br/learn/server-side/django/hospedagem/index.html create mode 100644 files/pt-br/learn/server-side/django/index.html create mode 100644 "files/pt-br/learn/server-side/django/introdu\303\247\303\243o/index.html" create mode 100644 files/pt-br/learn/server-side/django/models/index.html create mode 100644 "files/pt-br/learn/server-side/django/sess\303\265es/index.html" create mode 100644 files/pt-br/learn/server-side/django/skeleton_website/index.html create mode 100644 files/pt-br/learn/server-side/django/testing/index.html create mode 100644 files/pt-br/learn/server-side/django/tutorial_website_biblioteca_local/index.html create mode 100644 files/pt-br/learn/server-side/django/web_application_security/index.html create mode 100644 files/pt-br/learn/server-side/express_nodejs/ambiente_de_desenvolvimento/index.html create mode 100644 files/pt-br/learn/server-side/express_nodejs/deployment/index.html create mode 100644 files/pt-br/learn/server-side/express_nodejs/displaying_data/flow_control_using_async/index.html create mode 100644 files/pt-br/learn/server-side/express_nodejs/displaying_data/index.html create mode 100644 files/pt-br/learn/server-side/express_nodejs/index.html create mode 100644 "files/pt-br/learn/server-side/express_nodejs/introdu\303\247\303\243o/index.html" create mode 100644 files/pt-br/learn/server-side/express_nodejs/mongoose/index.html create mode 100644 files/pt-br/learn/server-side/express_nodejs/skeleton_website/index.html create mode 100644 files/pt-br/learn/server-side/express_nodejs/tutorial_local_library_website/index.html create mode 100644 files/pt-br/learn/server-side/first_steps/client-server_overview/index.html create mode 100644 files/pt-br/learn/server-side/first_steps/index.html create mode 100644 "files/pt-br/learn/server-side/first_steps/introdu\303\247\303\243o/index.html" create mode 100644 files/pt-br/learn/server-side/first_steps/seguranca_site/index.html create mode 100644 files/pt-br/learn/server-side/index.html (limited to 'files/pt-br/learn/server-side') 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 +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/Models", "Learn/Server-side/Django/Home_page", "Learn/Server-side/Django")}}
+ +

Agora que criamos modelos para o site da LocalLibrary, 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.

+ + + + + + + + + + + + +
Pré-requisitos:Primeiro complete: Tutorial Django Parte 3: Usando modelos.
Objetivo:Para entender os benefícios e limitações do site de administração do Django, use-o para criar alguns registros para nossos modelos.
+ +

Visão Geral

+ +

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.

+ +

Toda a configuração necessária para incluir o aplicativo admin em seu site foi feita automaticamente quando você criou o esqueleto do projeto (para obter informações sobre as dependências reais necessárias, consulte a documentação do Django aqui). 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.

+ +

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.

+ +

Registrando modelos

+ +

Primeiro, abra o admin.py no aplicativo de catálogo (/locallibrary/catalog/admin.py). Atualmente parece com isso - note que ele já importa django.contrib.admin:

+ +
from django.contrib import admin
+
+# Register your models here.
+
+ +

Registre os modelos copiando o seguinte texto na parte inferior do arquivo. Este código simplesmente importa os modelos e, em seguida, chama admin.site.register para registrar cada um deles.

+ +
from catalog.models import Author, Genre, Book, BookInstance
+
+admin.site.register(Book)
+admin.site.register(Author)
+admin.site.register(Genre)
+admin.site.register(BookInstance)
+
+ +
Nota: Se você aceitou o desafio de criar um modelo para representar a linguagem natural de um livro (consulte o artigo do tutorial de modelos), importe-o e registre-o também!
+ +

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.

+ +

Criando um super usuário

+ +

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 manage.py.

+ +

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.

+ +
python3 manage.py createsuperuser
+
+ +

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:

+ +
python3 manage.py runserver
+
+
+ +

Fazendo o login e usando o site

+ +

Para fazer login no site, abra o URL /admin (e.g. http://127.0.0.1:8000/admin) 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 /admin depois de inserir seus detalhes).

+ +

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.

+ +

Admin Site - Home page

+ +

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 help_text (se houver) correspondem aos valores especificados no modelo.

+ +

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 SALVAR, Salvar e adicionar outro ou Salvar e continuar editando para salvar o registro.

+ +

Admin Site - Book Add

+ +
+

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).

+
+ +

Quando terminar de adicionar livros, clique no link Home no marcador superior para ser levado de volta à página principal do administrador. Então clique no link Books 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 __str__() que especificamos no último artigo.

+ +

Admin Site - List of book objects

+ +

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 ADD BOOK

+ +

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 Delete, HISTORY e VIEW ON SITE (este último botão aparece porque definimos o método get_absolute_url() em nosso modelo).

+ +

Admin Site - Book Edit

+ +

Agora navegue de volta para o Home page (usando o link Home, a trilha de navegação) e, em seguida, Author e listas de Genre — você já deve ter criado a partir de quando adicionou os novos livros, mas fique à vontade para adicionar um pouco mais.

+ +

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 Book a partir de BookInstance — esta é a natureza da ForeignKey field). Navegue de volta para a Página inicial e pressione o botão Adicionar associado para exibir a tela Adicionar instância 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.

+ +

Admin Site - BookInstance Add

+ +

Crie vários desses registros para cada um de seus livros. Defina o status como Disponível para pelo menos alguns registros e Em empréstimo para outros. Se o status não for Disponível, defina também uma data de vencimento futura.

+ +

É isso aí! Agora você aprendeu como configurar e usar o site de administração. Você também criou registros para Book, BookInstance, Genre, e Author que poderemos usar assim que criarmos nossas próprias visualizações e modelos.

+ +

Configuração Avançada

+ +

O Django faz um bom trabalho ao criar um site de administração básico usando as informações dos modelos registrados:

+ + + +

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:

+ + + +

In this section we're going to look at a few changes that will improve the interface for our LocalLibrary, including adding more information to Book and Author model lists, and improving the layout of their edit views. We won't change the Language and Genre model presentation because they only have one field each, so there is no real benefit in doing so!

+ +

You can find a complete reference of all the admin site customisation choices in The Django Admin site (Django Docs).

+ +

Registrando uma classe ModelAdmin

+ +

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.

+ +

Vamos começar com o Author model. Abra admin.py no aplicativo de catálogo (/locallibrary/catalog/admin.py). Comente o seu registro original (prefixo com um #) para o Author model:

+ +
# admin.site.register(Author)
+ +

Agora adicione um novo AuthorAdmin e registre como mostrado abaixo.

+ +
# Define the admin class
+class AuthorAdmin(admin.ModelAdmin):
+    pass
+
+# Register the admin class with the associated model
+admin.site.register(Author, AuthorAdmin)
+
+ +

Agora vamos adicionar as classes ModelAdmin para Book, e BookInstance. Precisamos novamente comentar os registros originais:

+ +
# admin.site.register(Book)
+# admin.site.register(BookInstance)
+ +

Agora, para criar e registrar os novos modelos; para o propósito desta demonstração, vamos usar o @register decorador para registrar os modelos (isso faz exatamente a mesma coisa que admin.site.register() sintaxe):

+ +
# 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
+
+ +

Atualmente todas as nossas classes administrativas estão vazias (veja pass) então o comportamento do administrador não será alterado! Agora podemos estendê-los para definir nosso comportamento administrativo específico do modelo.

+ +

Configure list views

+ +

A LocalLibrary atualmente lista todos os autores usando o nome do objeto gerado a partir do método __str__() 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 list_display para adicionar campos adicionais à vista.

+ +

Substitua seuAuthorAdmin class com o código abaixo. Os nomes de campo a serem exibidos na lista são declarados em uma tupla na ordem requerida, conforme mostrado (esses são os mesmos nomes especificados em seu modelo original).

+ +
class AuthorAdmin(admin.ModelAdmin):
+    list_display = ('last_name', 'first_name', 'date_of_birth', 'date_of_death')
+
+ +

Agora navegue até a lista de autores em seu site. Os campos acima devem agora ser exibidos, assim:

+ +

Admin Site - Improved Author List

+ +

Para o nosso Book model nós vamos adicionalmente exibir o author e genre. O author é uma variável ForeignKey (um-para-um) relacionamento, e assim será representado pelo valor __str__() para o registro associado. Substitua o BookAdmin class com a versão abaixo.

+ +
class BookAdmin(admin.ModelAdmin):
+    list_display = ('title', 'author', 'display_genre')
+
+ +

Infelizmente não podemos especificar diretamente a variável  genre na list_display porque é um ManyToManyField(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 display_genre para obter as informações como uma string (esta é a função que chamamos acima; vamos defini-lo abaixo).

+ +
+

Nota: Obtendo o genre 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 Apagar ao lado de cada item da lista.

+
+ +

Adicione o seguinte código ao seu Book model (models.py). Isso cria uma string a partir dos três primeiros valores da variavel genre (se existirem) e cria um short_description que pode ser usado no site administrativo para esse método.

+ +
    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'
+
+ +

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:

+ +

Admin Site - Improved Book List

+ +

O Genre model (e a Language model, se você definiu um) ambos têm um único campo, portanto, não faz sentido criar um modelo adicional para exibir campos adicionais.

+ +
+

Nota: Vale a pena atualizar oBookInstance 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!

+
+ +

Adicionando list filters

+ +

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 list_filter. Substitua sua atual BookInstanceAdmin class com o fragmento de código abaixo.

+ +
class BookInstanceAdmin(admin.ModelAdmin):
+    list_filter = ('status', 'due_back')
+
+ +

A visualização de lista agora incluirá uma caixa de filtro à direita. Observe como você pode escolher datas e status para filtrar os valores:

+ +

Admin Site - BookInstance List Filters

+ +

Organizando o layout da detail view

+ +

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.

+ +
+

Nota: Os modelos LocalLibrary são relativamente simples, portanto não é necessário alterar o layout; No entanto, faremos algumas alterações, só para mostrar como.

+
+ +

Controlando quais campos são exibidos

+ +

Atualize seu AuthorAdmin class para adicionar a linha fields, como mostrado abaixo (em negrito):

+ +
class AuthorAdmin(admin.ModelAdmin):
+    list_display = ('last_name', 'first_name', 'date_of_birth', 'date_of_death')
+    fields = ['first_name', 'last_name', ('date_of_birth', 'date_of_death')]
+
+ +

O atributo fields 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).

+ +

No seu site, acesse a visualização de detalhes do autor. Agora, ele deve aparecer como mostrado abaixo:

+ +

Admin Site - Improved Author Detail

+ +
+

Nota: você também pode usar o atributo exclude para declarar uma lista de atributos a serem excluídos do formulário (todos os outros atributos no modelo serão exibidos).

+
+ +

Seccionando a detail view

+ +

Você pode adicionar "seções" para agrupar informações de modelo relacionadas dentro do formulário detalhado, usando o atributo fieldsets.

+ +

Na BookInstance model temos informações relacionadas ao que o livro é (i.e. name, imprint, e id) e quando estará disponível (status, due_back). Podemos adicionar estes em diferentes seções, adicionando o texto em negrito para o nosso BookInstanceAdmin class. 

+ +
@admin.register(BookInstance)
+class BookInstanceAdmin(admin.ModelAdmin):
+    list_filter = ('status', 'due_back')
+
+    fieldsets = (
+        (None, {
+            'fields': ('book', 'imprint', 'id')
+        }),
+        ('Availability', {
+            'fields': ('status', 'due_back')
+        }),
+    )
+ +

Cada seção tem seu próprio título (ou None,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.

+ +

Agora, navegue até uma visualização de instância do livro em seu website; o formulário deve aparecer como mostrado abaixo:

+ +

Admin Site - Improved BookInstance Detail with sections

+ +

Edição inline de registros associados

+ +

À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.

+ +

Você pode fazer isso declarando inlines, do tipo TabularInline (horizonal layout) or StackedInline (layout vertical, assim como o layout do modelo padrão). Você pode adicionar ao BookInstance informações inline para o nosso Book detalhe, adicionando as linhas abaixo em negrito perto do seu BookAdmin:

+ +
class BooksInstanceInline(admin.TabularInline):
+    model = BookInstance
+
+@admin.register(Book)
+class BookAdmin(admin.ModelAdmin):
+    list_display = ('title', 'author', 'display_genre')
+    inlines = [BooksInstanceInline]
+
+ +

Agora navegue até uma view pala um Book 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):

+ +

Admin Site - Book with Inlines

+ +

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 TabularInline para maiores informações).

+ +
+

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 Add another Book instance , ou poder listar apenas BookInstances como links não legíveis daqui. A primeira opção pode ser feita configurando atributo extra para 0 no BooksInstanceInline model, tente você mesmo.

+
+ +

Desafie-se

+ +

Aprendemos muito nesta seção, então agora é hora de você tentar algumas coisas.

+ +
    +
  1. Para a listview BookInstance, adicione o código para exibir o livro, o status, a data de devolução e o id (em vez do texto padrão __str__()).
  2. +
  3. Adicione uma listagem inline de itens Book para a lista detalhada de Author usando a mesma abordagem que fizemos para  Book/BookInstance.
  4. +
+ + + +

Resumo

+ +

É 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 views e templates.

+ +

Leitura adicional

+ + + +

{{PreviousMenuNext("Learn/Server-side/Django/Models", "Learn/Server-side/Django/Home_page", "Learn/Server-side/Django")}}

+ +

Neste módulo

+ + 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 +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/Introduction", "Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django")}}
+ +

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.

+ + + + + + + + + + + + +
Pré-requisitos:Saber como usar um teminal / linha de comando. Saber instalar softwares em seu sistema operacional.
Objetivo:Ter uma ambiente de desenvolvimento Django (2.0) operando em seu computador.
+ +

Visão geral do ambiente de desenvolvimento Django

+ +

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 recomendado de instalar o ambiente Django no Ubuntu, macOS e Windows e como testar.

+ +

O que é o ambiente de desenvolvimento Django?

+ +

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

+ +

A principal ferramenta que Django fornece é um conjunto de scripts Python para criar e trabalhar com projetos Django, junto com um simples webserver de desenvolvimento 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.

+ +

Existem outras ferramentas secundárias que fazem parte do ambiente de desenvolvimento que não cobriremos aqui. Isso inclui coisas como um editor de texto ou IDE para edição de código, e uma ferramenta pra gerenciamento do controle de origem de códigos (como o Git) 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.

+ +

Quais são as opções de instalação do Django?

+ +

Django é extremamente flexível em termos de como e onde ele pode ser instalado e configurado. Django pode:

+ + + +

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.

+ +
+

Nota: Outras possíveis opções de instalação são cobertas pela documentação oficial do Django. Nós linkamos os documents adequados abaixo.

+
+ +

Quais sistemas operacionais suportam Django?

+ +

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.

+ +

Neste artigo, iremos fornecer instruções para Windows, macOS a Linux/Unix.

+ +

Qual versão de Python deve ser usada?

+ +

Nós recomendamos que use a mais recente versão disponível — no momento que escrevo é Python 3.7.1.

+ +

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).

+ +
+

Nota: 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).

+
+ +

Onde posso baixar o Django?

+ +

Existem três lugares para fazer o download do Django:

+ + + +

Este artigo mostra a instalação pelo Pypi, pois queremos a última versão estável do Django.

+ +

Qual banco de dados?

+ +

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á problemas em potencial que é melhor evitar).

+ +

Neste artigo (e na maior parte deste módulo) nós usaremos o banco de Dados SQLite, 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.

+ +
+

Nota: 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.

+
+ +

Instalar em todo o sistema ou em um ambiente virtual Python?

+ +

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.

+ +
+

Nota: 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).

+
+ +

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.

+ +

Pensando nisso, desenvolvedores experientes de Python/Django normalmente executam apps Python dentro de um ambiente virtual Python 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!

+ +

Esse módulo assume que você instalou o Django em um ambiente virtual, nós iremos mostrá-lo como fazer isso logo abaixo.

+ +

Instalando Python 3

+ +

Você deve ter Python instalado em seu sistema operacional para usar Django. Se você estiver usando Python 3, também precisará da ferramenta Python Package Indexpip3 — que é usada para administrar (instalar, editar, remover) pacotes/bibliotecas Python usadas por Django e seus outros aplicativos Python.

+ +

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).

+ +
+

Nota: 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 https://www.python.org/downloads/ e instalá-los usando o método específico da plataforma em questão.

+
+ +

Ubuntu 18.04

+ +

Ubuntu Linux 18.04 LTS inclui Python 3.6.6 por padrão. Você pode confirmar isso executando o seguinte comando no Terminal:

+ +
python3 -V
+ Python 3.6.6
+ +

Contudo, o Python Package Index, que você precisará para instalar pacotes para Python 3 (incluindo Django), não está disponível por padrão. Você pode instalar pip3 pelo Terminal usando:

+ +
sudo apt install python3-pip
+
+ +

macOS

+ +

macOS "El Capitan" e outras versões mais recentes não incluem Python 3. Você pode confirmar isto executando os comandos abaixo no Terminal:

+ +
python3 -V
+ -bash: python3: command not found
+ +

Você pode instalar Python 3 (com a ferramenta pip3) facilmente em python.org:

+ +
    +
  1. Baixe o instalador exigido: +
      +
    1. Acesse https://www.python.org/downloads/
    2. +
    3. Selecione o botão Download Python 3.7.1 (o número exato da versão menor pode diferir).
    4. +
    +
  2. +
  3. Localize o arquivo usando o Finder, e clique duplo no arquivo do pacote. Siga os passos da instalação dos prompts.
  4. +
+ +

Agora você pode confirmar se tudo deu certo checando o Python 3 como mostrado abaixo:

+ +
python3 -V
+ Python 3.7.1
+
+ +

Você pode checar se pip3 está instalado listando todos os pacotes disponíveis.

+ +
pip3 list
+ +

Windows 10

+ +

Windows não inclui Python por padrão, mas você pode instalá-lo facilmente (com a ferramenta pip3) em python.org:

+ +
    +
  1. Baixe o instalador exigido: +
      +
    1. Acesse https://www.python.org/downloads/
    2. +
    3. Selecione o botão Download Python 3.7.1 (o número exato da versão menor pode diferir).
    4. +
    +
  2. +
  3. Instale Python com um clique duplo no arquivo baixado e siga a instalação dos prompts.
  4. +
  5. Tenha certeza que a caixa "Add Python to PATH" está checada.
  6. +
+ +

Você pode verificar se o Python 3 foi instalado colocando o seguinte texto no Prompt de Comando

+ +
py -3 -V
+ Python 3.7.1
+
+ +

O instalador do Windows incorpora pip3 (o administrador de pacotes Python) por padrão. Você pode facilmente listar os pacotes instalados com o comando abaixo:

+ +
pip3 list
+
+ +
+

Nota: 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.

+
+ +

Usando Django em um ambiente virtual Python

+ +

As bibliotecas que nós iremos usar para criar nossos ambientes virtuais são virtualenvwrapper (Linux e macOS) e virtualenvwrapper-win (Windows), sendo que ambas usam a ferramenta virtualenv. as bibliotecas criam uma interface consistente para manusear interfaces em todas plataformas;

+ +

Instalando o software de ambiente virtual

+ +

Instalação do ambiente virtual no Ubuntu

+ +

Após instalar Python e pip, você pode instalar virtualenvwrapper (que incluivirtualenv). O guia oficial para a instalação pode ser encontrado aqui, ou siga as instruções abaixo.

+ +

Instale a ferramenta usando pip3:

+ +
sudo pip3 install virtualenvwrapper
+ +

Em seguida, adicione as linhas abaixo no fim de seu arquivo shell startup (este é um arquivo oculto nomeado .bashrc 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.

+ +
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
+
+ +
+

Note: As variáveis VIRTUALENVWRAPPER_PYTHON e VIRTUALENVWRAPPER_VIRTUALENV_ARGS apontam para  a localização em uma instalação normal de Python 3, e source /usr/local/bin/virtualenvwrapper.sh aponta para a localização normal do script virtualenvwrapper.sh Se virtualenv 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).
+
+ Você pode encontrar a localização correta no seu sistema usando os comandos which virtualenvwrapper.sh e which python3.

+
+ +

Recarregue o arquivo de startup executando o seguinte comando no Terminal:

+ +
source ~/.bashrc
+ +

Após executar o comando, você deveria ver scripts como esses:

+ +
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
+
+ +

Agora você pode criar um novo ambiente virtual com o comando mkvirtualenv.

+ +

Instalação do ambiente virtual no macOS

+ +

Instalar virtualenvwrapper no macOS é quase a mesma coisa que instalar no Ubuntu (novamente, você pode seguir as instruções do guia oficial de instalação ou as instruções abaixo).

+ +

Instale virtualenvwrapper (e virtualenv) usando pip como abaixo.

+ +
sudo pip3 install virtualenvwrapper
+ +

Então adicione as seguintes linhas no arquivo de startup do seu shell.

+ +
export WORKON_HOME=$HOME/.virtualenvs
+export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
+export PROJECT_HOME=$HOME/Devel
+source /usr/local/bin/virtualenvwrapper.sh
+ +
+

Note: A variável VIRTUALENVWRAPPER_PYTHON  aponta para uma localização em uma instalação normal de Python 3, e source /usr/local/bin/virtualenvwrapper.sh aponta para a localização comum do script virtualenvwrapper.sh. Se virtualenv 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).

+ +

Por exemplo, uma instalação teste no macOS termina com as seguintes linhas no arquivo de startup:

+ +
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
+ +

Você pode encontrar a localização correta no seu sistema usando os comandos which virtualenvwrapper.sh e which python3.

+
+ +

São as mesmas linhas digitadas no Ubuntu, mas o arquivo de startup é diferente nomeado como .bash_profile, oculto no seu diretório home.

+ +
+

Nota: Se você não acha o arquivo .bash_profile pelo finder, você pode abir pelo terminal usando o nano.

+ +

Os comandos são como esses:

+ +
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.
+
+
+ +

Atualize o arquivo de startup fazendo o seguinte chamado no terminal:

+ +
source ~/.bash_profile
+ +

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 mkvirtualenv.

+ +

Instalação do ambiente virtual no Windows 10

+ +

Instalar virtualenvwrapper-win é ainda mais simples que instalar virtualenvwrapper, 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.

+ +
pip3 install virtualenvwrapper-win
+ +

Agora você pode criar um novo ambiente virtual com o comando mkvirtualenv.

+ +

Criando um ambiente virtual

+ +

Uma vez que você tenha instalado virtualenvwrapper ou virtualenvwrapper-win, trabalhar com ambientes virtuais é bem parecido em todas as plataformas.

+ +

Agora você pode criar um novo ambiente virtual com o comando mkvirtualenv. 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).

+ +
$ 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:~$
+
+ +

Agora que você está em um ambiente virtual, você pode instalar Django e iniciar o desenvolvimento.

+ +
+

Nota: 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.

+
+ +

Usando um ambiente virtual

+ +

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):

+ + + +

Instalando o Django

+ +

Após criar um ambiente virtual e usado o comando workon para ativá-lo, você pode usar pip3 para instalar o Django. 

+ +
pip3 install django
+
+ +

Você pode testar a instalação do Django executando o seguinte comando (isso apenas testa se o Python pode achar o módulo Django):

+ +
# Linux/macOS
+python3 -m django --version
+ 2.1.5
+
+# Windows
+py -3 -m django --version
+ 2.1.5
+
+ +
+

Nota: Se o comando Windows acima não mostrar um módulo django, tente:

+ +
py -m django --version
+ +

No Windows, os scripts Python 3 são iniciados prefixando o comando com py -3, embora isso possa variar de acordo com sua instalação. Tente omitir o modificador -3 se você encontrar algum problema com os comandos. No Linux/macOS, o comando é python3.

+
+ +
+

Importante: O resto deste módulo usa o comando Linux  para chamar o Python 3 (python3). Se você  está usando o Windows, substitua o prefixo por: py -3

+
+ +

Testando sua instalação

+ +

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.

+ +
mkdir django_test
+cd django_test
+
+ +

Agora você pode criar um novo site chamado "mytestsite" usando a ferramenta django-admin. Após criar o site você pode navegar dentro da pasta onde encontrará o script principal para gerenciar projetos, nomeado manage.py.

+ +
django-admin startproject mytestsite
+cd mytestsite
+ +

Nós podemos rodar o web server de desenvolvimento dentro dessa pasta usando o manage.py e o comando runserver, como mostrado.

+ +
$ 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.
+
+ +
+

Nota: Acima foi mostrado o comando em Linux/macOS. Você já pode ignorar o aviso sobre "15 unapplied migration(s)"!

+
+ +

Uma vez que o servidor está operando, você pode acessar o site colocando a seguinte URL no seu navegador local:http://127.0.0.1:8000/. Você deveria ver um site como esse:
+ Django Skeleton App Homepage - Django 2.0

+ + + +

Resumo

+ +

Agora você tem um ambiente de desenvolvimento em Django funcionando em seu computador.

+ +

Na seção Testando sua instalação você viu brevemente como criar um website Django usando django-admin startproject, e executá-lo em seu navegador usando um web server de desenvolvimento (python3 manage.py runserver). No próximo artigo nós iremos expandir esse processo, construindo uma aplicação web simples, mas completa.

+ +

Veja também

+ + + +

{{PreviousMenuNext("Learn/Server-side/Django/Introduction", "Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django")}}

+ +

Neste módulo

+ + 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 +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/Sessions", "Learn/Server-side/Django/Forms", "Learn/Server-side/Django")}}
+ +

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 LocalLibrary website, adicionando páginas de login e logout e páginas específicas do usuário e da equipe para visualizar os livros emprestados.

+ + + + + + + + + + + + +
Pré-requisitos:Conclua todos os tópicos do tutorial anterior, incluindo Django Tutorial Part 7: Sessions framework.
Objetivo:Para entender como configurar e usar a autenticação e permissões de usuário.
+ +

Visão global

+ +

O Django fornece um sistema de autenticação e autorização ("permissão"), construído sobre a estrutura da sessão discutida no tutorial anterior, 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 Users e Groups (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.

+ +
+

Nota: 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).

+
+ +

Neste tutorial, mostraremos como habilitar a autenticação do usuário no diretório LocalLibrary 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.

+ +

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.

+ +

Também mostraremos como criar permissões e verificar o status e as permissões de login nas visualizações e nos modelos.

+ +

Ativando a autenticação

+ +

A autenticação foi ativada automaticamente quando criamos o esqueleto do site (no tutorial 2), para que você não precise fazer mais nada neste momento.

+ +
+

Nota: A configuração necessária foi feita para nós quando criamos o aplicativo usando o comando django-admin startproject. As tabelas de banco de dados para usuários e permissões de modelo foram criadas quando chamamos pela primeira vez python manage.py migrate.

+
+ +

A configuração está definida nas seções INSTALLED_APPS e MIDDLEWARE no settings.py (locallibrary/locallibrary/settings.py), como mostrado abaixo:

+ +
INSTALLED_APPS = [
+    ...
+    'django.contrib.auth',  #Core authentication framework and its default models.
+    'django.contrib.contenttypes',  #Django content type system (allows permissions to be associated with models).
+    ....
+
+MIDDLEWARE = [
+    ...
+    'django.contrib.sessions.middleware.SessionMiddleware',  #Manages sessions across requests
+    ...
+    'django.contrib.auth.middleware.AuthenticationMiddleware',  #Associates users with requests using sessions.
+    ....
+
+ +

Criando usuários e grupos

+ +

Você já criou seu primeiro usuário quando olhamos para o site Django admin no tutorial 4 (este era um superusuário, criado com o comando python manage.py createsuperuser). 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.

+ +
+

Nota: 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).

+ +
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()
+
+
+ +

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.

+ +

Inicie o servidor de desenvolvimento e navegue até o site de administração em seu navegador da web local (http://127.0.0.1:8000/admin/). 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 Autenticação e Autorização, você pode clicar nos links Usuários ou Grupos para ver seus registros existentes.

+ +

Admin site - add groups or users

+ +

Primeiro vamos criar um novo grupo para os membros da nossa biblioteca.

+ +
    +
  1. Clique no botão Adicionar (ao lado de Grupo) para criar um novo grupo; digite o Nome "Library Members" para o grupo.Admin site - add group
  2. +
  3. Não precisamos de permissões para o grupo, então pressione SALVAR (você será direcionado para uma lista de grupos).
  4. +
+ +

Agora vamos criar um usuário:

+ +
    +
  1. Volte para a página inicial do site de administração
  2. +
  3. Clique no botão Adicionar ao lado de Usuários para abrir a caixa de diálogo Adicionar usuário.Admin site - add user pt1
  4. +
  5. Digite um nome de usuário e uma senha/confirmação de senha adequados para o usuário de teste
  6. +
  7. Pressione SALVAR para criar o usuário.
    +
    + 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 nome de usuário 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 Ativo 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).Admin site - add user pt2
  8. +
  9. Na seção Grupos, selecione grupo de Library Members na lista de Grupos disponíveis e pressione a seta para a direita entre as caixas para movê-lo para a caixa Grupos escolhidos.Admin site - add user to group
  10. +
  11. Não precisamos fazer mais nada aqui; basta selecionar SALVAR novamente, para ir para a lista de usuários.
  12. +
+ +

É 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).

+ +
+

Nota: 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!

+
+ +

Configurando suas views de autenticação

+ +

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!

+ +

Nesta seção, mostramos como integrar o sistema padrão no site LocalLibrary e criar os modelos. Vamos colocá-los nos principais URLs do projeto.

+ +
+

Nota: 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.

+
+ +
+

Nota: 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!

+
+ +

URLs do Projeto

+ +

Adicione o seguinte à parte inferior do arquivo urls.py do projeto (locallibrary/locallibrary/urls.py):

+ +
#Add Django site authentication urls (for login, logout, password management)
+urlpatterns += [
+    path('accounts/', include('django.contrib.auth.urls')),
+]
+
+ +

Navegue até URL http://127.0.0.1:8000/accounts/ (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:

+ +
+

Nota: 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.

+ +
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']
+
+ +

Agora tente navegar para o URL de login (http://127.0.0.1:8000/accounts/login/). Isso falhará novamente, mas com um erro informando que estamos perdendo o modelo necessário (registration/login.html) no caminho de pesquisa do modelo. Você verá as seguintes linhas listadas na seção amarela na parte superior:

+ +
Exception Type:    TemplateDoesNotExist
+Exception Value:    registration/login.html
+ +

A próxima etapa é criar um diretório de registro no caminho de pesquisa e adicionar o arquivo login.html.

+ +

Diretório de Templates

+ +

Os URLs (e implicitamente, visualizações) que acabamos de adicionar esperam encontrar seus modelos associados em um diretório /registration/ em algum lugar no caminho de pesquisa de modelos.

+ +

Neste site, colocaremos nossas páginas HTML no diretório templates/registration/. Esse diretório deve estar no diretório raiz do projeto, ou seja, o mesmo diretório que a pasta catalog e locallibrary. Por favor, crie essas pastas agora.

+ +
+

Nota: Sua estrutura de pastas agora deve se parecer como abaixo:
+ locallibrary (Django project folder)
+    |_catalog
+    |_locallibrary
+    |_templates (new)
+                 |_registration

+
+ +

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 (/locallibrary/locallibrary/settings.py) e atualize o seção TEMPLATES linha 'DIRS' como mostrado abaixo.

+ +
TEMPLATES = [
+    {
+        ...
+        'DIRS': [os.path.join(BASE_DIR, 'templates')],
+        'APP_DIRS': True,
+        ...
+
+ +

Template de login

+ +
+

Importante: 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!

+
+ +

Crie um novo arquivo HTML chamado /locallibrary/templates/registration/login.html e forneça o seguinte conteúdo:

+ +
{% 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 %}
+ +

Este modelo compartilha algumas semelhanças com as que já vimos antes - estende nosso modelo base e substitui o bloco content. 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.

+ +

Navegue de volta para a página de login (http://127.0.0.1:8000/accounts/login/). Depois de salvar seu modelo, você verá algo assim:

+ +

Library login page v1

+ +

Se você fizer login usando credenciais válidas, será redirecionado para outra página (por padrão, isso será http://127.0.0.1:8000/accounts/profile/). 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!

+ +

Abra as configurações do projeto (/locallibrary/locallibrary/settings.py) 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.

+ +
# Redirect to home URL after login (Default redirects to /accounts/profile/)
+LOGIN_REDIRECT_URL = '/'
+
+ +

Template de logout

+ +

Se você navegar para o URL de logout (http://127.0.0.1:8000/accounts/logout/) você verá um comportamento estranho - seu usuário será desconectado com certeza, mas será direcionado para a pagina de logout do Admin. 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 is_staff).

+ +

Crie e abra /locallibrary/templates/registration/logged_out.html. Copie o texto abaixo:

+ +
{% extends "base_generic.html" %}
+
+{% block content %}
+  <p>Logged out!</p>
+  <a href="{% url 'login'%}">Click here to login again.</a>
+{% endblock %}
+ +

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:

+ +

Library logout page v1

+ +

Templates para reset de password

+ +

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.

+ +

Os seguintes modelos podem ser usados como ponto de partida.

+ +

Formulário para reset de password

+ +

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 /locallibrary/templates/registration/password_reset_form.html e forneça o seguinte conteúdo:

+ +
{% 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 %}
+
+ +

Password reset done

+ +

Este formulário é exibido após a coleta do seu endereço de email. Crie /locallibrary/templates/registration/password_reset_done.html, e forneça o seguinte conteúdo:

+ +
{% 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 %}
+
+ +

Password reset email

+ +

Este modelo fornece o texto do email em HTML que contém o link de redefinição que enviaremos aos usuários. Crie /locallibrary/templates/registration/password_reset_email.html e forneça o seguinte conteúdo:

+ +
Someone asked for password reset for email \{{ email }}. Follow the link below:
+\{{ protocol}}://\{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
+
+ +

Password reset confirm

+ +

É nesta página que você digita sua nova senha depois de clicar no link no e-mail de redefinição de senha. Crie /locallibrary/templates/registration/password_reset_confirm.html e forneça o seguinte conteúdo:

+ +
{% 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 %}
+
+ +

Password reset complete

+ +

Este é o último modelo de redefinição de senha, exibido para notificá-lo quando a redefinição de senha for bem-sucedida. Crie /locallibrary/templates/registration/password_reset_complete.html e forneça o seguinte conteúdo:

+ +
{% extends "base_generic.html" %}
+
+{% block content %}
+  <h1>The password has been changed!</h1>
+  <p><a href="{% url 'login' %}">log in again?</a></p>
+{% endblock %}
+ +

Testando as novas páginas de autenticação

+ +

Agora que você adicionou a configuração da URL e criou todos esses modelos, as páginas de autenticação agora devem funcionar!

+ +

Você pode testar as novas páginas de autenticação tentando fazer login e sair da sua conta de superusuário usando estes URLs:

+ + + +

Você poderá testar a funcionalidade de redefinição de senha no link na página de login. 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!

+ +
+

Nota: 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).

+ +
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
+
+ +

Para mais informações, veja Sending email (Django docs).

+
+ +

Testando contra usuários autenticados

+ +

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.

+ +

Testando nos templates

+ +

Você pode obter informações sobre o usuário conectado no momento em modelos com a variável de template \{{ user }} (isso é adicionado ao contexto do template por padrão quando você configura o projeto como fizemos em nosso esqueleto).

+ +

Normalmente você primeiro testará contra a variável de template \{{ user.is_authenticated }} 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.

+ +

Abra o template base (/locallibrary/catalog/templates/base_generic.html) e copie o texto a seguir no bloco sidebar, imediatamente antes da template tag endblock.

+ +
  <ul class="sidebar-nav">
+
+    ...
+
+   {% if user.is_authenticated %}
+     <li>User: \{{ user.get_username }}</li>
+     <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>
+ +

Como você pode ver, usamos template tags if-else-endif para exibir condicionalmente o texto com base em \{{ user.is_authenticated }} ser verdadeiro. Se o usuário estiver autenticado, sabemos que temos um usuário válido, por isso chamamos \{{ user.get_username }} para exibir o nome deles.

+ +

Criamos os URLs dos links de logon e logout usando a template tag url e os nomes das respectivas configurações de URL. Observe também como anexamos ?next=\{{request.path}} 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 "next" para redirecionar o usuário de volta à página em que ele clicou pela primeira vez no link de logon/logout.

+ +
+

Nota: 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.

+
+ +

Testando nas views

+ +

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 login_required à 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.(settings.LOGIN_URL), passando o caminho absoluto atual como o next no parametro da URL. Se o usuário conseguir fazer login, ele retornará a esta página, mas desta vez autenticado.

+ +
from django.contrib.auth.decorators import login_required
+
+@login_required
+def my_view(request):
+    ...
+ +
+

Nota: Você pode fazer o mesmo tipo de coisa manualmente testando emrequest.user.is_authenticated, mas o decorator é muito mais conveniente!

+
+ +

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 LoginRequiredMixin. Você precisa declarar esse mixin primeiro na lista de superclasses, antes da classe de visualização principal.

+ +
from django.contrib.auth.mixins import LoginRequiredMixin
+
+class MyView(LoginRequiredMixin, View):
+    ...
+ +

Isso tem exatamente o mesmo comportamento de redirecionamento que o decorator login_required. Você também pode especificar um local alternativo para redirecionar o usuário se ele não estiver autenticado (login_url), e um nome de parâmetro de URL em vez de "next" para inserir o caminho absoluto atual (redirect_field_name).

+ +
class MyView(LoginRequiredMixin, View):
+    login_url = '/login/'
+    redirect_field_name = 'redirect_to'
+
+ +

Para detalhes adicionais, consulte o Django docs here.

+ +

Exemplo - listando os livros do usuário atual

+ +

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.

+ +

Infelizmente, ainda não temos como os usuários emprestarem livros! Portanto, antes que possamos criar a lista de livros, primeiro estenderemos o modelo BookInstance para suportar o conceito de empréstimo e usar o aplicativo Django Admin para emprestar vários livros ao nosso usuário de teste.

+ +

Models

+ +

Primeiro, teremos que possibilitar que os usuários tenham um BookInstance emprestado (já temos um status e uma data due_back, mas ainda não temos nenhuma associação entre esse modelo e um usuário. Vamos criar um usando um campo ForeignKey (one-to-many). Também precisamos de um mecanismo fácil para testar se um livro emprestado está vencido.

+ +

Abra catalog/models.py, e importe o model User de django.contrib.auth.models (adicione isso logo abaixo da linha de importação anterior na parte superior do arquivo, para User estar disponível para o código subsequente que faz uso dele):

+ +
from django.contrib.auth.models import User
+
+ +

Em seguida, adicione o campo borrower para o modelo BookInstance:

+ +
borrower = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
+
+ +

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 property como mostrado abaixo será muito mais eficiente.

+ +

Adicione isso em algum lugar perto da parte superior do arquivo:

+ +
from datetime import date
+ +

Agora adicione a seguinte definição de propriedade a classe BookInstance:

+ +
@property
+def is_overdue(self):
+    if self.due_back and date.today() > self.due_back:
+        return True
+    return False
+ +
+

Nota: Primeiro, verificamos se due_back está vazio antes de fazer uma comparação. Um campo due_back 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!

+
+ +

Agora que atualizamos nossos modelos, precisaremos fazer novas migrações no projeto e aplicá-las:

+ +
python3 manage.py makemigrations
+python3 manage.py migrate
+
+ +

Admin

+ +

Agora abra catalog/admin.py, e adicione o campo borrower para a classe BookInstanceAdmin em ambos os list_display e o fieldsets como mostrado abaixo. Isso tornará o campo visível na seção Admin, permitindo atribuir um User para um BookInstance quando necessário.

+ +
@admin.register(BookInstance)
+class BookInstanceAdmin(admin.ModelAdmin):
+    list_display = ('book', 'status', 'borrower', 'due_back', 'id')
+    list_filter = ('status', 'due_back')
+
+    fieldsets = (
+        (None, {
+            'fields': ('book','imprint', 'id')
+        }),
+        ('Availability', {
+            'fields': ('status', 'due_back','borrower')
+        }),
+    )
+ +

Emprestando alguns livros

+ +

Agora que é possível emprestar livros para um usuário específico, vá e empreste vários BookInstance. Defina o campo borrowed para o usuário de teste, faça o status "On loan", e defina datas de vencimento no futuro e no passado.

+ +
+

Nota: Não detalharemos o processo, pois você já sabe como usar o site Admin!

+
+ +

Na view loan

+ +

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 LoginRequiredMixin, para que apenas um usuário conectado possa chamar essa visualização. Também optaremos por declarar um template_name, em vez de usar o padrão, pois podemos ter algumas listas diferentes de registros BookInstance, com diferentes visualizações e modelos.

+ +

Adicione o seguinte a catalog/views.py:

+ +
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')
+ +

Para restringir nossa consulta apenas ao objeto BookInstance para o usuário atual, reimplementamos get_queryset() como mostrado abaixo. Observe que "o" is the stored code for "on loan" (emprestado) e nós pedimos pela data due_back para que os itens mais antigos sejam exibidos primeiro.

+ +

URL conf para livros on loan (emprestado)

+ +

Agora abra /catalog/urls.py e adicione um path() apontando para a visualização acima (você pode copiar o texto abaixo no final do arquivo).

+ +
urlpatterns += [
+    path('mybooks/', views.LoanedBooksByUserListView.as_view(), name='my-borrowed'),
+]
+ +

Template para livros on loan (emprestado)

+ +

Agora, tudo o que precisamos fazer para esta página é adicionar um modelo. Primeiro, crie o arquivo de modelo /catalog/templates/catalog/bookinstance_list_borrowed_user.html e forneça o seguinte conteúdo:

+ +
{% 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 %}
+ +

Este modelo é muito semelhante ao que criamos anteriormente para os objetos Book e Author. A única coisa "nova" aqui é que verificamos o método que adicionamos no modelo (bookinst.is_overdue) e use-o para alterar a cor dos itens em atraso.

+ +

Quando o servidor de desenvolvimento estiver em execução, agora você poderá visualizar a lista de um usuário conectado no seu navegador em http://127.0.0.1:8000/catalog/mybooks/. Experimente isso com o usuário conectado e desconectado (no segundo caso, você deve ser redirecionado para a página de login).

+ +

Adicione a lista à barra lateral

+ +

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.

+ +

Abra o template base (/locallibrary/catalog/templates/base_generic.html) e adicione a linha em negrito à barra lateral, como mostrado.

+ +
 <ul class="sidebar-nav">
+   {% if user.is_authenticated %}
+   <li>User: \{{ user.get_username }}</li>
+   <li><a href="{% url 'my-borrowed' %}">My Borrowed</a></li>
+   <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>
+
+ +

Com o que se parece?

+ +

Quando qualquer usuário estiver conectado, ele verá o link My Borrowed 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!) .

+ +

Library - borrowed books by user

+ +

Permissões

+ +

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.

+ +

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).

+ +

Models

+ +

A definição de permissões é feita na seção "class Meta" do modelo, usando o campo permissions. 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:

+ +
class BookInstance(models.Model):
+    ...
+    class Meta:
+        ...
+        permissions = (("can_mark_returned", "Set book as returned"),)   
+ +

Poderíamos então atribuir a permissão a um grupo "Librarian" no site do administrador.

+ +

Abra catalog/models.py, e adicione a permissão como mostrado acima. Você ira precisar atualizar seus migrations (execute python3 manage.py makemigrations e python3 manage.py migrate) para atualizar o banco de dados apropriadamente.

+ +

Templates

+ +

As permissões do usuário atual são armazenadas em uma variável de modelo chamada \{{ perms }}. 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. \{{ perms.catalog.can_mark_returned }} será True se o usuário tiver essa permissão, caso contrário,  False. Normalmente testamos a permissão usando a template tag {% if %} como mostrado:

+ +
{% 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 %}
+
+ +

Views

+ +

As permissões podem ser testadas na exibição de funções usando o decorator permission_required ou em uma view baseada em classe usando o PermissionRequiredMixin. 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.

+ +

Função view decorator:

+ +
from django.contrib.auth.decorators import permission_required
+
+@permission_required('catalog.can_mark_returned')
+@permission_required('catalog.can_edit')
+def my_view(request):
+    ...
+ +

Um permission-required mixin para class-based views.

+ +
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!
+ +

Exemplo

+ +

Não atualizaremos a LocalLibrary aqui; talvez no próximo tutorial!

+ +

Desafie-se

+ +

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 todos os livros que foram emprestados e que inclua o nome de cada mutuário.

+ +

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: staff_member_required, variável do template: user.is_staff) mas recomendamos que você use a permissão can_mark_returned e PermissionRequiredMixin, conforme descrito na seção anterior.

+ +
+

Importante: 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.

+
+ +

Quando terminar, sua página será semelhante à captura de tela abaixo.

+ +

All borrowed books, restricted to librarian

+ + + +

Resumo

+ +

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.

+ +

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.

+ +

Veja também

+ + + +

{{PreviousMenuNext("Learn/Server-side/Django/Sessions", "Learn/Server-side/Django/Forms", "Learn/Server-side/Django")}}

+ +

Neste módulo

+ + 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 +--- +
 {{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/authentication_and_sessions", "Learn/Server-side/Django/Testing", "Learn/Server-side/Django")}}
+ +

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 BibliotecaLocal 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.

+ + + + + + + + + + + + +
Pré-requisitos:Completar todos os tópicos anteriores deste tutorial, incluindo Django Tutorial Parte 8: Autenticação e Permissões de Usuário.
Objetivo: +

Entender como programar formulários para obter informações dos usuários e atualizar a base de dados. Entender como as views genéricas de edição de formulários baseadas em classes podem simplificar a criação de formulários para trabalhar com um único model.

+
+ +

Visão Geral

+ +

Um Formulário HTML é um grupo de um ou mais campos/widgets 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á widgets 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 POST com proteção contra ataques maliciosos CSRF (Cross-Site Request Forgery - em inglês, falsificação de solicitação entre sites).

+ +

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 Livros, incluindo algumas listas de seleção e editores de texto.

+ +

Admin Site - Book Add

+ +

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 Django Forms 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.

+ +

Neste tutorial, vamos te mostrar alguns dos métodos para se criar e trabalhar com formulários e, em particular, como as views genéricas de edição de formulários podem reduzir significativamente o seu trabalho ao criar formulários para manipular seus models. Ao longo do caminho, vamos estender nossa aplicação LocalLibrary 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).

+ +

Formulários HTML

+ +

Antes de mais nada, um breve resumo de Formulários HTML. Considere um formulário HTML simples, com um único campo de texto para entrada do nome de uma "equipe", e sua respectiva legenda:

+ +

Simple name field example in HTML form

+ +

O formulário é definido no HTML como uma coleção de elementos dentro das tags <form>...</form>, contendo ao menos um elemento input do tipo type="submit".

+ +
<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>
+ +

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 type de um campo define que tipo de widget será exibido. O name e o id de cada campo são utilizados para identificá-lo no JavaScript/CSS/HTML, enquanto value define o valor preenchido inicialmente no campo quando ele é exibido pela primeira vez. A legenda da equipe é especificada usando a tag label (veja "Enter name" na imagem acima), com um atributo for contendo o valor de id do input a ele associado.

+ +

A entrada submit 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 team_name). Os atributos do formulário definem o método HTTP (method) utilizado para enviar os dados e o destino para esses dados no servidor (action):

+ + + +

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.

+ +

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!

+ +

Processo de manipulação de formulários Django

+ +

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 contexto 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.

+ +

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).

+ +

Updated form handling process doc.

+ +

Com base no diagrama acima, as principais coisas que o manuseio de formulários do Django faz são:

+ +
    +
  1. Exiba o formulário padrão na primeira vez em que for solicitado pelo usuário +
      +
    • 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).
    • +
    • O formulário é referido como unbound neste momento, porque não está associado a nenhum dado inserido pelo usuário (embora possa ter valores iniciais).
    • +
    +
  2. +
  3. Receba dados de uma solicitação de envio e vincule-os ao formulário. +
      +
    • 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.
    • +
    +
  4. +
  5. Limpe e valide os dados. +
      +
    • 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.
    • +
    • 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.)
    • +
    +
  6. +
  7. 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.
  8. +
  9. 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.)
  10. +
  11. Quando todas as ações estiverem concluídas, redirecione o usuário para outra página.
  12. +
+ +

O Django fornece várias ferramentas e abordagens para ajudá-lo nas tarefas detalhadas acima. O mais fundamental é a classe Form, 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.

+ +
+

Nota: Entendendo como Form é usado para ajudá-lo quando discutirmos as classes de estrutura de formulário mais "de alto nível" do Django.

+
+ +

Renew-book form usando uma function view

+ +

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 BookInstance.due_back.

+ +

O exemplo usará uma function-based view e uma classe Form. As seções a seguir explicam como os formulários funcionam e as alterações que você precisa fazer em nosso projeto LocalLibrary.

+ +

Form

+ +

A classe Form é 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).

+ +

Declarando um Form

+ +

A sintaxe da declaração para um Form é muito semelhante ao da declaração de um Model, 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.

+ +

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 locallibrary/catalog/forms.py. Para criar um Form, nós importamos a biblioteca forms, deriva da classe Form, 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:

+ +
from django import forms
+
+class RenewBookForm(forms.Form):
+    renewal_date = forms.DateField(help_text="Enter a date between now and 4 weeks (default 3).")
+
+ +

Campos do Form

+ +

Nesse caso, temos um único DateField para inserir a data de renovação que será renderizada em HTML com um valor em branco, o valor padrão da label "Renewal date:", e algum texto de ajuda: "Enter a date between now and 4 weeks (default 3 weeks)." Como nenhum dos outros argumentos opcionais é especificado, o campo aceita datas usando o input_formats: 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 widget: DateInput.

+ +

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: BooleanField, CharField, ChoiceField, TypedChoiceField, DateField, DateTimeField, DecimalField, DurationField, EmailField, FileField, FilePathField, FloatField, ImageField, IntegerField, GenericIPAddressField, MultipleChoiceField, TypedMultipleChoiceField, NullBooleanField, RegexField, SlugField, TimeField, URLField, UUIDField, ComboField, MultiValueField, SplitDateTimeField, ModelMultipleChoiceField, ModelChoiceField.

+ +

Os argumentos comuns à maioria dos campos estão listados abaixo (estes têm valores padrão sensíveis):

+ + + +

Validação

+ +

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 clean_<fieldname>() para o campo que você deseja verificar. Por exemplo, podemos validar esse valor inserido renewal_date daqui a quatro semanas, implementando clean_renewal_date() como mostrado abaixo.

+ +

Atualize seu arquivo forms.py para ficar assim:

+ +
import datetime
+
+from django import forms
+from django.core.exceptions import ValidationError
+from django.utils.translation import ugettext_lazy as _
+
+class RenewBookForm(forms.Form):
+    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 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
+ +

Há duas coisas importantes a serem observados. A primeira é que temos nossos dados usando self.cleaned_data['renewal_date'] 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 datetime.datetime).

+ +

O segundo ponto é que, se um valor cai fora da nossa gama que levanta um ValidationError, 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 Django's translation functions ugettext_lazy() (importado como _()), que é uma boa prática se você quiser traduzir o seu site mais tarde.

+ +
+

Nota: Existem muitos outros exemplos e métodos para validar os forms Form e field validation (Django docs). Por exemplo, nos casos em que você tem vários campos que dependem uns dos outros, você pode substituir a função Form.clean() e novamente levantar uma ValidationError.

+
+ +

Isso é tudo que necessitamos para o form neste exemplo?

+ +

Configuração da URL

+ +

Antes de criar nossa view, vamos adicionar a configuração da URL para a pagina renew-books. Copie a seguinte configuração para o final do aquivo locallibrary/catalog/urls.py.

+ +
urlpatterns += [
+    path('book/<uuid:pk>/renew/', views.renew_book_librarian, name='renew-book-librarian'),
+]
+ +

A configuração da URL irá redirecionar as URLs com o formato /catalog/book/<bookinstance id>/renew/ para a função chamada renew_book_librarian() em views.py, e enviar o id  BookInstance como parâmetro nomeado pk. O padrão corresponde apenas se pk estiver com a formatação uuid correta.

+ +
+

Nota: Podemos citar nos nossos dados capturados na URL "pk" 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 pk para "chave primária", é uma convenção razoável para uso!

+
+ +

View

+ +

Como discutido no processo de manipulação de formulários Django 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.

+ +

Para forms que usam uma solicitação POST para enviar informações para o servidor, o padrão mais comum para a view é testar se o tipo de solicitação é POST (if request.method == 'POST':) para identificar requisições válidas de formulário e GET (usando uma condição else) para identificar a requisição de criação do form inicial. Se você deseja enviar seus dados usando uma reuquisição GET 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).

+ +

O processo de renovação de livros será gravado em nosso banco de dados, portanto, por convenção, usamos a abordagem de requisição POST. O fragmento de código abaixo mostra o padrão (bem padrão) para esse tipo de exibição de função.

+ +
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
+    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)
+ +

Primeiro, importamos nosso formulário (RenewBookForm) e outros objetos/métodos úteis usados no corpo da função view:

+ + + +

Na view, primeiro usamos o argumento pk em get_object_or_404() para obter o BookInstance atual (se isso não existir, a view será imediatamente encerrada e a página exibirá um erro "não encontrada"). Se essa não for uma solicitação POST (manipulada pela cláusula else) criamos o formulário padrão passando o valor initial para o campo renewal_date (como mostrado abaixo em negrito, isso é, 3 semanas a partir da data atual). 

+ +
    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(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)
+ +

Depois de criar o form, chamamos render() para criar a página HTML, especificando o template e o context que contém o nosso form. Nesse caso, o context também contem nosso BookInstance, que usaremos no template para fornecer informações sobre o livro que estamos renovando.

+ +

No entenato, se essa for uma solicitação POST , criamos nosso objeto form e prenchemos com dados da requisição. Esse processo é chamado "binding" 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 clean_renewal_date() do nosso formulário para verificar se a data está na faixa certa. 

+ +
    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') )
+
+    context = {
+        'form': form,
+        'book_instance': book_instance,
+    }
+
+    return render(request, 'catalog/book_renew_librarian.html', context)
+ +

Se o formulário não é válido, chamamos render() novamente, mas dessa vez o valor passado de form no context incluirá mensagens de erro. 

+ +

Se o formulário é válido, então podemos começar a utilizar os dados, acessando-o por meio do atributoform.cleaned_data (Ex. data = form.cleaned_data['renewal_date']). Aqui, apenas salvamos os dados no atributo due_back do objeto BookInstance associado.

+ +
+

Importante: Embora você também possa acessar os dados do formulário diretamente por meio do request (por exemplo, request.POST['renewal_date'] ou request.GET['renewal_date'] se utilizando requisição GET), isso NÃO é recomendado. O dado limpo é "higienizado", validado, e convertido em tipo compatível com Python.

+
+ +

A estapa final da manipulação de formulário na parte da view é redirecionar para outra página, geralmente uma página de "êxito". Nesse caso, usamos  HttpResponseRedirect e reverse() para redirecionar para a view chamada 'all-borrowed' (isso foi criado como desafio em Tutorial Django Parte 8: Autenticação de usuário e permissões). Se você não criou está página considere redirecionar para a página principal na URL '/').

+ +

Isso é tudo que é necessário para a manipulação do formulario, mas ainda precisamo restringir o acesso a view aos bibliotecários. Provavelmente devemos criar uma nova permissão em BookInstance ("can_renew"), mas, para simplificar as coisa aqui, apenas usamos o decorator da função@permission_required com nossa permissão existente  can_mark_returned.

+ +

A view final, é portanto, como mostrado abaixo. Por favor, copie isso na parte inferior de locallibrary/catalog/views.py.

+ +
import datetime
+
+from django.contrib.auth.decorators import permission_required
+from django.shortcuts import get_object_or_404
+from django.http import HttpResponseRedirect
+from django.urls import reverse
+
+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):
+        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)
+
+ +

O template

+ +

Crie o template mencionado na view (/catalog/templates/catalog/book_renew_librarian.html) e copie o código abaixo nele:

+ +
{% 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>
+
+  <form action="" method="post">
+    {% csrf_token %}
+    <table>
+    \{{ form.as_table }}
+    </table>
+    <input type="submit" value="Submit">
+  </form>
+{% endblock %}
+ +

A maior parte disso será totalmente familiar dos tutoriais anteriores. Estendemos o template base e então redefinimos o bloco content. Somos capazes de referenciar  \{{ book_instance }} (e suas variáveis) porque foi passado no objeto context na função render(), e nós as usamos para listar o título do livro, tomador do empréstimo, e a data de devolução original.

+ +

O código do formulário é relativamente simples. Primeiro, declaramos a tag form, especificando onde o formulário deve ser submetido (action) e o method para submeter os dados (nesse caso, um "HTTP POST") — se você lembrar da visão geral de Formulários HTML na parte superior da página, uma action 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 submit, que um usuário pode apertar para submeter os dados. O {% csrf_token %} adicionado apenas dentro das tags do formulário é parte da proteção de falsificação ente sites (cross-site forgery protection) do  Django.

+ +
+

Nota: Adicione o {% csrf_token %} para todos os templates Django que você cria que utiliza POST para submeter dados. Isso reduzirá a chance de que os formulários sejam invadidos por usuários maliciosos.

+
+ +

Tudo que resta é  a variável \{{ form }} do template, que passamos para o template no dicionário context. Talvez, sem supresa, quando usado como mostrado, isto fornece a renderização padrão de todos os campos do formulário, incluindo seus labels, widgets e texto de ajuda —  a renderização é como mostrado abaixo:

+ +
<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>
+
+ +
+

Nota: 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 template \{{ form.as_table }}.

+
+ +

Se você fosse inserir uama data inválida, você também obteria uma lista dos erros renderizados na página (mostrado em negrito abaixo).

+ +
<tr>
+  <th><label for="id_renewal_date">Renewal date:</label></th>
+    <td>
+      <ul class="errorlist">
+        <li>Invalid date - renewal in past</li>
+      </ul>
+      <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>
+ +

Outras maneiras de usar variável de formulário de template

+ +

Usando \{{ form.as_table }} como mostrado acima, cada campo é renderizado como uma linha da tabela. Você também pode renderizar cada campo como um item da lista (usando \{{ form.as_ul }} ) como um parágrafo (usando \{{ form.as_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 renewal_date:

+ + + +

Para mais exemplos de como renderizar formulários manualmente em templates e fazer loop nos campos de templates, veja Trabalhando com formulários > Renderizando campos manualmente (Django docs).

+ +

Testando a página

+ +

Se você aceitou o "desafio" em Tutorial Django Parte 8: Autenticação de usuário e permissões você terá uma lista de todos os livros emprestados na biblioteca, que é visível apenas aos funcionários da biblioteca. Podemos adicionar um link para nossa página de renovação ao lado de cada item, usando o código de modelo abaixo.

+ +
{% if perms.catalog.can_mark_returned %}- <a href="{% url 'renew-book-librarian' bookinst.id %}">Renew</a>  {% endif %}
+ +
+

Nota: Lembre que seu login de teste precisará ter a permissão  "catalog.can_mark_returned" para acessar a página de renovação de livro (talvez use sua conta de superusuário).

+
+ +

Você pode, alternativamente, construir manualmente uma URL de teste como esta — http://127.0.0.1:8000/catalog/book/<bookinstance_id>/renew/ (um id válido de bookinstance pode ser obtido navegando para a página de detalhes de um livro em sua biblioteca, e copiando o campoid).

+ +

Com o que se parece?

+ +

Se você tiver sucesso, o formulário padrão será semelhante a este:

+ +

+ +

O formulário com um valor inválido inserido terá a seguinte aparência:

+ +

+ +

A lista de todos os livros com o link de renovação será assim:

+ +

+ +

ModelForms

+ +

Criar uma classeForm 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.

+ +

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 ModelForm para criar o formulário a partir do seu modelo. Esse ModelForm pode ser usado em suas views exatamente da mesma maneira como um Form comum.

+ +

Uma ModelForm contém o mesmo campo que nossa RenewBookForm original, como mostrado abaixo. Tudo que você precisa fazer para criar o formulário é adicionar class Meta com o model (BookInstance) associado e uma lista dos fields do modelo a serem incluídos no formulário (você pode incluir todos os campos usando fields = '__all__', ou pode usar exclude (em vez de fields) para especificar os campos do modelo a não incluir).

+ +
from django.forms import ModelForm
+
+from catalog.models import BookInstance
+
+class RenewBookModelForm(ModelForm):
+    class Meta:
+        model = BookInstance
+        fields = ['due_back']
+
+ +
+

Nota: Isso pode não parecer muito mais simples do que apenas usar um Form (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!

+
+ +

O restante das informações vem das definições de campo do modelo (ex. rótulos, widgets, texdo de ajuda, mensagens de erro). Se isso não for suficiente, então podemos substituí-los em nossa class Meta, 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 "Renewal date" (em vez do padrão baseado no padrão com base no nome do campo: Due Back), e também queremos que nosso campo de ajuda seja específico para esse caso de uso. A Meta abaixo mostra como substituir esses campos, e você pode definir widgets and error_messages da mesma forma, se os padrões não forem suficientes.

+ +
class Meta:
+    model = BookInstance
+    fields = ['due_back']
+    labels = {'due_back': _('New renewal date')}
+    help_texts = {'due_back': _('Enter a date between now and 4 weeks (default 3).')} 
+
+ +

Para adicionar validação você pode usar  a mesma abordagem como uma Form normal — você define uma função chamada clean_field_name() e raise a exceção ValidationError para valores inválidos. A única diferença em relação ao nosso form original é que o campo do modelo é chamdo due_back e não "renewal_date". Essa mudança é necessária pois o campo correspondente em BookInstance é chamado due_back

+ +
from django.forms import ModelForm
+
+from catalog.models import BookInstance
+
+class RenewBookModelForm(ModelForm):
+    def clean_due_back(self):
+       data = self.cleaned_data['due_back']
+
+       # 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
+
+    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).')}
+
+ +

A classe RenewBookModelForm acima agora é funcionalmente equivalente a nossa original RenewBookForm. Você poderia importar e usar onde quer que você use RenewBookForm desde que você também atualize o nome da variável do formulário correspondente de renewal_date para due_back como na segunda declaração do formulário: RenewBookModelForm(initial={'due_back': proposed_renewal_date}.

+ +

Views genéricas de edição

+ +

O algoritmo de manipulação de formulários que usamos em nosso exemplo de função view acima, representa um padrão extremamente comum nas views de edição de formulário. Django abstrai grande parte desse "boilerplate" (trabalho repetitivo) para você, criando views genéricas de edição 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 ModelForm) a partir do modelo.

+ +
+

Nota: Além das views de edição descritas aqui, há também uma classe FormView, que fica em algum lugar entre nossa função view e outra view genérica em termos de "flexibilidade" vs "esforço de codificação". Usando FormView, você ainda precisa criar seu Form, 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.

+
+ +

Nessa seção vamos usar views genericas de edição para criar páginas para adicionar funcionalidades para criar, editar e excluir registros de Author da nossa biblioteca — fornecendo efetivamente uma reimplementação básica de parte do site Admin (isso poderá ser útil se você precisa oferecer funcionalidades de administrador de uma maneira mais flexível que possa ser fornecida pelo dite Admin).

+ +

Views

+ +

Abra o arquivo das views (locallibrary/catalog/views.py) e acrescente o seguinte bloco de código na parte inferior:

+ +
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')
+ +

Como você pode ver, para criar, atualizar e excluir as views, você precisa derivar de CreateView, UpdateView, e DeleteView (respectivamente) e então definir o modelo associado.

+ +

Para os casos "criar" e "atualizar" você também precisa especificar os campos para mostrar no formulário (usando a mesma sintaxe que para ModelForm). Nesse caso, nós mostramos ambas as sintaxes para mostrar todos ("all") 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 views 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 success_url (como feito na classe AuthorDelete).

+ +

A classe AuthorDelete  não precisa mostrar nenhum dos campos, então eles não precisam ser especificados. No entanto, você precisa especificar a  success_url, porque  não há um valor padrão óbvio para o Django usar. Nesse caso, usamos a função reverse_lazy() para redirecioanr para nossa lista de autores depois que um autor é excluido — reverse_lazy() é uma versão executada "preguiçosamente" de reverse(), usada aqui porque estamos fornecendo uma URL para um atributo baseado em classe de view.

+ +

Templates

+ +

As views "create" e "update"  usam o mesmo template por padrão, que serão nomeadas seguindo o modelo: model_name_form.html (você pode mudar o sufixo para algo diferente de _form usando o campo template_name_suffix em sua view, ex. template_name_suffix = '_other_suffix')

+ +

Crie o arquivo de template  locallibrary/catalog/templates/catalog/author_form.html e copie o texto abaixo.

+ +
{% extends "base_generic.html" %}
+
+{% block content %}
+  <form action="" method="post">
+    {% csrf_token %}
+    <table>
+    \{{ form.as_table }}
+    </table>
+    <input type="submit" value="Submit">
+  </form>
+{% endblock %}
+ +

Isso é semelhante aos nossos formulários anteriores e renderiza os campos usando uma tabela. Note também como novamente declaramos o {% csrf_token %} para garantir que nossos formulários são resistentes a ataques CSRF.

+ +

A view "delete" espera encontrar um template nomeado com o formato  model_name_confirm_delete.html (novamente, você pode mudar o sufixo usando template_name_suffix em sua view). Crie o arquivo de template locallibrary/catalog/templates/catalog/author_confirm_delete.html e copie o texto abaixo.

+ +
{% 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 %}
+
+ +

URL configurations

+ +

Abra seu arquivo de configuração de URL (locallibrary/catalog/urls.py)  e adicione a seguinte configuração no final do arquivo:

+ +
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'),
+]
+ +

Não há nada particularmente novo aqui! Você pode ver que  as views são classes, e portanto devem ser chamadas via .as_view(), e você deve poder reconhecer os padrões URL em cada caso. Devemos usar pk como o nome para nosso valor capturado de chave primária (primary key), como esse é o nome do parâmetro esperado pelas classes view.

+ +

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).

+ +
+

Nota: 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  PermissionRequiredMixin e criar uma nova permissão ou reutilizar nossa permissão can_mark_returned).

+
+ +

Testando a página

+ +

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.

+ +

Então navegue para a página de criação de autor: http://127.0.0.1:8000/catalog/author/create/, que deve parecer como a captura de tela abaixo.

+ +

Form Example: Create Author

+ +

Entre com valores para os campos e então pressione Submit 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 http://127.0.0.1:8000/catalog/author/10.

+ +

Você pode testar edição de registros enexando /update/ ao final da URL da página de detalhe (ex. http://127.0.0.1:8000/catalog/author/10/update/) — não mostramos uma captura de tela, porque se parace com a página de criação

+ +

Finalmente, podemos excluir a página anexando delete ao final da URL da visualização detalhada do autor  (ex. http://127.0.0.1:8000/catalog/author/10/delete/). Django deve exibir a página de exclusão mostrada abaixo. Pressione Yes, delete. para remover o registro e ser levado para a lista de todos os autores.

+ +

+ +

Desafie-se

+ +

Crie alguns forms para criar, editar e excluir registros de Book. Você pode utilizar exatamente a mesma estrutura que a de  Authors. Se seu template book_form.html é apenas uma cópia renomeada de   author_form.html , então a nova página "criar livro" será semelhante a captura de tela abaixo:

+ +

+ + + +

Resumo

+ +

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 views 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 model.

+ +

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.

+ +

Veja também

+ + + +

{{PreviousMenuNext("Learn/Server-side/Django/authentication_and_sessions", "Learn/Server-side/Django/Testing", "Learn/Server-side/Django")}}

+ +

Neste módulo

+ + 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 +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/Home_page", "Learn/Server-side/Django/Sessions", "Learn/Server-side/Django")}}
+ +

Este tutorial estende nosso website LocalLibrary, 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.

+ + + + + + + + + + + + +
Pré-requisitos:Conclua todos os tópicos do tutorial anterior, incluindo Django Tutorial Part 5: Creating our home page.
Objetivo: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.
+ +

Visão global

+ +

Neste tutorial, vamos concluir a primeira versão do website LocalLibrary 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!)

+ +

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.

+ +

A parte final do tutorial demonstrará como paginar seus dados ao usar visualizações de lista genéricas baseadas em classe.

+ +

Book list page

+ +

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: catalog/books/. 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 (base_generic.html) que criamos no tutorial anterior.

+ +

URL mapping

+ +

Abra /catalog/urls.py e copie na linha mostrada em negrito abaixo. Quanto à página index, a função path() define um padrão para corresponder ao URL ('books/'), a função view que será chamado se o URL corresponder (views.BookListView.as_view()), e um nome para esse mapeamento específico.

+ +
urlpatterns = [
+    path('', views.index, name='index'),
+    path('books/', views.BookListView.as_view(), name='books'),
+]
+ +

Conforme discutido no tutorial anterior, o URL já deve ter correspondencia /catalog, então a visualização será realmente chamada para o URL: /catalog/books/.

+ +

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.

+ +

Para as class-based views do Django, acessamos uma função de visualização apropriada chamando o método de classe as_view(). 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.

+ +

View (class-based)

+ +

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 render() para passar a lista para um modelo especificado. No entanto, usaremos uma view de lista genérica class-based (ListView) — 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.

+ +

Abra catalog/views.py, e copie o seguinte código na parte inferior do arquivo:

+ +
from django.views import generic
+
+class BookListView(generic.ListView):
+    model = Book
+ +

É isso aí! A view genérica consultará o banco de dados para obter todos os registros para o modelo especificado (Book) em seguida, renderize um template localizado em /locallibrary/catalog/templates/catalog/book_list.html (que criaremos abaixo). Dentro do template, você pode acessar a lista de livros com a variável de template denominada object_list OU book_list (i.e. genericamente "the_model_name_list").

+ +
+

Nota: Esse caminho estranho para a localização do template não é um erro de impressão - as visualizações genéricas procuram modelos em /application_name/the_model_name_list.html (catalog/book_list.html nesse caso) dentro do aplicativo /application_name/templates/ diretório (/catalog/templates/).

+
+ +

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 book_list 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.

+ +
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
+ +

Substituindo métodos em class-based views

+ +

Embora não precisemos fazer isso aqui, você também pode substituir alguns dos métodos da classe.

+ +

Por exemplo, podemos substituir o método get_queryset() para alterar a lista de registros retornados. Isso é mais flexível do que apenas definir o atributo queryset como fizemos no fragmento de código anterior (embora não haja nenhum benefício real neste caso):

+ +
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
+
+ +

Também podemos substituir get_context_data() 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 "some_data" para o contexto (estaria disponível como uma variável de template).

+ +
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
+ +

Ao fazer isso, é importante seguir o padrão usado acima:

+ + + +
+

Nota: Confira Built-in class-based generic views (Django docs) para muitos mais exemplos do que você pode fazer.

+
+ +

Criando o template List View

+ +

Crie o arquivo HTML /locallibrary/catalog/templates/catalog/book_list.html 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 Book em um aplicativo chamado catalog).

+ +

Os templates para visualizações genéricas são como qualquer outro template (embora, é claro, o contexto/informações passadas para o template possam ser diferentes). Assim como em nosso template index, estendemos nosso template base na primeira linha e substituímos o bloco denominado content.

+ +
{% extends "base_generic.html" %}
+
+{% block content %}
+  <h1>Book List</h1>
+  {% if book_list %}
+  <ul>
+    {% for book in book_list %}
+      <li>
+        <a href="\{{ book.get_absolute_url }}">\{{ book.title }}</a> (\{{book.author}})
+      </li>
+    {% endfor %}
+  </ul>
+  {% else %}
+    <p>There are no books in the library.</p>
+  {% endif %} 
+{% endblock %}
+ +

A view passa o contexto (lista de livros), por padrão, um object_list e book_list aliases; qualquer um funcionará.

+ +

Execução conditional

+ +

Nós usamos o if, else, e endif template tags para verificar se o book_list foi definido e não está vazio. E se book_list está vazio, então a cláusula else exibe o  texto explicando que não há livros para listar. E se book_list não estiver vazio, percorreremos a lista de livros.

+ +
{% if book_list %}
+  <!-- code here to list the books -->
+{% else %}
+  <p>There are no books in the library.</p>
+{% endif %}
+
+ +

A condição acima verifica apenas um caso, mas você pode testar em condições adicionais usando a template tag elif (e.g. {% elif var2 %}). Para obter mais informações sobre operadores condicionais, consulte: if, ifequal/ifnotequal, e ifchanged em Built-in template tags and filters (Django Docs).

+ +

For loops

+ +

O template usa as template tags for e endfor para percorrer a lista de livros, como mostrado abaixo. Cada iteração preenche a variável de template book com informações para o item da lista atual.

+ +
{% for book in book_list %}
+  <li> <!-- code here get information from each book item --> </li>
+{% endfor %}
+
+ +

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  forloop.last para executar o processamento condicional na última vez em que o loop é executado.

+ +

Acessando variáveis

+ +

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.

+ +
<a href="\{{ book.get_absolute_url }}">\{{ book.title }}</a> (\{{book.author}})
+
+ +

Acessamos os campos do registro de livro associado usando a "notação de ponto" (e.g. book.title e book.author), onde o texto após o item book é o nome do campo (conforme definido no modelo).

+ +

Também podemos chamar funções no modelo de dentro do nosso template - nesse caso, chamamos Book.get_absolute_url() 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!)

+ +
+

Nota: 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!

+
+ +

Atualize o template base

+ +

Abra o template base (/locallibrary/catalog/templates/base_generic.html) e insira {% url 'books' %} no link da URL para All books,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").

+ +
<li><a href="{% url 'index' %}">Home</a></li>
+<li><a href="{% url 'books' %}">All books</a></li>
+<li><a href="">All authors</a></li>
+ +

Com o que se parece?

+ +

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.

+ +

Pagina Book detail

+ +

A página book detail exibirá informações sobre um livro específico, acessado usando o URL catalog/book/<id> (onde <id> é a chave primária do livro). Além dos campos no model Book (author, summary, ISBN, language, e genre), também listaremos os detalhes das cópias disponíveis (BookInstances) 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.

+ +

URL mapping

+ +

Abra /catalog/urls.py e adicione a URL 'book-detail' mostrado em negrito abaixo. Esta função path() define um padrão, exibição de detalhes genérica associada à classe associada e um nome.

+ +
urlpatterns = [
+    path('', views.index, name='index'),
+    path('books/', views.BookListView.as_view(), name='books'),
+    path('book/<int:pk>', views.BookDetailView.as_view(), name='book-detail'),
+]
+ +

Para o path book-detail 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, <something> , 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 converter specification que define o tipo de dados (int, str, slug, uuid, path).

+ +

Neste caso, usamos '<int:pk>' 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 pk (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.

+ +
+

Nota: Como discutido anteriormente, nosso URL correspondente é realmente catalog/book/<digits> (porque estamos no aplicativo de catalog, /catalog/ é assumido).

+
+ +
+

Importante: A view de detalhes genérica class-based espera receber um parâmetro chamado pk. 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.

+
+ +

Correspondência avançada de caminhos/iniciador de expressão regular

+ +
+

Nota: 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.

+
+ +

The pattern matching provided by path() is simple and useful for the (very common) cases where you just want to capture any 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 re_path() method.

+ +

This method is used just like path() except that it allows you to specify a pattern using a Regular expression. For example, the previous path could have been written as shown below:

+ +
re_path(r'^book/(?P<pk>\d+)$', views.BookDetailView.as_view(), name='book-detail'),
+
+ +

Regular expressions are an incredibly powerful pattern mapping tool. They are, frankly, quite unintuitive and scary for beginners. Below is a very short primer!

+ +

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: r'<your regular expression text goes here>').

+ +

The main parts of the syntax you will need to know for declaring the pattern matches are:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SymbolMeaning
^Match the beginning of the text
$Match the end of the text
\dMatch a digit (0, 1, 2, ... 9)
\wMatch a word character, e.g. any upper- or lower-case character in the alphabet, digit or the underscore character (_)
+Match one or more of the preceding character. For example, to match one or more digits you would use \d+. To match one or more "a" characters, you could use a+
*Match zero or more of the preceding character. For example, to match nothing or a word you could use \w*
( )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).
(?P<name>...)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!
[  ]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.
+ +

Most other characters can be taken literally!

+ +

Let's consider a few real examples of patterns:

+ + + + + + + + + + + + + + + + + + + + + + +
PatternDescription
r'^book/(?P<pk>\d+)$' +

This is the RE used in our URL mapper. It matches a string that has book/ at the start of the line (^book/), then has one or more digits (\d+), and then ends (with no non-digit characters before the end of line marker).

+ +

It also captures all the digits (?P<pk>\d+) and passes them to the view in a parameter named 'pk'. The captured values are always passed as a string!

+ +

For example, this would match book/1234 , and send a variable pk='1234' to the view.

+
r'^book/(\d+)$'This matches the same URLs as the preceding case. The captured information would be sent as an unnamed argument to the view.
r'^book/(?P<stub>[-\w]+)$' +

This matches a string that has book/ at the start of the line (^book/), then has one or more characters that are either a '-' or a word character ([-\w]+), and then ends. It also captures this set of characters and passes them to the view in a parameter named 'stub'.

+ +

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 /catalog/book/the-secret-garden rather than /catalog/book/33.

+
+ +

You can capture multiple patterns in the one match, and hence encode lots of different information in a URL.

+ +
+

Nota: 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.

+
+ +

Passando opções adicionais em seus mapas de URL

+ +

Um recurso que não usamos aqui, mas que você pode achar valioso, é que você pode declarar e passar opções adicionais 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 path(). 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).

+ +
path('url/', views.my_reused_view, {'my_template_name': 'some_path'}, name='aurl'),
+path('anotherurl/', views.my_reused_view, {'my_template_name': 'another_path'}, name='anotherurl'),
+
+ +
+

Nota: As opções extras e os padrões capturados nomeados são passados para a view como argumentos nomeados. Se você usar o mesmo nome 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).

+
+ +

View (class-based)

+ +

Abra catalog/views.py, e copie o seguinte código na parte inferior do arquivo:

+ +
class BookDetailView(generic.DetailView):
+    model = Book
+ +

É isso aí! Tudo o que você precisa fazer agora é criar um modelo chamado /locallibrary/catalog/templates/catalog/book_detail.html, e a visualização passará as informações do banco de dados para o registro Book extraído pelo mapeador de URL. Dentro do modelo, você pode acessar a lista de livros com a variável de modelo denominada object ou book (i.e. genericamente "the_model_name").

+ +

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.

+ +

O que acontece se o registro não existir?

+ +

Se um registro solicitado não existir, a view de detalhes genérica class-based levantará uma exceção Http404 para você automaticamente — em produção, isso exibirá automaticamente uma página apropriada de "resource not found", que você pode personalizar se desejar.

+ +

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.

+ +
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})
+
+ +

A view tenta primeiro obter o registro de livro específico do modelo. Se isso falhar, a view deve gerar uma exceção Http404 para indicar que o livro "não foi encontrado". A etapa final é, como sempre, chamar render() com o nome do template e os dados do livro no parâmetro context (como um dicionário).

+ +

Como alternativa, podemos usar a função get_object_or_404() como um atalho para levantar uma exceção Http404 se o registro não for encontrado.

+ +
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})
+ +

Criando o template Detail View

+ +

Crie o arquivo HTML /locallibrary/catalog/templates/catalog/book_detail.html e forneça o conteúdo abaixo. Conforme discutido acima, este é o nome do arquivo de template padrão esperado pela view de detalhes genérica class-based (para um modelo chamado Book no aplicativo chamado catalog).

+ +
{% 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 %}
+ + + +
+

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:

+ +
<a href="{% url 'author-detail' book.author.pk %}">\{{ book.author }}</a>
+
+
+ +

Embora um pouco maior, quase tudo neste template foi descrito anteriormente:

+ + + +

A única coisa interessante que não vimos antes é a função book.bookinstance_set.all(). Este método é "automagicamente" construído pelo Django para retornar o conjunto de registros BookInstance associados com um Book em particular.

+ +
{% for copy in book.bookinstance_set.all %}
+  <!-- code to iterate across each copy/instance of a book -->
+{% endfor %}
+ +

Este método é necessário porque você declara um campo ForeignKey (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 ForeignKey foi declarado, seguido por _set (i.e. então a função criada em Book é bookinstance_set()).

+ +
+

Nota: Aqui usamos all() para obter todos os registros (o padrão). Enquanto você pode usar o método filter() 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.

+ +

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:

+ +
[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)
+
+ +

Isso acontece porque o objeto paginator 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!

+ +

Este tutorial não atingiu a Paginação (ainda, mas em breve), mas como você não pode usar sort_by() e passar um parâmetro (o mesmo com filter() descrito acima), você terá que escolher entre três opções:

+ +
    +
  1. Adicione um ordering dentro de uma declaração class Meta no seu model.
  2. +
  3. Adicione um atributo queryset na sua class-based view, especificando um order_by().
  4. +
  5. Adicione um método get_queryset à sua class-based view personalisada e também especifique o order_by().
  6. +
+ +

Se você decidir ir com uma class Meta no model Author (provavelmente não tão flexível quanto personalizar o class-based view, mas fácil o suficiente), você terminará com algo assim:

+ +
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}'
+
+    class Meta:
+        ordering = ['last_name']
+ +

Obviamente, o campo não precisa ser last_name: poderia ser qualquer outro.

+ +

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.

+
+ +

Com o que se parece agora?

+ +

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 (python3 manage.py runserver) e abra no seu navegador http://127.0.0.1:8000/.

+ +
+

Aviso: Não clique em nenhum autor ou link de detalhes do autor ainda - você os criará no desafio!

+
+ +

Clique no link All books para exibir a lista de livros.

+ +

Book List Page

+ +

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.

+ +

Book Detail Page

+ +

Paginação

+ +

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.

+ +

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!

+ +

Views

+ +

Abra catalog/views.py, e adicionea linha paginate_by mostrado em negrito abaixo.

+ +
class BookListView(generic.ListView):
+    model = Book
+    paginate_by = 10
+ +

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: /catalog/books/?page=2.

+ +

Templates

+ +

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. 

+ +

Abra /locallibrary/catalog/templates/base_generic.html 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).

+ +
{% block content %}{% endblock %}
+
+  {% 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 %} 
+ +

O page_obj é um objeto de Paginator 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.

+ +

Usamos \{{ request.path }} para obter o URL da página atual para criar os links de paginação. Isso é útil porque é independente do objeto que estamos paginando.

+ +

É isso aí!

+ +

Com o que se parece agora?

+ +

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 paginate_by no seu arquivo catalog/views.py. Para obter o resultado abaixo, alteramos para paginate_by = 2.

+ +

Os links de paginação são exibidos na parte inferior, com os links seguinte/anterior, dependendo da página em que você está.

+ +

Book List Page - paginated

+ +

Challenge yourself

+ +

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:

+ + + +

The code required for the URL mappers and the views should be virtually identical to the Book list and detail views we created above. The templates will be different but will share similar behaviour.

+ +
+

Note:

+ + +
+ +

When you are finished, your pages should look something like the screenshots below.

+ +

Author List Page

+ + + +

Author Detail Page

+ + + +

Summary

+ +

Congratulations, our basic library functionality is now complete! 

+ +

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.

+ +

In our next articles, we'll extend this library to support user accounts, and thereby demonstrate user authentication, permissons, sessions, and forms.

+ +

See also

+ + + +

{{PreviousMenuNext("Learn/Server-side/Django/Home_page", "Learn/Server-side/Django/Sessions", "Learn/Server-side/Django")}}

+ +

Neste módulo

+ + 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 +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django")}}
+ +

Agora estamos prontos para adicionar o código que exibe nossa primeira página completa - uma home page do site LocalLibrary. 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.

+ + + + + + + + + + + + +
Pré-requisitos:Leia a Introdução ao Django. Conclua os tópicos do tutorial anterior (incluindo Django Tutorial Part 4: Django admin site).
Objetivo:Aprender a criar mapas e visualizações de URL simples (onde nenhum dado é codificado no URL), obtenha dados de modelos e crie modelos.
+ +

Visão Global

+ +

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.

+ +

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:

+ + + +

+ +

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.

+ +

Definindo os URLs do recurso

+ +

Como esta versão do LocalLibrary é 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.

+ +

As URLs que iremos precisar na nossa página são:

+ + + +

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.

+ +

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 <id> 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). 

+ +
+

Nota: 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 GET parâmetros no URL, por exemplo /book/?id=6. Qualquer que seja a abordagem usada, os URLs devem ser mantidos limpos, lógicos e legíveis, conforme recomendado pelo W3C.
+ A documentação do Django recomenda informações de codificação no corpo da URL para obter um melhor design da URL.

+
+ +

Conforme mencionado na visão geral, o restante deste artigo descreve como construir a página index.

+ +

Criando a página index

+ +

A primeira página que criaremos é a página index (catalog/). 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.

+ +
+

Nota: 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.

+
+ +

Mapeamento de URL

+ +

Quando criamos o esqueleto do website, atualizamos o arquivo locallibrary/urls.py para garantir que sempre que um URL que comece com catalog/  é recebido, o módulo URLConf catalog.urls processará a substring restante.

+ +

O seguinte snippet de código de locallibrary/urls.py inclui o modulo catalog.urls:

+ +
urlpatterns += [
+    path('catalog/', include('catalog.urls')),
+]
+
+ +
+

Nota: Sempre que o Django encontra a função de importação  django.urls.include(), 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.

+
+ +

Também criamos um arquivo de espaço reservado para o modulo URLConf, chamado /catalog/urls.py. Adicione as seguintes linhas a esse arquivo: 

+ +
urlpatterns = [
+    path('', views.index, name='index'),
+]
+ +

A função path() define o seguinte:

+ + + +

A função path() 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:

+ +
<a href="{% url 'index' %}">Home</a>.
+ +
+

Nota: Podemos codificar o link como em <a href="/catalog/">Home</a>), mas se alterarmos o padrão da nossa página inicial, por exemplo, para /catalog/index) os modelos não serão mais vinculados corretamente. Usar um mapeamento de URL invertido é muito mais flexível e robusto.

+
+ +

View (function-based)

+ +

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 Book, BookInstance, disponibilidade de  BookInstance e registros de Author que temos no banco de dados e passa essas informações para um modelo para exibição.

+ +

Abra catalog/views.py e observe que o arquivo já importa o render() da função shortcuts para gerar arquivo HTML usando um modelo e dados: 

+ +
from django.shortcuts import render
+
+# Create your views here.
+
+ +

Cole as seguintes linhas na parte inferior do arquivo:

+ +
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)
+ +

A primeira linha importa as classes de models que usaremos para acessar dados em todas as nossas visualizações.

+ +

A primeira parte da função view busca o número de registros usando o atributo  objects.all() nas classes de modelo. Também recebe uma lista de objetos de  BookInstance 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 Django Tutorial Part 3: Using models > Searching for records.

+ +

No final da função view chamamos a função render() 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 render() aceita os seguintes parâmetros:

+ + + +

Falaremos mais sobre modelos e variáveis context na próxima seção. Vamos criar nosso template para que possamos exibir algo para o usuário!

+ +

Template

+ +

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.

+ +

Django irá procurar automaticamente templates na pasta chamada 'templates' em sua aplicação. Por exemplo, na exibição de index que acabamos de adicionar, a função render() espera encontrar o arquivo index.html em /locallibrary/catalog/templates/ e gera um erro se o arquivo não estiver presente.

+ +

Você pode verificar isso salvando as alterações anteriores e acessando 127.0.0.1:8000 no seu navegador - ele exibirá uma mensagem de erro bastante intuitiva: "TemplateDoesNotExist at /catalog/", e outros detalhes.

+ +
+

Nota: 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 the Templates section of the Django documentation.

+
+ +

Estendendo templates

+ +

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.

+ +

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.

+ +

O seguinte snippet de código é um template base de amostra de um arquivo base_generic.html. 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 block e endblock, 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.

+ +
+

Nota: Template tags 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).

+
+ +
<!DOCTYPE html>
+<html lang="en">
+<head>
+  {% block title %}<title>Local Library</title>{% endblock %}
+</head>
+<body>
+  {% block sidebar %}<!-- insert default navigation text for every page -->{% endblock %}
+  {% block content %}<!-- default content text (typically empty) -->{% endblock %}
+</body>
+</html>
+
+ +

Ao definir um template para uma visualização específica, primeiro especificamos o template base usando a template tag extends — veja o exemplo de código abaixo. Em seguida, declaramos quais seções do template queremos substituir (se houver), usando seções block/endblock como no template base. 

+ +

Por exemplo, o trecho de código abaixo mostra como usar a template tag extends e substituir o block content. 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 title, mas o novo block content no lugar do padrão.

+ +
{% 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 %}
+ +

O template base LocalLibrary

+ +

Usaremos o seguinte snippet de código como modelo básico para o site LocalLibrary. Como você pode ver, ele contém algum código HTML e define blocos para title, sidebar, e content. 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.

+ +
+

Nota: Também introduzimos duas template tags adicionais: url e load static. Essas tags serão explicadas nas próximas seções.

+
+ +

Crie um novo arquivo base_generic.html em /locallibrary/catalog/templates/ e cole o seguinte código no arquivo:

+ +
<!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>
+ +

O template inclui CSS de Bootstrap 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.

+ +

O template base também faz referência a um arquivo css local (styles.css) que fornece estilo adicional. Criar um arquivo styles.css em /locallibrary/catalog/static/css/ e cole o seguinte código no arquivo:

+ +
.sidebar-nav {
+    margin-top: 20px;
+    padding: 0;
+    list-style: none;
+}
+ +

O template index

+ +

Crie um novo arquivo HTML index.html em /locallibrary/catalog/templates/ e cole o seguinte código no arquivo Esse código estende nosso modelo base na primeira linha e substitui o padrão block content para o template. 

+ +
{% 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> \{{ 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>
+{% endblock %}
+ +

Na seção Dynamic content, declaramos espaços reservados (variáveis de template) 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. 

+ +
+

Nota: Você pode reconhecer facilmente variáveis de template e template tags (funções) - as variáveis são colocadas entre chaves (\{{ num_books }}), e as tags são colocadas em chaves simples com sinais de porcentagem ({% extends "base_generic.html" %}).

+
+ +

O importante a ser observado aqui é que as variáveis são nomeadas com as chaves que passamos para o dicionário context na função render() da nossa view (veja a amostra abaixo). As variáveis serão substituídas pelos valores associados quando o modelo for renderizado.

+ +
context = {
+    'num_books': num_books,
+    'num_instances': num_instances,
+    'num_instances_available': num_instances_available,
+    'num_authors': num_authors,
+}
+
+return render(request, 'index.html', context=context)
+ +

Referenciando arquivos estáticos nos templates

+ +

É 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 STATIC_URL. O site padrão do esqueleto define o valor de STATIC_URL para '/static/', mas você pode optar por hospedá-los em uma rede de entrega de conteúdo ou em outro local.

+ +

Dentro do template que você chama primeiro na template tag load especificando "static" para adicionar a biblioteca de modelos, conforme mostrado no exemplo de código abaixo. Você pode então usar a template tag static e especifique o URL relativo ao arquivo necessário.

+ +
<!-- Add additional CSS in static file -->
+{% load static %}
+<link rel="stylesheet" href="{% static 'css/styles.css' %}">
+ +

Você pode adicionar uma imagem à página de maneira semelhante, por exemplo:

+ +
{% load static %}
+<img src="{% static 'catalog/images/local_library_model_uml.png' %}" alt="UML diagram" style="width:555px;height:540px;">
+
+ +
+

Nota: 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 (/locallibrary/locallibrary/urls.py) quando criamos o esqueleto do website, mas ainda precisamos ativar a veiculação de arquivos na produção. Veremos isso mais tarde.

+
+ +

Para obter mais informações sobre como Trabalhar com arquivos estaticos, consulte Gerenciando arquivos estáticos na documentação do Django.

+ +

Vinculando as URLs

+ +

O template base abaixo introduziu a template tag url.

+ +
<li><a href="{% url 'index' %}">Home</a></li>
+
+ +

Essa tag aceita o nome de uma função path() chamado em urls.py 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.

+ +

Configurando onde encontrar os templates

+ +

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 settings.py, como mostrado em negrito, no seguinte exemplo de código:

+ +
TEMPLATES = [
+    {
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
+        'DIRS': [
+            os.path.join(BASE_DIR, 'templates'),
+        ],
+        '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',
+            ],
+        },
+    },
+]
+ +

Com o que se parece?

+ +

Neste ponto, criamos todos os recursos necessários para exibir a página index. Execute o servidor (python3 manage.py runserver) e abra http://127.0.0.1:8000/ no seu navegador. Se tudo estiver configurado corretamente, seu site deverá ter a seguinte captura de tela.

+ +

Index page for LocalLibrary website

+ +
+

Nota: Os links All books e All authors 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 base_generic.html.

+
+ +

Desafie-se

+ +

Temos duas tarefas para testar a sua familiaridade com as consultas de modelos, views e templates

+ +
    +
  1. O modelo de base da BibliotecaLocal inclui um bloco de título. Substitua este bloco no modelo de índice e crie um novo título para a página.
  2. +
  3. +
    +

    Dica: A seção Extendendo Templates explica como criar blocos e  extender um bloco em outro template.

    +
    +
  4. +
  5. Modifique a view para gerar contagens para gêneros e livros que contenham uma palavra específica (case insensitive), e passe o resultado para o contexto. Isso é feito de maneira semelhante à criação e uso de num_books e num_instances_available. Em seguida, atualize o template do index para incluir essas variáveis.
  6. +
+ + + +

Resumo

+ +

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.

+ +

No próximo artigo, continuaremos sobre esse conhecimento para criar as quatro páginas restantes de nosso site.

+ +

Veja também

+ + + +

{{PreviousMenuNext("Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django")}}

+ +

Nesse Módulo

+ + 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 +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/Testing", "Learn/Server-side/Django/web_application_security", "Learn/Server-side/Django")}}
+ +

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.

+ + + + + + + + + + + + +
Pré-requisitos: +

Completar todos os tópicos do tutorial anterior, incluindo o Tutorial Django Parte 10: Testando uma aplicação web Django.

+
Objectivo:Para saber onde e como se pode hospedar uma aplicação Django na produção.
+ +

Visão geral

+ +

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.

+ +

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:

+ + + +

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 Heroku.

+ +

O que é um ambiente de produção?

+ +

O ambiente de produção é o ambiente fornecido pelo computador/servidor onde você executará seu site para consumo externo. O ambiente inclui:

+ + + +
+

Nota: Dependendo de como sua produção está configurada, você também pode ter um proxy reverso, load balancer(balanceador de carga), etc.

+
+ +

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.

+ +

Esse tipo de hardware de computação/rede acessível remotamente é conhecido como Infraestrutura como Serviço (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.

+ +
+

Nota: 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!

+
+ +

Outros provedores de hospedagem oferecem suporte a Django como parte de uma oferta de Plataforma como Serviço (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.

+ +

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.

+ +
+

Dica: 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 documentos da comunidade Digital Ocean Django.

+
+ +

Escolhendo um provedor de hospedagem

+ +

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 Djangofriendly hosts). Esses fornecedores oferecem diferentes tipos de ambientes (IaaS, PaaS) e diferentes níveis de recursos de computação e rede a preços diferentes.

+ +

Algumas coisas a serem consideradas ao escolher um host:

+ + + +

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 Heroku, Python Anywhere, Amazon Web Services, Microsoft Azure, etc.

+ +

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. Digital Ocean e Python Anywhere 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).

+ +
+

Nota: 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.

+
+ +

Preparando seu site para publicação

+ +

O esqueleto do site do Django 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.

+ +
+

Dica: É comum ter um arquivo settings.py 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.

+
+ +

As configurações críticas que você deve verificar são:

+ + + +

Vamos mudar o aplicativo LocalLibrary para que possamos ler nosso SECRET_KEY e DEBUG variáveis ​​de variáveis ​​de ambiente se forem definidas, mas caso contrário, use os valores padrão no arquivo de configuração.

+ +

Abra /locallibrary/settings.py, desative o original SECRET_KEYconfiguração e adicione as novas linhas conforme mostrado abaixo em negrito. 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).

+ +
# SECURITY WARNING: keep the secret key used in production secret!
+# SECRET_KEY = 'cg#p$g+j9tax!#a3cup@1$8obt2_+&k3q+pmu)5%asj6yjpkag'
+import os
+SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'cg#p$g+j9tax!#a3cup@1$8obt2_+&k3q+pmu)5%asj6yjpkag')
+
+ +

Em seguida, comente o existente DEBUG configuração e adicione a nova linha mostrada abaixo.

+ +
# SECURITY WARNING: don't run with debug turned on in production!
+# DEBUG = True
+DEBUG = os.environ.get('DJANGO_DEBUG', '') != 'False'
+
+ +

O valor do DEBUG será True por padrão, mas será apenas False se o valor do DJANGO_DEBUG variável de ambiente é definida para False. 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 DEBUG variável para False é realmente configurá-lo para a string False

+ +

Você pode definir a variável de ambiente como False, emitindo o seguinte comando:

+ +
export DJANGO_DEBUG=False
+ +

Uma lista de verificação completa das configurações que você pode querer mudar é fornecida na Lista de verificação de implantação (documentos do Django). Você também pode listar vários deles usando o comando de terminal abaixo:

+ +
python3 manage.py check --deploy
+
+ +

Exemplo: Instalando LocalLibrary no Heroku

+ +

Esta seção fornece uma demonstração prática de como instalar a LocalLibrary na nuvem Heroku PaaS.

+ +

Por que Heroku?

+ +

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!

+ +

Estamos optando por usar o Heroku por vários motivos:

+ + + +

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.

+ +

How does Heroku work?

+ +

Heroku runs Django websites within one or more "Dynos", which are isolated, virtualized Unix containers that provide the environment required to run an application. The dynos are completely isolated and have an ephemeral 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 configuration variables. 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).

+ +

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.

+ +

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:

+ + + +

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!

+ +

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.

+ +

Once we've done all that we can set up a Heroku account, get the Heroku client, and use it to install our website.

+ +
+

Note: 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: Getting Started on Heroku with Django.

+
+ +

That's all the overview you need in order to get started (see How Heroku works for a more comprehensive guide).

+ +

Creating an application repository in Github

+ +

Heroku is closely integrated with the git 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 heroku 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.

+ +
+

Note: 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.

+
+ +

There are a lot of ways to work with git, but one of the easiest is to first set up an account on Github, create the repository there, and then sync to it locally:

+ +
    +
  1. Visit https://github.com/ and create an account.
  2. +
  3. Once you are logged in, click the + link in the top toolbar and select New repository.
  4. +
  5. Fill in all the fields on this form. While these are not compulsory, they are strongly recommended. +
      +
    • Enter a new repository name (e.g. django_local_library), and description (e.g. "Local Library website written in Django".
    • +
    • Choose Python in the Add .gitignore selection list.
    • +
    • Choose your preferred license in the Add license selection list.
    • +
    • Check Initialize this repository with a README.
    • +
    +
  6. +
  7. Press Create repository.
  8. +
  9. Click the green "Clone or download" button on your new repo page.
  10. +
  11. Copy the URL value from the text field inside the dialog box that appears (it should be something like: https://github.com/<your_git_user_id>/django_local_library.git).
  12. +
+ +

Now that the repository ("repo") is created we are going to want to clone it on our local computer:

+ +
    +
  1. Install git for your local computer (you can find versions for different platforms here).
  2. +
  3. Open a command prompt/terminal and clone your repository using the URL you copied above: +
    git clone https://github.com/<your_git_user_id>/django_local_library.git
    +
    + This will create the repository in a new folder in the current working directory.
  4. +
  5. Navigate into the new repo. +
    cd django_local_library
    +
  6. +
+ +

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:

+ +
    +
  1. Copy your Django application into this folder (all the files at the same level as manage.py and below, not their containing locallibrary folder).
  2. +
  3. Open the .gitignore 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). +
    # Text backup files
    +*.bak
    +
    +# Database
    +*.sqlite3
    +
  4. +
  5. Open a command prompt/terminal and use the add command to add all files to git. This adds the files which aren't ignored by the .gitignore file to the "staging area". +
    git add -A
    +
    +
  6. +
  7. Use the status command to check that all files you are about to commit are correct (you want to include source files, not binaries, temporary files etc.). It should look a bit like the listing below. +
    > 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
    +
  8. +
  9. When you're satisfied, commit 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. +
    git commit -m "First version of application moved into github"
    +
  10. +
  11. At this point, the remote repository has not been changed. Synchronise (push) your local repository to the remote Github repository using the following command: +
    git push origin master
    +
  12. +
+ +

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.

+ +
+

Tip: 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.

+ +

The best way to do this is to use git to manage your revisions. With git 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. Learning Git is well worth the effort, but is beyond the scope of this topic.

+ +

The easiest way to do this is to just copy your files into another location. Use whichever approach best matches your knowledge of git!

+
+ +

Update the app for Heroku

+ +

This section explains the changes you'll need to make to our LocalLibrary application to get it to work on Heroku. While Heroku's Getting Started on Heroku with Django 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.

+ +

Procfile

+ +

Create the file Procfile (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:

+ +
web: gunicorn locallibrary.wsgi --log-file -
+ +

The "web:" tells Heroku that this is a web dyno and can be sent HTTP traffic. The process to start in this dyno is gunicorn, which is a popular web application server that Heroku recommends. We start Gunicorn using the configuration information in the module locallibrary.wsgi (created with our application skeleton: /locallibrary/wsgi.py).

+ +

Gunicorn

+ +

Gunicorn 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 Deploying Python applications with Gunicorn for more information).

+ +

While we won't need Gunicorn to serve our LocalLibrary application during development, we'll install it so that it becomes part of our requirements for Heroku to set up on the remote server.

+ +

Install Gunicorn locally on the command line using pip (which we installed when setting up the development environment):

+ +
+

Note: Make sure that you're in your Python virtual environment (use the workon [name-of-virtual-environment] command) before you install Gunicorn and further modules with pip, or you might experience problems with importing these modules in your /locallibrary/settings.py file in the later sections. 

+
+ +
pip3 install gunicorn
+
+ +

Database configuration

+ +

We can't use the default SQLite database on Heroku because it is file-based, and it would be deleted from the ephemeral file system every time the application restarts (typically once a day, and every time the application or its configuration variables are changed).

+ +

The Heroku mechanism for handling this situation is to use a database add-on and configure the web application using information from an environment configuration variable, set by the add-on. There are quite a lot of database options, but we'll use the hobby tier of the Heroku postgres database as this is free, supported by Django, and automatically added to our new Heroku apps when using the free hobby dyno plan tier.

+ +

The database connection information is supplied to the web dyno using a configuration variable named DATABASE_URL. Rather than hard-coding this information into Django, Heroku recommends that developers use the dj-database-url package to parse the DATABASE_URL environment variable and automatically convert it to Django’s desired configuration format. In addition to installing the dj-database-url package we'll also need to install psycopg2, as Django needs this to interact with Postgres databases.

+ +
dj-database-url (Django database configuration from environment variable)
+ +

Install dj-database-url locally so that it becomes part of our requirements for Heroku to set up on the remote server:

+ +
$ pip3 install dj-database-url
+
+ +
settings.py
+ +

Open /locallibrary/settings.py and copy the following configuration into the bottom of the file:

+ +
# 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)
+ +
+

Note:

+ + +
+ +
psycopg2 (Python Postgres database support)
+ +

Django needs psycopg2 to work with Postgres databases and you will need to add this to the requirements.txt for Heroku to set this up on the remote server (as discussed in the requirements section below).

+ +

Django will use our SQLite database locally by default, because the DATABASE_URL 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:

+ +
sudo apt-get install python-pip python-dev libpq-dev postgresql postgresql-contrib
+pip3 install psycopg2-binary
+
+ +

Installation instructions for the other platforms can be found on the psycopg2 website here.

+ +

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 requirements.txt (see below).

+ +

Serving static files in production

+ +

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.

+ +
+

Note: 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. 

+
+ +

To make it easy to host static files separately from the Django web application, Django provides the collectstatic tool to collect these files for deployment (there is a settings variable that defines where the files should be collected when collectstatic is run). Django templates refer to the hosting location of the static files relative to a settings variable (STATIC_URL), so that this can be changed if the static files are moved to another host/server.

+ +

The relevant setting variables are:

+ + + +
settings.py
+ +

Open /locallibrary/settings.py and copy the following configuration into the bottom of the file. The BASE_DIR should already have been defined in your file (the STATIC_URL 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).

+ +
# 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/'
+
+ +

We'll actually do the file serving using a library called WhiteNoise, which we install and configure in the next section.

+ +

For more information, see Django and Static Assets (Heroku docs).

+ +

Whitenoise

+ +

There are many ways to serve static files in production (we saw the relevant Django settings in the previous sections). Heroku recommends using the WhiteNoise project for serving of static assets directly from Gunicorn in production.

+ +
+

Note: Heroku automatically calls collectstatic and prepares your static files for use by WhiteNoise after it uploads your application. Check out WhiteNoise documentation for an explanation of how it works and why the implementation is a relatively efficient method for serving these files.

+
+ +

The steps to set up WhiteNoise to use with the project are given here (and reproduced below):

+ +
WhiteNoise
+ +

Install whitenoise locally using the following command:

+ +
$ pip3 install whitenoise
+
+ +
settings.py
+ +

To install WhiteNoise into your Django application, open /locallibrary/settings.py, find the MIDDLEWARE setting and add the WhiteNoiseMiddleware near the top of the list, just below the SecurityMiddleware:

+ +
MIDDLEWARE = [
+    'django.middleware.security.SecurityMiddleware',
+    'whitenoise.middleware.WhiteNoiseMiddleware',
+    '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',
+]
+
+ +

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 /locallibrary/settings.py:

+ +
# Simplified static file serving.
+# https://warehouse.python.org/project/whitenoise/
+STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
+
+ +

Requirements

+ +

The Python requirements of your web application must be stored in a file requirements.txt in the root of your repository. Heroku will then install these automatically when it rebuilds your environment. You can create this file using pip on the command line (run the following in the repo root):

+ +
pip3 freeze > requirements.txt
+ +

After installing all the different dependencies above, your requirements.txt file should have at least 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.

+ +
dj-database-url==0.5.0
+Django==2.1.5
+gunicorn==19.9.0
+psycopg2-binary==2.7.7
+whitenoise==4.1.2
+
+ +
+

Make sure that a psycopg2 line like the one above is present! Even if you didn't install this locally then you should still add it to requirements.txt.

+
+ +

Runtime

+ +

The runtime.txt file, if defined, tells Heroku which programming language to use. Create the file in the root of the repo and add the following text:

+ +
python-3.7.0
+ +
+

Note: Heroku only supports a small number of Python runtimes (at time of writing, this includes the one above). Heroku will use a supported runtime irrespective of the value specified in this file.

+
+ +

Re-test and save changes to Github

+ +

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.

+ +
python3 manage.py runserver
+ +

Next, lets push our changes to Github. In the terminal (after having navigated to our local repository), enter the following commands:

+ +
git add -A
+git commit -m "Added files and changes required for deployment to heroku"
+git push origin master
+
+ +

We should now be ready to start deploying LocalLibrary on Heroku.

+ +

Get a Heroku account

+ +

To start using Heroku you will first need to create an account:

+ + + +

Install the client

+ +

Download and install the Heroku client by following the instructions on Heroku here.

+ +

After the client is installed you will be able run commands. For example to get help on the client:

+ +
heroku help
+
+ +

Create and upload the website

+ +

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 heroku in our local git environment.

+ +
heroku create
+ +
+

Note: 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.

+
+ +

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.

+ +
git push heroku master
+ +

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 heroku run command and start a "one off dyno" to perform a migrate operation. Enter the following command in your terminal:

+ +
heroku run python manage.py migrate
+ +

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:

+ +
heroku run python manage.py createsuperuser
+ +

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:

+ +
heroku open
+ +

Create some books in the admin site, and check out whether the site is behaving as you expect.

+ +

Managing addons

+ +

You can check out the add-ons to your app using the heroku addons command. This will list all addons, and their price tier and state.

+ +
> heroku addons
+
+Add-on                                     Plan       Price  State
+─────────────────────────────────────────  ─────────  ─────  ───────
+heroku-postgresql (postgresql-flat-26536)  hobby-dev  free   created
+ └─ as DATABASE
+ +

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:

+ +
heroku addons:open heroku-postgresql
+
+ +

Other commands allow you to create, destroy, upgrade and downgrade addons (using a similar syntax to opening). For more information see Managing Add-ons (Heroku docs).

+ +

Setting configuration variables

+ +

You can check out the configuration variables for the site using the heroku config command. Below you can see that we have just one variable, the DATABASE_URL used to configure our database.

+ +
> heroku config
+
+=== locallibrary Config Vars
+DATABASE_URL: postgres://uzfnbcyxidzgrl:j2jkUFDF6OGGqxkgg7Hk3ilbZI@ec2-54-243-201-144.compute-1.amazonaws.com:5432/dbftm4qgh3kda3
+ +

If you recall from the section on getting the website ready to publish, we have to set environment variables for DJANGO_SECRET_KEY and DJANGO_DEBUG. Let's do this now.

+ +
+

Note: The secret key needs to be really secret! One way to generate a new key is to use the Django Secret Key Generator.

+
+ +

We set DJANGO_SECRET_KEY using the config:set command (as shown below). Remember to use your own secret key!

+ +
> 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
+
+ +

We similarly set DJANGO_DEBUG:

+ +
> heroku config:set DJANGO_DEBUG=
+
+Setting DJANGO_DEBUG and restarting locallibrary... done, v8
+ +

If you visit the site now you'll get a "Bad request" error, because the ALLOWED_HOSTS setting is required if you have DEBUG=False (as a security measure). Open /locallibrary/settings.py and change the ALLOWED_HOSTS setting to include your base app url (e.g. 'locallibrary1234.herokuapp.com') and the URL you normally use on your local development server.

+ +
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']
+
+ +

Then save your settings and commit them to your Github repo and to Heroku:

+ +
git add -A
+git commit -m 'Update ALLOWED_HOSTS with site and development server URL'
+git push origin master
+git push heroku master
+ +
+

After the site update to Heroku completes, enter a URL that does not exist (e.g. /catalog/doesnotexist/). Previously this would have displayed a detailed debug page, but now you should just see a simple "Not Found" page.

+
+ +

Debugging

+ +

The Heroku client provides a few tools for debugging:

+ +
# 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
+
+ +

If you need more information than these can provide you will need to start looking into Django Logging.

+ + + +

Summary

+ +

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 source code on Github here.
+
+ The next step is to read our last few articles, and then complete the assessment task.

+ +

See also

+ + + +

{{PreviousMenuNext("Learn/Server-side/Django/Testing", "Learn/Server-side/Django/web_application_security", "Learn/Server-side/Django")}}

+ +

In this module

+ + 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 +--- +
{{LearnSidebar}}
+ +

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.

+ +

Pré-requisitos

+ +

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 Server-side programação de website primeiros passos.

+ +

Um conhecimento geral de conceitos de programação e Python é recomendado, mas não essenciais para entendimento dos conceitos principais.

+ +
+

Nota: 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 Python for não programadores no wiki do python.org)

+
+ +

Como começar?

+ +
+
Introdução ao Django
+
+

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, incluindo 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 se divertir.

+
+
Configurando um ambiente de desenvolvimento Django
+
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.
+
Tutorial Django: Website de uma Biblioteca Local
+
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.
+
+ +
+
Tutorial Django Parte 2: Criando a base do website
+
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.
+
Tutorial Django Parte 3: Utilizando models
+
Este artigo mostra como definir modelos para o site BibliotecaLocal - os modelos representam as estruturas de dados em que queremos armazenar os dados do aplicativo, 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.
+
Tutorial Django Parte 4: Django admin site
+
Agora que nós criamos os modelos para o site BibliotecaLocal, 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.
+
Tutorial Django Parte 5: Criando nossa página principal
+
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.
+
Tutorial Django Parte 6: Lista genérica e detail views
+
Este tutorial estende nosso website BibliotecaLocal 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.
+
Tutorial Django Parte 7: Framework de Sessões
+
Este tutorial estende nosso site  BibliotecaLocal, 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.
+
Django Tutorial Part 8: Autenticação de Usuário e permissões
+
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.
+
Tutorial Django Parte 9: Trabalhando com formulários
+
Neste tutorial iremos mostrar como trabalhar com HTML Forms 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 BibliotecaLocal 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).
+
Tutorial Django Parte 10: Testando uma aplicação web Django
+
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 o teste de unidade do seu site usando a estrutura de teste do Django.
+
Tutorial Django Parte 11: Implantando Django em produção
+
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.
+
Segurança de aplicações web Django
+
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 Web security - este artigo fornece uma demonstração prática de como as proteções internas do Django lidam com essas ameaças.
+
+
+ +

Assessments

+ +

A avaliação a seguir testará sua compreensão de como criar um site usando o Django, conforme descrito nos guias listados acima.

+ +
+
DIY Django mini blog
+
Nesta avaliação, você usará alguns dos conhecimentos que aprendeu neste módulo para criar seu próprio blog.
+
diff --git "a/files/pt-br/learn/server-side/django/introdu\303\247\303\243o/index.html" "b/files/pt-br/learn/server-side/django/introdu\303\247\303\243o/index.html" new file mode 100644 index 0000000000..9258d18dc6 --- /dev/null +++ "b/files/pt-br/learn/server-side/django/introdu\303\247\303\243o/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 +--- +
{{LearnSidebar}}
+ +
{{NextMenu("Learn/Server-side/Django/development_environment", "Learn/Server-side/Django")}}
+ +

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).

+ + + + + + + + + + + + +
Pré-requisitos: +

Conhecimentos básicos em computação. Um entendimento geral de programação de websites do lado do servidor e, em particular, a mecânica de interações cliente-servidor em websites.

+
Objetivos:Ganhar familiaridade com o que é o Django, quais funcionalidades ele fornece e os principais blocos de construção de uma aplicação django.
+ +

O que é Django?

+ +

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. 

+ +

Django ajuda você a escrever programas que são:

+ +
+
Completo
+
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 atualizada documentação.
+
Versátil
+
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.
+
À 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.
+
Seguro
+
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.
+
Um hash de senha é um valor fixed-length (tamanho-fixo) criado mandando a senha por uma cryptographic hash function (função hash criptográfica). 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.
+
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 Segurança de sites para mais detalhes de tais ataques).
+
Escalável
+
Django usa uma arquitetura baseada em componentes “shared-nothing” ("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).
+
Sustentável
+
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 MVC - Model View Controller).
+
Portável
+
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.
+
+ +

De onde o Django veio?

+ +

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.

+ +

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).

+ +
+

Nota: Cheque as notas de lançamento 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.

+
+ +

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.

+ + + +

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 Hot Frameworks 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?

+ +

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!

+ +

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: Página inicial do django).

+ +

O Django é opinativo?

+ +

Frameworks de web frequentemente referem a si mesmos como "opinativo" e "não opinativo".

+ +

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 um domínio em particular (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.

+ +

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.
+
+ 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.

+ +

Com o que o código do Django parece?

+ +

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 POST ou GET. 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.

+ +

Aplicativos web feitos com Django geralmente agrupam o código que manipula cada uma dessas etapas em arquivos separados:

+ +

+ + + +
+

Nota: 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 Model View Controller (Modelo Vista Controlador).

+
+ + + +

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).

+ +

Enviando a solicitação para a view correta (urls.py)

+ +

Um mapeador de URLs normalmente é armazenado em um arquivo chamado urls.py. No exemplo abaixo, o mapeador (urlpatterns) (padrões de url) define uma lista de mapeamentos entre rotas (padrões 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.

+ +
urlpatterns = [
+    path('admin/', admin.site.urls),
+    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),
+# ]
+
+ +

O objeto urlpatterns é uma lista de funções path() (caminhos) e/ou re_path() (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: [item1, item2, item3,]).

+ +

O primeiro argumento para ambos os métodos é uma rota (padrão) que será correspondida. O método path() 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 re_path() 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!

+ +

O segundo argumento é outra função que será chamada quando o padrão for correspondido. A notação views.book-detail (views.livro-detalhes) indica que a função é chamada de book-detail() (livro-detalhes()) e pode ser encontrada em um módulo chamado views (ou seja, dentro de um arquivo chamado views.py)

+ +

Manipulando a solicitação (views.py)

+ +

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.

+ +

O exemplo abaixo mostra uma função view mínima chamada index(), que poderia ter sido chamado pelo nosso mapeador de URLs na seção anterior. Como todas as funções view, ele recebe um objeto HttpRequest como um parâmetro (request) e retorna um objeto HttpResponse. 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.

+ +
## 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!')
+
+# favor utilizar o código acima no seu projeto ao invés do que está abaixo
+## 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!')
+
+ +
+

Nota: Um pouquinho de Python:

+ + +
+ + + +

Views geralmente são armazenadas em um arquivo chamado views.py.

+ +

Definindo o modelo dos dados (models.py)

+ +

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 tipos 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ê.

+ +

O trecho de código abaixo mostra um modelo simples do Django para um objeto Team (Time). A classe Team é derivada da classe do Django models.Model. 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 team_level (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.

+ +
## 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')
+
+# favor utilizar o código acima no seu projeto ao invés do que está abaixo
+## 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
+
+ +
+

Nota: Um pouquinho de Python:

+ + +
+ +

Consultando dados (views.py)

+ +

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").

+ +

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 team_level possui exatamente o texto 'U09' (observe como esse critério é passado para a função  filter()  com o argumento no campo de nome e o tipo de busca de correspondência (exact) separado por um sublinhado duplo: (team_level__exact).

+ +
## filename: views.py
+
+from django.shortcuts import render
+from .models import Team
+
+def index(request):
+    list_teams = Team.objects.filter(team_level__exact="U09")
+    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):
+    lista_times = Team.objects.filter(team_level__exact="U09")
+    contexto = {'times_jovens': lista_times}
+    return render(request, '/best/index.html', contexto)
+
+ +
+
+ +

A função index() usa a função render() para criar o HttpResponse 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 "context"). Na próxima seção, mostramos como os dados são inseridos no modelo para criar HTML.

+ +

Renderizando dados (Modelos HTML)

+ +

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).

+ +

O trecho de código mostra a aparência do modelo HTML chamado pela função render() na seção anterior. Este modelo foi escrito sob a premissa de que ele terá acesso a uma variável do tipo lista chamada youngest_teams quando for renderizada (contida na variável context dentro da função render() acima). Dentro do esqueleto HTML, temos um a expressão que primeiro verifica se a variável youngest_teams existe e a itera em um loop for. Em cada iteração, o modelo exibe o valor team_name de cada equipe em um elemento {{htmlelement("li")}}.

+ +
## 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>
+
+ +

O que mais você pode fazer?

+ +

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:

+ + + +

Resumo

+ +

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.

+ +

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.

+ +
{{NextMenu("Learn/Server-side/Django/development_environment", "Learn/Server-side/Django")}}
+ +

Neste módulo

+ + 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 +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django")}}
+ +

Este artigo mostra como definir os modelos para o website LocalLibrary. 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.

+ + + + + + + + + + + + +
Pré-requisitos:Django Tutorial Part 2: Criar um esqueleto de um site.
Objetivo:Ser capaz de projetar e criar seus próprios modelos, escolhendo os campos de forma apropriada.
+ +

Visão Geral

+ +

Aplicativos Django acessam e gerenciam dados através de objetos Python chamados de modelos (models). Modelos definem a estrutura 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ê.

+ +

Este tutorial mostra como definir e acessar os modelos para o website LocalLibrary website.

+ +

Projetando os modelos para o website LocalLibrary

+ +

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.

+ +

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.

+ +

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.

+ +

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.

+ +

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 (OneToOneField), um pra muitos (ForeignKey) e muitos pra muitos (ManyToManyField).

+ +

Com isso em mente, os diagramas UML de associação, mostram abaixo os modelos que definiremos nesse caso (como caixas).

+ +

LocalLibrary Model UML

+ +

Como acima, criamos modelos para Book (que contém os detalhes genéricos do livro),
+ BookInstance (contém os status das cópias físicas e específicas dos livros disponíveis no sistema) e Author. Também decidimos ter um modelo para o gênero (Genre), para que os valores possam ser criados/selecionados através da interface administrativa. Decidimos não ter um modelo para o BookInstance: status - pois, codificamos os valores em (LOAN_STATUS) 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.

+ +

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 Book e um Genre estão relacionados. Os números próximos ao modelo Genre 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 Book mostram que um gênero pode ter zero ou muitos livros associados.

+ +
+

Nota: 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.

+
+ +

Model primer

+ +

Esta seção fornece uma breve visão sobre como um modelo é definido e alguns dos mais importantes campos e argumentos dos campos.

+ +

Definição do Modelo

+ +

Modelos são geralmente definidos no arquivo models.py em uma aplicação. Eles são implementados como subclasse de django.db.models.Model, e podem incluir campos, métodos e metadados. O fragmento de código abaixo, mostra um modelo "típico", chamado MyModelName:

+ +
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
+ +

Nas seções abaixa, exploraremos detalhadamente cada um dos recursos dentro do modelo:

+ +

Campos (Fields)

+ +

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:

+ +
my_field_name = models.CharField(max_length=20, help_text='Enter field documentation')
+ +
+
Nosso exemplo acima tem um único campo chamado my_field_name, do tipo models.CharField - 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:
+ +
+
+ + + +

O nome do campo é usado para se referir a ele em consultas e modelos. Os campos também têm um rótulo, que é especificado como um argumento (verbose_name) ou inferido ao capitalizar a primeira letra do nome da variável do campo e substituindo quaisquer sublinhados por um espaço (por exemplo, my_field_name teria um rótulo padrão de My field name).

+ +

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.

+ +
Argumentos comuns de um campo
+ +

Os seguintes argumentos são comuns e podem ser usados quando declaramos muitos ou a maioria dos diferentes tipos de campos:

+ + + +

Existem muitas outras opções - você pode ver a lista completa de opções aqui.

+ +
Tipos comuns de um campo
+ +

A lista a seguir descreve alguns dos tipos de campos mais usados.

+ + + +

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 lista completa AQUI.

+ +

Metadados (metadada)

+ +

Você pode declarar o nível de modelo para os metadados declarando class Meta, como mostrado.

+ +
class Meta:
+    ordering = ['-my_field_name']
+
+ +

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 (ordering) 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.

+ +

Então, como exemplo, se optássemos por ordenar livros como este por padrão:

+ +
ordering = ['title', '-pubdate']
+ +

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.

+ +

Outro atributo comum é verbose_name, um nome detalhado para a classe no singular e plural:

+ +
verbose_name = 'BetterName'
+ +

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).

+ +

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).

+ +

A lista completa de opções de metadados pode ser encontrada aqui: Opções de modelos de metadados (Django docs).

+ +

Métodos

+ +

Um modelo também pode ter métodos.

+ +

Minimamente, em cada modelo você deve definir o método de classe padrão do Python __str__() para retornar uma string legível para cada objeto. 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.

+ +
def __str__(self):
+    return self.field_name
+ +

Outro método comum a incluir nos modelos do Django é o get_absolute_url(), 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 get_absolute_url () é mostrado abaixo.

+ +
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)])
+
+ +
+

Nota: Supondo que você usará URLs como / myapplication / mymodelname / 2 para exibir registros individuais para seu modelo (onde "2" é o id 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 reverse () acima é capaz de "inverter" seu mapeador de url (no caso acima chamado 'model-detail-view') para criar uma URL do formato correto.

+ +

Claro que para fazer este trabalho você ainda tem que escrever o mapeamento de URL, visão e modelo!

+
+ +

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).

+ +

Gestão de modelos

+ +

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.

+ +

Criando e modificando registros

+ +

Para criar um registro, você pode definir uma instância do modelo e, em seguida, chamar save ().

+ +
# 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()
+
+ +
+

Nota: 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.

+
+ +

Você pode acessar os campos nesse novo registro usando a sintaxe de ponto e alterar os valores. Você precisa chamar save () para armazenar valores modificados no banco de dados.

+ +
# 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()
+ +

Procurando por registros

+ +

Você pode procurar registros que correspondam a um determinado critério usando o atributo de objetos do modelo (fornecido pela classe base).

+ +
+

Nota: 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 nome de campo.

+
+ +

Podemos obter todos os registros para um modelo como um QuerySet, usando objects.all (). O QuerySet é um objeto iterável, o que significa que ele contém um número de objetos que podemos iterar / percorrer.

+ +
all_books = Book.objects.all()
+
+ +

O método filter () do Django nos permite filtrar o QuerySet retornado para corresponder a um campo especificado de texto ou numérico 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.

+ +
wild_books = Book.objects.filter(title__contains='wild')
+number_wild_books = Book.objects.filter(title__contains='wild').count()
+
+ +

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. é aqui.

+ +

Em alguns casos, você precisará filtrar um campo que defina um relacionamento um-para-muitos com outro modelo (por exemplo, uma ForeignKey). 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 nome por meio do campo de gênero, conforme mostrado abaixo:

+ +
# Combinará em: ficção, ficção científica, não-ficção etc.
+books_containing_genre = Book.objects.filter(genre__name__icontains='fiction')
+
+ +
+

Nota: Você pode usar sublinhados (__) para navegar quantos níveis de relacionamentos (ForeignKey / ManyToManyField) desejar. Por exemplo, um Livro que tinha tipos diferentes, definidos usando um relacionamento "cover" adicional, pode ter um nome de parâmetro: type__cover__name__exact = 'hard'.

+
+ +

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 Fazendo consultas (Django Docs).

+ +

Definindo os modelos LocalLibrary

+ +

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.

+ +
from django.db import models
+
+# Create your models here.
+ +

Genre model

+ +

Copie o código do model Genre , que aparece a baixo, e cole no seu arquivo models.py , 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.

+ +
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
+ +

O model tem apenas um campo do tipo CharField (name), que é usado para descrever o genero (esse campo é limitado a 200 caracteres e tem um help_text). No final da classe Genre declaramos o metodo  __str__() que retorna o nome do genero definido por um registro especifico. Não foi definido um argumento verbose_name , assim o campo será referenciado como  Name nos forms.

+ +

Book model

+ +

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 CharField para representar o  title (tílutlo) do livro e o isbn (veja que o isbn 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 TextField para o campo summary porque ele precisa ser um tanto longo.

+ +
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)])
+ +

Genre é um campo ManyToManyField, 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 ForeignKey, 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!)

+ +

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 author é null=True, o qual permite ao banco de dados armazer um valor Null se nenhum autor for selecionado, e, on_delete=models.SET_NULL, o qual definirá o valor author como Null se o registro do autor associado for excluído.

+ +

O mode também defini __str__(), usando o title do livro para representar o registro do Book. O método final, get_absolute_url(), 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 book-detail e associá-la a uma view e a um template.).

+ +

BookInstance model

+ +

Em seguida, copie o modelo BookInstance (exibido a abaixo) depois dos outros modelos. O BookInstance 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.

+ +

Alguns dos campos e métodos serão familiares agora. O model usa

+ + + +
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})'
+ +

Nós declaramos adicionalmente alguns tipos novos de campos:

+ + + +

O model __str__() representa o objeto BookInstance usando a combinação do seu id único e o título do Book associado.

+ +
+

Nota: Um pouco sobre Python:

+ + +
+ +

Author model

+ +

Copie o model Author (exibido abaixo) na sequência do código existente em  models.py.

+ +

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 __str__() retorna por default sobrenome e nome, nesta ordem. O método get_absolute_url() reverte o mapaeamento da URL author-detail para obter a URL de display individual author.

+ +
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}'
+
+
+ +

Rode novamente a migração do banco de dados

+ +

Todos os modelos foram criados. Agora rode a migração do banco de dados para adicioná-los ao seu banco de dados.

+ +
python3 manage.py makemigrations
+python3 manage.py migrate
+ +

Language model — desafio

+ +

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.

+ +

Algumas coisas a considerar:

+ + + +

Depois de decidido, adicione o campo. Pode ser visto o que decidimos no Github aqui.

+ + + + + +

Resumo

+ +

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  LocalLibrary.

+ +

Neste ponto faremos um rápido desvio da criação do site para ver o Django Administration site. 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).

+ +

Veja também

+ + + +

{{PreviousMenuNext("Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django")}}

+ +

Neste módulo

+ + diff --git "a/files/pt-br/learn/server-side/django/sess\303\265es/index.html" "b/files/pt-br/learn/server-side/django/sess\303\265es/index.html" new file mode 100644 index 0000000000..f2f16b521f --- /dev/null +++ "b/files/pt-br/learn/server-side/django/sess\303\265es/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 +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django/authentication_and_sessions", "Learn/Server-side/Django")}}
+ +
Esse tutorial estende nosso site LocalLibrary, 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.
+ +
+ + + + + + + + + + + + +
Pré-requisitos:Completar todos os tópicos anteriores do tutorial, incluindo Django Tutorial Part 6: Generic list and detail views
Objetivo:Entender como as sessões são usadas.
+ +

Visão Geral

+ +

O site LocalLibrary 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.

+ +

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 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).

+ +
+
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.
+
+ +

O que são sessões?

+ +

Toda a comunicação entre os navegadores web e os servidores é feita via protocolo HTTP, qual é stateless (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. 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.

+ +

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.

+ +

O Django usa um cookie contendo um identificador 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".

+ +

Habilitando as Sessões

+ +

As sessões foram ativadas automaticamente quando criamos o esqueleto do site (no tutorial 2).

+ +

A configuração e feita nas seções INSTALLED_APPS e MIDDLEWARE do arquivo (locallibrary/locallibrary/settings.py), exibidas a seguir:

+ +
INSTALLED_APPS = [
+    ...
+    'django.contrib.sessions',
+    ....
+
+MIDDLEWARE = [
+    ...
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    ....
+ +

Usando Sessões

+ +

Você pode acessar o atributo session na view a partir do parâmetro request (um HttpRequest passado como primeiro argumento na view). Esse atributo de sessão representa a conexão atual específica com um usuário (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).

+ +

O atributo session é 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.

+ +

O fragmento de código abaixo mostra como você pode obter, setar e deletar qualquer dado com com a chave "my_car", associada com a sessão atual (navegador).

+ +
+

Nota: 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 my_car estão associadas apenas com o navegador que enviou a requisição atual.

+
+ +
# 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']
+
+ +

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 How to use sessions (documentação do Django).

+ +

Salvando os dados da sessão

+ +

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 é modificada (atribuida) ou deletada. 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:

+ +
# This is detected as an update to the session, so session data is saved.
+request.session['my_car'] = 'mini'
+ +

Se você está atualizando algumas informações dentro 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  "wheels"  dentro dos dados do seu "my_car", como mostrado abaixo). Nesse caso você precisará marcar explicitamente a sessão como tendo sido modificada.

+ +
# 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.
+request.session.modified = True
+
+ +
+

Nota: Você pode mudar o comportamento do site para atualizar a base de dados/enviar cookie em qualquer requisição adicionando SESSION_SAVE_EVERY_REQUEST = True nas configurações (locallibrary/locallibrary/settings.py) do seu projeto.

+
+ +

Exemplo simples - obtendo a contagem de visitas

+ +

Como um exemplo simples do mundo real, atualizaremos nossa biblioteca para informar ao usuário atual quantas vezes ele visitou o site LocalLibrary

+ +

Abra /locallibrary/catalog/views.py, e faça as alterações mostradas em negrito abaixo.

+ +
def index(request):
+    ...
+
+    num_authors = Author.objects.count()  # The 'all()' is implied by default.
+
+    # 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
+
+    context = {
+        'num_books': num_books,
+        'num_instances': num_instances,
+        'num_instances_available': num_instances_available,
+        'num_authors': num_authors,
+        'num_visits': num_visits,
+    }
+
+    # Render the HTML template index.html with the data in the context variable.
+    return render(request, 'index.html', context=context)
+ +

Aqui primeiro obtemos o valor da  session key 'num_visits', 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 num_visits é então passada para o template na nossa varável context.

+ +
+

Nota: Também podemos testar se os cookies são suportados no navegador (veja Como usar sessões para exemplos) ou projetar nossa UI (interface do usuário) para que não se importe se os cookies são ou não suportados.

+
+ +

Adicione a linha vista na parte inferior do bloco a seguir ao seu template HTML principal (/locallibrary/catalog/templates/index.html) na parte inferior da sessão "Dynamic content", para exibir a variável context:

+ +
<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>
+
+<p>You have visited this page \{{ num_visits }}{% if num_visits == 1 %} time{% else %} times{% endif %}.</p>
+
+ +

Salve suas alterações e reinicie o servidor de teste. Sempre que você atualiza a página, o número deve ser atualizado.

+ + + +

Resumo

+ +

Agora você sabe como é fácil utilizar sessões para melhorar sua interação com usuários anônimos. 

+ +

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.

+ +

Veja também

+ + + +

{{PreviousMenuNext("Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django/Authentication", "Learn/Server-side/Django")}}

+ +

Neste módulo

+ + 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 +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django/Models", "Learn/Server-side/Django")}}
+ +

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. 

+ + + + + + + + + + + + +
Pré-requisitos:Configurar um ambiente de desenvolvimento Django. Ter lido Tutorial Django: Website de uma Biblioteca Local.
Objetivo:Ser capaz de usar as ferramentas do Django para começar seus próprios novos projetos de websites.
+ +

Visão Geral

+ +

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).

+ +

O processo é direto:

+ +
    +
  1. Use a ferramenta django-admin para criar a pasta do projeto, arquivos de template básicos, e o script de gestão do projeto (manage.py).
  2. +
  3. Use o script manage.py para criar um ou mais aplicativos. +
    +

    Nota: 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.

    +
    +
  4. +
  5. Registre os novos aplicativos para inclui-los no projeto.
  6. +
  7. Conecte o mapeador de url/path para cada aplicativo.
  8. +
+ +

Para o  website Biblioteca Local a pasta do website e a pasta do projeto terão, ambas, o nome locallibrary, e nós teremos apenas um aplicativo chamado catalog. O nível hierárquico mais alto da estrutura de pastas ficará assim:

+ +
locallibrary/         # Pasta do websitemanage.py        # Script para executara as ferramentas do Django para este projeto (criado utilizando o django-admin)
+    locallibrary/     # Pasta do project folder (criado utilizando o django-admin)
+    catalog/          # Pasta do aplicativo (criado utilizando o django-admin)
+
+ +

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.

+ +

Criando o projeto

+ +

Primeiro abra o prompt de comando/terminal t(enha certeza que está em seu ambiente virtual), navegue até o diretório que deseja colocar seus aplicativos Django (coloque em um lugar fácil de achar, como dentro da pasta documentos), e crie uma pasta para seu novo website (nesse caso: django_projects). Acesse então a pasta usando o comando cd:

+ +
mkdir locallibrary
+cd locallibrary
+ +

Crie um novo projeto usando o comando django-admin startproject, como mostrado abaixo, e entre nessa pasta.

+ +
django-admin startproject locallibrary
+cd locallibrary
+ +

O comando django-admin cria uma estrutura com pastas e arquivos como a mostrada abaixo:

+ +
locallibrary/
+    manage.py
+    locallibrary/
+        __init__.py
+        settings.py
+        urls.py
+        wsgi.py
+ +

Nosso diretório de trabalho atual deve parecer com isso:

+ +
../django_projects/locallibrary/
+ +

  A sub-pasta do projeto locallibrary será a raíz para nosso site:

+ + + +

O script manage.py é usado para criar aplicações, trabalhar com bancos de dados, e iniciar o webserver de desenvolvimento. 

+ + + +

Agora execute o seguinte comando para criar o catálogo da aplicação que fará parte de nosso projeto localibrary (o comando deve ser executado na mesma pasta que está o manage.py do seu projeto):

+ +
python3 manage.py startapp catalog
+ +
+

Nota: O comando acima é para Linux/macOS X. No windows o comando deve ser: py -3 manage.py startapp catalog

+ +

Se você  está trabalhando com o Windows, substitua python3 por py -3 ao longo deste módulo.

+ +

Se você está usando Python 3.7.0, use py manage.py startapp catalog

+
+ +

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 views.py, models em models.py, testes em tests.py, configurações de administração do site em admin.py, registro da aplicação em apps.py) e contém algum código mínimo para trabalhar com os objetos associados.

+ +

O diretório do projeto atualizado deve parecer com esse:

+ +
locallibrary/
+    manage.py
+    locallibrary/
+    catalog/
+        admin.py
+        apps.py
+        models.py
+        tests.py
+        views.py
+        __init__.py
+        migrations/
+
+ +

Além disso, nós temos:

+ + + +
+

Nota: 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).

+
+ + + +

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 INSTALLED_APPS que fica nas configurações do projeto.

+ +

Abra o arquivo de configurações do projeto locallibrary/locallibrary/settings.py e encontre a definição para a lista INSTALLED_APPS. Agora adicione uma nova linha no fim da lista, como a mostrada em negrito abaixo.

+ +
INSTALLED_APPS = [
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+    'catalog.apps.CatalogConfig', 
+]
+ +

A nova linha especifica o objeto de configuração do aplicativo (CatalogConfig) que foi gerado em /locallibrary/catalog/apps.py onde a aplicação foi criada.

+ +
+

Nota: Você deve ter notado que existem vários outros INSTALLED_APPS (e MIDDLEWARE, pelo final do arquivo de configuração). Eles permitem suporte para o site de administração do Django e, como resultado,  várias funcionalidades que ele utiliza (incluindo seções, autenticação etc).

+
+ +

Especificando o Banco de Dados

+ +

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 Databases (Documentação Django).

+ +

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 settings.py (mais informações estão incluidas abaixo).

+ +
DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.sqlite3',
+        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
+    }
+}
+
+ +

Já que nós estamos usando SQLite, nós não precisamos de nenhum outro passo aqui. Vamos ir em frente!

+ +

Outras configurações do projeto

+ +

O arquivo settings.py também é usado para configurar várias outras definições, mas por ora você provavelmente quer mudar apenas a TIME_ZONE — deve se utilizar uma string padrão da Lista de tz time zones (a coluna TZ na tabela contém os valores que você precisa). Mude seu valor de TIME_ZONE para uma string relativa ao seu fuso-horário, por exemplo:

+ +
TIME_ZONE = 'America/Sao_Paulo'
+ +

Tem outras duas definições que você não vai mudar agora, mas que deve ficar ciente:

+ + + +

Conectando o mapeador de URL

+ +

O website foi criado com um arquivo mapeador de URL (urls.py) 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.

+ +

Abra locallibrary/locallibrary/urls.py e leia o texto que explica alguma formas de usar o mapeador de URL.

+ +
"""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),
+]
+
+ +

Os mapeamentos de URL são gerenciados através da variável urlpatterns  que é uma lista Python de funções path(). Cada função path() associa um padrão de URL para uma view específica, 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 urlpatterns define inicialmente uma função única que mapeia todas URLs com o padrão admin para o módulo admin.site.urls, que contém as próprias definições de mapeamento de URL da área de administração do aplicativo.

+ +
+

Nota: A rota em path() é 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. 'catalog/<id>/'. Esse padrão corresponderá a uma URL como /catalog/any_chars/ e passa any_chars para a view como uma string com paramêtros nome id). Nós discutiremos métodos de caminho e padrões de rota ainda mais em tópicos posteriores

+
+ +

Adicione as linhas abaixo no fim do arquivo a fim de adicionar um novo item à lista urlpatterns. Esse novo item inclui um  path() que encaminha solicitações com o padrão catalog/ para o módulo catalog.urls (o arquivo com a URL relativa /catalog/urls.py). 

+ +
# 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')),
+]
+
+ +

Agora iremos mudar a URL raíz de nosso site (i.e. 127.0.0.1:8000) para 127.0.0.1:8000/catalog/; pois esse é o único app que iremos usar neste projeto. Para isso, usaremos uma função view especial (RedirectView), que leva como primeiro argumento a nova URL relativa para redirecionar para /catalog/ quando o padrão URL especificado na função path() for chamado (a URL raíz nesse caso).

+ +

Adicione as linhas abaixo, novamente no fim do arquivo:

+ +
#Add URL maps to redirect the base URL to our application
+from django.views.generic import RedirectView
+urlpatterns += [
+    path('', RedirectView.as_view(url='/catalog/')),
+]
+ +

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.

+ +
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 '/'.
+
+ +

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.

+ +

Coloque o seguinte bloco no fim do arquivo:

+ +
# 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)
+
+ +
+

Nota: Existem várias maneiras de estender a lista urlpatterns (acima nós acrecentamos uma nova lista de itens usando o operador += 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.

+ +
urlpatterns = [
+    path('admin/', admin.site.urls),
+    path('catalog/', include('catalog.urls')),
+    path('', RedirectView.as_view(url='/catalog/', permanent=True)),
+] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
+
+ +

Além disso, incluimos a linha para importação (from django.urls import include) 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.

+
+ +

Finalmente, crie um arquivo dentro da pasta catalog e dê o nome urls.py, adicione então o seguinte texto para definir um urlpatterns importado (e vazio). É aqui onde você adicionará nossos padrões enquanto desenvolvemos o aplicativo.

+ +
from django.urls import path
+from catalog import views
+
+
+urlpatterns = [
+
+]
+
+ +

Testando o framework do site

+ +

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.

+ +

Antes de começarmos, devemos primeiramente executar uma migração de banco de dados. Isso atualiza nosso banco de dados para incluir qualquer model em nossas aplicações instaladas (e remove avisos da build).

+ +

Migrando Bancos de Dados

+ +

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 /locallibrary/catalog/migrations/) para migrar automaticamente a estrutura de dados subjacente no banco de dados para manter a correnpondência com o model.

+ +

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 manage.py):

+ +
python3 manage.py makemigrations
+python3 manage.py migrate
+
+ +
+

Importante: 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).

+
+ +

O comando makemigrations cria (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!

+ +

O comando migrate aplica as migrações em seu banco de dados (Django rastreia quais foram adicionados ao banco de dados atual).

+ +
+

Nota: Leia Migrations (Documentação Django) para informações adicionais sobre os  comandos de migração menos usados.

+
+ +

Testando o website

+ +

Durante o desenvolvimento você pode testar o website usando o webserver de desenvolvimento, e vê-lo em seu navegador local.

+ +
+

Nota: 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 (http://127.0.0.1:8000/), mas você também pode especificar que outros computadores da rede acessem-o. Para mais informações acesse django-admin and manage.py: runserver (Documentação Django).

+
+ +

Execute o web server de desenvolvimento com o comando runserver (no mesmo diretório de manage.py):

+ +
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.
+
+ +

Com o servidor funcionando, você pode ver seu site colocando o endereço http://127.0.0.1:8000/ em seu navegador local. Você deve ver uma página de erro como essa:

+ +

Django Debug page for Django 2.0

+ +

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 catalogs.urls (que é para onde somos redirecionados quando usamos a URL para a raíz do site).

+ +
+

Nota: 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.

+
+ +

No momento basta saber que o Django está funcionando! 

+ +
+

Nota: Você deve executar novamente as migrações e testar o site sempre que fizer alguma mudança signifcante. Não demora muito!

+
+ +

Desafio

+ +

O diretório catalog/ 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). 

+ +

Como você viu acima, um mapeamento de URL para o site Admin já foi adicionado no arquivo urls.py do projeto. Vá à área do admin em seu navegador e veja o que acontece (você pode deduzir a URL correta para o mapeamento acima).

+ +

Sumário

+ +

Você acabou de criar um "esqueleto" para websties, agora você pode popular o site com URL's, models, views e templates.

+ +

Como o escopo para o website Local Library está completo e executando, é hora de começar a escrever códigos que farão o website realizar sua função.

+ +

Veja também

+ + + +

{{PreviousMenuNext("Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django/Models", "Learn/Server-side/Django")}}

+ +

Neste módulo

+ + 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 +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/Forms", "Learn/Server-side/Django/Deployment", "Learn/Server-side/Django")}}
+ +

À 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 framework de testes do Django.

+ + + + + + + + + + + + +
Pré-requisitos:Complete todos os tópicos de tutoriais anteriores, incluindo Tutorial Django Parte 9: Trabalhando com formulários.
Objetivo:Entender como escrever testes unitários para websites baseados em Django.
+ +

Visão Geral

+ +

Local Library atualmente tem páginas para mostrar listas de todos livros e autores, visualização detalhada para itens Book e Author, uma página para renovar BookInstances, e páginas para criar, atualizar e excluir itens Author (e também registros de Book, se você completou o desafio no forms tutorial). 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.

+ +

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 .

+ +

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. desenvolvimento guiado por testes e desenvolvimento guiado por comportamento).

+ +

Este tutorial mostra como escrever testes automatizados para Django, adicionando um número de testes para o website LocalLibrary.

+ +

Tipos de teste

+ +

Há inúmeros tipos, níveis, e classificações de testes e abordagens de testes. Os testes automatizados mais importantes são:

+ +
+
Testes unitários
+
Verifica o comportamento funcional de componentes individuais, geralmente ao nível de classe e função.
+
Testes de regressão
+
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.
+
Testes de integração
+
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.
+
+ +
+

Nota: 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), performance, carga (load) e testes de stress. Procure-os para mais informaçãos.

+
+ +

O que o Django fornece para testes?

+ +

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 template.

+ +

Django fornece um framework de teste com uma baixa hierarquia de classes construida na biblioteca padrão unittest de Python. Apesar do nome, este framework de teste é adequado para testes unitários e de integração. O framework 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 (LiveServerTestCase) e ferramentas para usar diferentes frameworks de teste, por exemplo, você pode integrar com o popular framework Selenium para simular um usuário interagindo com um navegador.

+ +

Para escrever um teste, você deriva de qualquer uma das classes base de teste de Django (ou unittest) (SimpleTestCaseTransactionTestCaseTestCaseLiveServerTestCase) e então escreve métodos separados para verificar se a funcionalidade específica funciona como esperado (testes usam métodos "assert" para testar se a expressão resulta em valores True ou False, 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 tear-down definido na classe, como mostrado abaixo.

+ +
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)
+
+ +

A melhor classe base para maioria dos testes é django.test.TestCase. 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 Client de teste, que você pode utilizar para simular um usuário interagindo com o código no nível de view. Nas seções a seguir vamos nos concentrar nos testes unitários, criados utilizando a classe base TestCase.

+ +
+

Nota: A classe django.test.TestCase é 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 view). 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.

+
+ +

O que você deve testar?

+ +

Você deve testar todos aspectos do seu próprio código, mas nenhuma biblioteca ou funcionalidade oferecida como parte do Python ou Django.

+ +

Assim por exemplo, conseidere o model Author definido abaixo. Você não precisa testar explicitamente se first_name e last_name foram armazenados corretamente como CharField 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 date_of_birth foi validado para ser um campo de data, porque isso novamente é algo implementeado no Django.

+ +

No entanto, você deve verificar o texto utilizado para os labels (First name, Last name, Date of birth, Died), e o tamanho do campo alocado para o texto (100 caracteres), porque isso faz parte do seu design e algo que pode ser violado/alterado no futuro.

+ +
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)
+ +

Similarmente, você deve verificar se os métodos personalizados  get_absolute_url() e __str__() se comportam como desejado, porque els são sua lógica de código/negócios. No caso de get_absolute_url() você pode confiar que o método reverse() de Django, foi implementado corretamente, portanto, o que você esta testando é se a view associada foi realmente definida.

+ +
+

Nota: 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 form (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).

+
+ +

Com isso em mente, vamos começar a ver como definir e executar testes.

+ +

Visão geral da estrutura de teste

+ +

Antes de entrarmos nos detalhes de "o que testar", vamos primeiro examinar brevemente onde e como os testes são definidos.

+ +

Django usa o módulo unittest com descoberta de teste acoplada, que descrobrirá testes no diretório de trabalho atual em qualquer arquivo nomeado com o padrão test*.py. 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 models, views, forms e qualquer outro tipo de código que você precise testar. Por exemplo:

+ +
catalog/
+  /tests/
+    __init__.py
+    test_models.py
+    test_forms.py
+    test_views.py
+
+ +

Crie uma estrutura de arquivos como mostrado acima em seu projeto LocalLibrary. O __init__.py 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" /catalog/tests.py.

+ +
+

Nota: O arquivo de teste /catalog/tests.py do "esqueleto", foi criado automaticamente quando nós construimos o "esqueleto" do website Django. É 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.

+ +

Exclua o arquivo do "esqueleto", pois não precisamos dele.

+
+ +

Abra /catalog/tests/test_models.py. O arquivo deve importar django.test.TestCase, como mostrado:

+ +
from django.test import TestCase
+
+# Create your tests here.
+
+ +

Frequentemente, você adicionará uma classe de teste para cada model/view/form 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 model é 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.

+ +

Adicione a classe de teste abaixo na parte inferior do arquivo. A classe demonstra como construir uma classe de teste derivando de TestCase.

+ +
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)
+ +

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):

+ + + +
+

As classes de teste também têm um método tearDown(), que não usamos. Este método não é particularmente útil para testes de banco de dados, pois a classe base TestCase cuida da desmontagem do banco de dados para você.

+
+ +

Abaixo desses, temos vários métodos de teste, que usam funções Assert para testar se as condições são verdadeiras, falsas ou iguais (AssertTrue, AssertFalse, AssertEqual). Se a condição não for avaliada como esperado, então o teste falhará e reportará o erro ao seu console.

+ +

AssertTrue, AssertFalse, AssertEqual são assertivas padrão fornecidas pelo unittest. Existem outras assertivas padão no framework e também Django especifica assertivas para testar se uma view redireciona (assertRedirects), para testar se um template específico foi utilizado (assertTemplateUsed), etc.

+ +
+

Você normalmente não deve incluir funções print() 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).

+
+ +

Como executar os testes

+ +

A maneira mais fácil para executar todos os testes é usar o comando:

+ +
python3 manage.py test
+ +

Isso descobrirá todos arquivos nomeados com o padrão test*.py no diretório atual e executará todos testes definidos usando as classes base apropriadas (aqui temos vários arquivos de teste, mas, atualmente, apenas  /catalog/tests/test_models.py contém testes). Por padrão, os testes irão reportar individualmente apenas falhas no teste, seguidos por um resumo do teste.

+ +
+

Se você obter erros semelhantes a: ValueError: Missing staticfiles manifest entry ... isso pode ocorrer porque o teste não é executado como collectstatic por padrão e seu app está usando uma classe de armazenamento que exige isto (veja manifest_strict para mais informações). Existem várias maneiras de solucionar esse problema - o mais fácil é simplesmente executar collectstatic antes de executar os testes:

+ +
python3 manage.py collectstatic
+
+
+ +

Execute os testes no diretório raiz de LocalLibrary. Você deve ver uma saída como a abaixo.

+ +
> python3 manage.py test
+
+Creating test database for alias 'default'...
+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.
+.
+======================================================================
+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'...
+ +

Aqui vemos que tivemos uma falha no teste e podemos ver exatamente qual função falhou e por quê (essa falha é esperada, porque False não é True!).

+ +
+

Dica: 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.

+
+ +

O texto acima mostrado em negrito normalmente não apareceria na saída do teste (isso é gerado pelas funções print() em nossos teste). Isso mostra como o método  setUpTestData() é chamdo uma vez para classe e setUp() é chamado antes de cada método.

+ +

As próximas seções mostram como você pode executar testes específicos e como controlar quanta infromação os testes exibem.

+ +

Mostrando mais informações de teste

+ +

Se você deseja obter mais informação sobre a execução do teste, você pode mudar  a verbosidade (verbosity). 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 verbosity para "2" como mostrado:

+ +
python3 manage.py test --verbosity 2
+ +

Os níveis permitidos de verbosity são 0, 1, 2, e 3, com o padrão sendo "1".

+ +

Executando testes específicos

+ +

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 TestCase ou método:

+ +
# 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
+
+ +

Testes da LocalLibrary

+ +

Agora que sabemos como executar nosso testes e que tipo de coisas precisams testar, vamos ver alguns exemplos práticos.

+ +
+

Nota: 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.

+
+ +

Models

+ +

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.

+ +

Por exemplo, considere o model Author abaixo. Aqui devemos testar os labels 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 labels 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.

+ +
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}'
+ +

Abra nosso /catalog/tests/test_models.py, e substitua qualquer código existente pelo seguinte código de teste para o model Author.

+ +

Aqui você verá que primeiro importamos TestCase e derivamos nossa classe de teste (AuthorModelTest) 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 setUpTestData() para criar um objeto autor que iremos usar mas não modificaremos em nenhum dos testes.

+ +
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')
+ +

Os testes de campo verificam se os valores dos labels dos campos (verbose_name)  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:

+ +
# 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')
+ +

As coisas interessantes a serem observadas aqui:

+ + + +
+

Nota: Testes para os rótulos last_name e date_of_birth e também para o teste para o tamanho do last_name field foram omitidos. Adicione suas próprias versões agora, seguindo as convenções de nomeclatura e abordagens mostradas acima.

+
+ +

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 Author é o que esperávamos.

+ +
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')
+ +

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 label date_of_death como mostrado abaixo. O teste está falhando porque foi escrito esperando que a definição do label siga a convenção do Django de não colocar em maíúscula a primeira letra do label (Django faz isso por você).

+ +
======================================================================
+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
+? ^
+ +

Este é um bug muito pequeno, mas destaca como a escrita de testes pode verificar mais minuciosamente quaislquer suposições que você tenha feito.

+ +
+

Nota: Altere o label para o campo date_of_death (/catalog/models.py) para "died" e re-executes os testes.

+
+ +

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.

+ +

Forms

+ +

A filosofia para testar seus forms é a mesma que para testar seus models; 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

+ +

Geralmente, isso significa que você deve testar se os forms têm os campos que você deseja e se esses são exibidos com os labels  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.

+ +

Considere nosso form para renovação de livros. Ele tem apenas um campo para data de renovação, que terá um label e um texto de ajuda que precisaremos verificar.

+ +
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
+ +

Abra nosso arquivo /catalog/tests/test_forms.py e substitua qualquer código existente pelo seguinte código de teste para o form RenewBookForm. Nós iniciamos importando nosso form e algumas bibliotecas Python e Django para ajudar testar funcionalidades relacionadas ao tempo. Em seguida, declaramos nossa classe de teste do form, da mesma maneira que fizemos para models,  usando um nome descritivo para a classe de teste derivada de TestCase.

+ +
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())
+
+ +

As primeiras duas funções testam se os campos label e help_text são como esperados. Temos que acessar o campo usando o dicionário de campos (ex. form.fields['renewal_date']). Observe aqui que também precisamos testar se o valor do label é None, porque mesmo que o Django processe o label correto, retornará None se o valor não estiver definido explicitamente.

+ +

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 (datetime.date.today()) usando datetime.timedelta() (nesse caso, especificando um número de dias ou semanas). Então, apenas criamos o form, passando nossos dados e testando se é válido.

+ +
+

Nota: Aqui, na realidade, não usamos o banco de dados ou cliente teste. Considere modificar essses testes para utilizar SimpleTestCase.

+ +

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.

+
+ +

Isso é tudo para forms; nós temos alguns outros, mas eles são automaticamente criados pelas nossas views de edição baseada na classe genérica, e devem ser testadas lá! Execute os testes e confirme  se nosso código ainda passa!

+ +

Views

+ +

Para validar o comportamento das nossas views, utilzamos Client de teste do Django. Essa classe funciona como um navegador web fictício que podemos usar para simular requisições GET and POST 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 template 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 view esta fazendo o que é esperado.

+ +

Vamos iniciar com uma de nossas views mais simples, que fornece uma lista de todos Autores. Isso é exibido na URL /catalog/authors/ (uma URL chamada 'authors' na configuração de URL).

+ +
class AuthorListView(generic.ListView):
+    model = Author
+    paginate_by = 10
+
+ +

Como esta é uma list view 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 view é 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 view exibe todos Autores, paginando-os em lotes de 10.

+ +

Abra o arquivo /catalog/tests/test_views.py e substitua qualquer texto existente pelo seguinte código de teste para AuthorListView. Como antes, importamos nosso model e algumas classe úteis. No método setUpTestData() configuramos vários objetos Author para que possamos testar nossa paginação.

+ +
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)
+ +

Todos os teste usam o cliente (pertenecente a nossa classe derivada TestCase's) para simular uma requisição GET 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.

+ +
response = self.client.get('/catalog/authors/')
+response = self.client.get(reverse('authors'))
+
+ +

Uma vez que temos a resposta, consultamos o seu código de status, o template usado, se a resposta é paginada ou não, o número de itens retonado e o número total de itens.

+ +
+

Nota: Se você definir a variável paginate_by em seu arquivo  /catalog/views.py para um número diferente de 10, atualize as linhas que testam se o número correto de itens é exibido nos templates 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:

+ +
self.assertTrue(len(response.context['author_list']) == 5)
+
+
+ +

A variável mais importante que demonstramos acima é response.context, que é a variável de contexto passada para o template pela view. 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 template pretendido e quais dados o template está obtendo, o que ajuda bastante a verificar que alguns problemas de renderização são apenas devido ao template.

+ +

Views restritas a usuários logados

+ +

Em alguns casos, você desejará testar uma view que é restrita apenas aos usuários logados. Por exemplo, nossa LoanedBooksByUserListView é muito similar a nossa view anterior, mas está disponível apenas para usuários logados e exibe apenas os registros BookInstance que são emprestados pelo usuário atual, têm o status 'emprestado' e são ordenados "mais antigos primeiro".

+ +
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')
+ +

Adicione o código seguinte ao /catalog/tests/test_views.py. Aqui, primeiro usamos SetUp() para criar alguma contas de login de usuário e objetos BookInstance (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 SetUp() em vez de setUpTestData() porque modificaremos alguns desses objetos depois.

+ +
+

Nota: O código setUp() abaixo, cria um livro com uma  Language especificada, mas seu código pode não incluir o model Language, pois foi criado como um desafio. Se esse for o caso, simplesmente comente as partes do código que cria ou importa objetos Language. Você também deve fazer isso na seção  RenewBookInstancesViewTest a seguir.

+
+ +
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')
+
+ +

Para verificar se a view será redirecionada para uma página de login se o usuário não estiver logado, usamos assertRedirects, como demonstrado em test_redirect_if_not_logged_in(). 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 status_code de 200 (successo). 

+ +

O restante dos testes verificam se nossa view retorna apenas livros emprestados ao nosso usuário atual. Copie o código abaixo e cole no final da classe de teste acima.

+ +
    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
+ +

Você também pode adicionar testes de paginação, se desejar!

+ +

Testando views com forms

+ +

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 views somente de exibição.

+ +

Para demonstrar, vamos escrever alguns testes para a view usada para renovar livros (renew_book_librarian()):

+ +
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)
+ +

Precisamos testar se a view está disponível apenas para usuários que têm a permissão can_mark_returned , e se eles são direcionados para uma página de erro HTTP 404 se tentarem renovar um BookInstance 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 view "all-borrowed books". Como parte da verificação dos testes de falha de validação, também verificaremos se nosso form está enviando mensagens de erro apropriadas.

+ +

Adicione a primeira parte da classe de teste (mostrada abaixo) na parte inferior de /catalog/tests/test_views.py. 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 view. O código para conceder permissões durante os testes é mostrado em negrito:

+ +
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()
+
+        permission = Permission.objects.get(name='Set book as returned')
+        test_user2.user_permissions.add(permission)
+        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 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',
+        )
+ +

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 view. 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 BookInstance que não existe. Também verificamos se o template correto é utilizado.

+ +
   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')
+
+ +

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).

+ +
    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.context['form'].initial['renewal_date'], date_3_weeks_in_future)
+
+ +
+

Se você usar a classe form RenewBookModelForm(forms.ModelForm) em vez da classe RenewBookForm(forms.Form), então o nome do campo do form será 'due_back' em vez de 'renewal_date'.

+
+ +

O próximo teste (adicione isso a classe também) verifica se a view 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 POST de dados usando o cliente. Os dados do post são o segundo argumento da função post, e são especificados como um dicionário de chave/valores.

+ +
    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)
+        response = self.client.post(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}), {'renewal_date':valid_date_in_future})
+        self.assertRedirects(response, reverse('all-borrowed'))
+
+ +
+

A view all-borrowed foi adicionada como um desafio, 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 follow=True na solicitação, garante que a solicitação retorna a URL final de destino (portanto verifique /catalog/ em vez de /).

+ +
 response = self.client.post(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}), {'renewal_date':valid_date_in_future}, follow=True )
+ self.assertRedirects(response, '/catalog/')
+
+ +

Copie as última duas funções para a classe, como visto abaixo. Elas testam novamente as requisições POST, mas nesse caso, com datas inválidas de renovação. Utilizamos assertFormError() para verificar se as mensagens de erro são as esperadas.

+ +
    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)
+        self.assertFormError(response, 'form', 'renewal_date', 'Invalid date - renewal in past')
+
+    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)
+        self.assertFormError(response, 'form', 'renewal_date', 'Invalid date - renewal more than 4 weeks ahead')
+
+ +

Os mesmos tipos de técnicas podem ser usadas para testar a outra view.

+ +

Templates

+ +

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.

+ +

Outras ferramentas de teste recomendadas

+ +

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 unittest pode fazer, muito menos as adições de Django (por exemplo, confira como você pode usar unittest.mock para corrigir bibliotecas de terceiros para que você possa testar mais detalhadamente seu próprio código).

+ +

Embora existam inúmeras outras ferramentas de teste que você pode utilizar, destacaremos apenas duas:

+ + + +

Desafie-se

+ +

Existem muito mais models e views que podemos testar. Como uma tarefa simples, tente criar um caso de teste para a view AuthorCreate.

+ +
class AuthorCreate(PermissionRequiredMixin, CreateView):
+    model = Author
+    fields = '__all__'
+    initial = {'date_of_death':'12/10/2016'}
+    permission_required = 'catalog.can_mark_returned'
+ +

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 template utilizado e para onde a view é redirecionada quando bem-sucedida.

+ +

Resumo

+ +

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 release após fazer alterações e de baixo custo de manutenção.

+ +

Neste tutorial, mostramos como escrever e executar testes para seus models, forms e views. 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.

+ +

O próximo e último tutorial mostra como você pode implantar seu maravilhoso (e totalmente testado!) website Django.

+ +

Veja também

+ + + +

{{PreviousMenuNext("Learn/Server-side/Django/Forms", "Learn/Server-side/Django/Deployment", "Learn/Server-side/Django")}}

+ +

Neste módulo

+ + 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 +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/development_environment", "Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django")}}
+ +

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.

+ + + + + + + + + + + + +
Pré-requisitos:Ler a introdução ao Django. Para os próximos artigos você também necessitará ter montando o ambiente de desenvolvimento para o Django.
Objetivo:Introduzir o exemplo da aplicação usado neste tutorial, e permitir que os leitores entendam quais tópicos serão abordados.
+ +

Visão geral

+ +

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.

+ +

Nessa série de artigos você irá:

+ + + +

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.

+ +

Website da Biblioteca Local - LocalLibrary

+ +

LocalLibrary é 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.

+ +

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 guiado através da funcionalidade mais importante do estrutura web do Django:

+ + + +

Embora este seja um exemplo extenso, ele é chamado Biblioteca Local 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".

+ +

Onde posso obter o código fonte?

+ +

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).

+ +

Se você travar, a versão completa do website pode ser encontrada aqui no Github.

+ +

Resumo

+ +

Agora que você sabe um pouco mais sobre o website LocalLIbrary e o que você irá aprender, é hora de começar a criar um escopo do projeto.

+ +

{{PreviousMenuNext("Learn/Server-side/Django/development_environment", "Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django")}}

+ + + +

Neste módulo

+ + 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 +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Django/Deployment", "Learn/Server-side/Django/django_assessment_blog", "Learn/Server-side/Django")}}
+ +

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 Web security — esse artigo fornece uma demonstração prática de como as proteções internas de Django lidam com essas ameaças.

+ + + + + + + + + + + + +
Pré-requisitos:Ler o tópico "Website security" de Programação Server-side. Conclua os tópicos do tutorial Django tutorial até (e incluindo) pelos menos Tutorial Django Parte 9: Trabalhando com formulários.
Objective:Para entender as principais coisas que você precisa fazer (ou não fazer) para proteger seu aplicatico web Django.
+ +

Visão geral

+ +

O tópico Website security 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.

+ +
+

Importante: A lição mais importante que você pode aprender sobre segurança de website é nunca confiar nos dados do navegador. Isso inclui dados de requisição GET em parâmetros de URL, dados POST, cabeçalhos HTTP e cookies, arquivos enviados por usuários, etc. Sempre verifique e "desinfete" todos os dados recebidos. Sempre assuma o pior.

+
+ +

A boa notícia para usuários Django é que muitas das ameaças mais comuns são tratadas pelo framework! O artigo Segurança no Django (Django docs) explica os recursos de segurança e como proteger um website desenvolvido pelo Django.

+ +

Ameaças/proteções comuns

+ +

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 LocalLibrary.

+ +

Cross site scripting (XSS)

+ +

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.

+ +

O sistema de templates do Django protege você da maioria dos ataques XSS escapando de caracteres específicos que são "perigosos" em HTML. Podemos demonstrar isso tentando injetar algum JavaScript em nosso website LocalLibrary  usando o form Create-author que configuramos em Django Tutorial Parte 9: Trabalhando com formulários.

+ +
    +
  1. Inicie o website usando o servidor de desenvolvimento (python3 manage.py runserver).
  2. +
  3. Abra o site em seu navegador local e faça login em sua conta de superusuário.
  4. +
  5. Navegue até a página de criação do autor (que deve estar na URL: http://127.0.0.1:8000/catalog/author/create/).
  6. +
  7. Digite os nomes e os detalhes de data para um novo usuário, e então acrescente o seguinte texto no campo Last Name :
    + <script>alert('Test alert');</script>.
    + Author Form XSS test +
    +

    Nota: 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.

    +
    +
  8. +
  9. Pressione Submit para salvar o registro.
  10. +
  11. Quando você salvar o autor, ele será exibido como mostrado abaixo. Por causa das proteções XSS o alert() não deve ser executado. Em vez disso o script é exibido como texto simples.Author detail view XSS test
  12. +
+ +

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. > agora é &gt;)

+ +
<h1>Author: Boon&lt;script&gt;alert(&#39;Test alert&#39;);&lt;/script&gt;, David (Boonie) </h1>
+
+ +

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 help_text em um campo de formulário normalmente não é preechido pelo usuário, então Django não escapa esses valores).

+ +

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.

+ +

Proteção contra Cross site request forgery (CSRF) 

+ +

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.

+ +
+

Nota: 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.)

+
+ +

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.

+ +
<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>
+
+ +

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!

+ +

A forma como a proteção é habilitada é incluindo a tag de template {% csrf_token %} 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.

+ +
<input type='hidden' name='csrfmiddlewaretoken' value='0QRWHnYVg776y2l66mcvZqp8alrv4lb8S8lZ4ZJUWGZFA5VHrVfL2mpH29YZ39PW' />
+
+ +

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.

+ +

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.

+ +

A proteção CSRF do Django é ativada por padrão. Você deve sempre usar a tag de template {% csrf_token %} em seus formulários e utilizar POST para requisições que podem alterar ou adicionar dados ao banco de dados.

+ +

Outras proteções

+ +

Django also provides other forms of protection (most of which would be hard or not particularly useful to demonstrate):

+ +
+
Proteção contra Injeção de SQL
+
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.
+
Proteção contra Clickjacking 
+
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 <iframe> invisível, controlado pelo atacante. O Django possui proteção contra clickjacking na forma do X-Frame-Options middleware que, em um navegador de suporte, pode impedir que um site seja renderizado dentro de um frame.
+
Aplicação de SSL/HTTPS
+
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:
+
+ + + +
+
Validação de cabeçalho de host
+
Usar ALLOWED_HOSTS para aceitar apenas requisições de hosts confiáveis.
+
+ +

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.

+ + + +

Resumo

+ +

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 LocalLibrary. Também fornecemos uma breve visão geral de algumas das outras proteções.

+ +

Esta foi uma incursão muito breve em segurança web. Nós recomendamos fortemente que você leia Segurança no Django para obter um entendimento mais profundo.

+ +

A próxima e última etapa neste módulo sobre Django é concluir a tarefa de avaliação.

+ +

Veja também

+ + + +

{{PreviousMenuNext("Learn/Server-side/Django/Deployment", "Learn/Server-side/Django/django_assessment_blog", "Learn/Server-side/Django")}}

+ +

Neste módulo

+ + 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 +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Introduction", "Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs")}}
+ +

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.

+ + + + + + + + + + + + +
Pré-Requisitos:Saber como abrir um terminal/linha de comando. Saber como instalar pacotes de software no sistema operacional do computador utilizado para desenvolvimento
Objetivo:Configurar o ambiente de desenvolvimento para Express (X.XX) em seu computador
+ +

Visão geral do ambiente de desenvolvimento do Express

+ +

NodeExpress 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.

+ +

O que é o ambiente de desenvolvimento Express?

+ +

O ambiente de desenvolvimento Express inclui uma instalação do Nodejs, o pacote de gerenciamento NPM e (opcionalmente) o Gerador de Aplicações Express em seu computador local.

+ +

O Node e o NPM 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 Express é então instalado pelo NPM como uma dependência de sua aplicação web Express individual (junto a outras bibliotecas como motores de modelo, drivers de banco de dados, autenticações middleware, middleware para arquivos estáticos, etc.)

+ +

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.

+ +
+

Nota: 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.

+
+ +

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).

+ +

Quais sistemas operacionais têm suporte?

+ +

Node 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 Downloads 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 Node.

+ +

Neste artigo, vamos abordar as instruções de configuração para Windows, macOS, e Ubuntu Linux.

+ +

Qual versão do Node/Express você deve usar?

+ +

Há várias versões do Node - as mais recentes contém correção de bugs, suporte para EMCAScript (JavaScript) e melhorias nas APIs do Node.

+ +

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.

+ +

Para o Express, você deve usar sempre a versão mais completa.

+ +

Sobre o banco de dados e outras dependências?

+ +

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.

+ +

Instalando o Node

+ +

Para utilizar o Express, você terá que instalar o Nodejs e o NPM 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.

+ +
+

Dica: 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 Instalando Node.js via NPM (nodejs.org).

+
+ +

Windows e macOS

+ +

Instalar o Node e o NPM no Windows ou no macOS é uma tarefa rápida e simples. Siga os seguintes passos:

+ +
    +
  1. Baixar o instalador: +
      +
    1. Vá para https://nodejs.org/en/
    2. +
    3. Selecione o botão de download da versão LTS, que é a recomendada para a maioria dos usuários.
    4. +
    +
  2. +
  3. 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.
  4. +
+ +

Ubuntu 16.04

+ +

O jeito mais fácil de instalar a versão LTS do Node é usar o NPM a partir do Ubuntu binary distributions repository. Isso pode ser feito de uma maneira muito simples. Rode os seguintes comandos no seu terminal.

+ +
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
+sudo apt-get install -y nodejs
+
+ +
+

Atenção: Não faça a instalação direto do repositório normal do Ubuntu pois ele contém versões antigas do Node.

+
+ +
    +
+ +

Testando a instalação do Nodejs e do NPM

+ +

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.

+ +
>node -v
+v8.9.4
+ +

O NPM também deve ter sido instalado. Você pode checar da seguinte maneira:

+ +
>npm -v
+5.6.0
+ +

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.

+ +
    +
  1. 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. +
    //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/')
    +
    + +

    O código importa o módulo "http" e o utiliza para criar um servidor (createServer()) que escuta as requisições HTTP na porta 8000. O script, então, imprime a mensagem no console. A função createServer() 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".

    +
  2. +
  3. +
    +

    Nota:  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.

    +
    +
  4. +
  5. Inicie o servidor e navegue pelo mesmo diretório que o seu arquivo hellonode.js no terminal. Depois chame o Node da seguinte forma: +
    >node hellonode.js
    +Server running at http://127.0.0.1:8000/
    +
    +
  6. +
  7. Navegue até a URL (http://127.0.0.1:8000/). Se tudo estiver funcionando bem, o browser vai apresentar a frase "Hello World".
  8. +
+ +

Usando o NPM

+ +

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.

+ +
+

Nota: A partir da perspectiva do Node, Express é um pacote que precisa ser instalado utilizando o NPM e depois importado para o seu código.

+
+ +

Você pode usar o NPM separadamente para buscar cada pacote desejado. Em geral, nós gerenciamos as dependências com um arquivo chamado package.json. 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 package.json 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).

+ +

Adicionando dependências

+ +

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.

+ +
+

Nota:  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 Express Application Generator. É  muito importante entendermos como o NPM funciona e o que é criado com o generator. 

+
+ +
    +
  1. Primeiro passo é criar um diretório para sua aplicação. No prompt, insira os comandos a seguir. +
    mkdir myapp
    +cd myapp
    +
  2. +
  3.  Use o comando npm init para criar o arquivo package.json 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" (index.js por padrão). Por hora, vamos manter a configuração padrão. +
    npm init
    + +

    Se você acessar o arquivo package.json (cat packge.json), você verá toda a configuração padrão e, ao final, o tipo de licença que o app está utilizando.

    + +
    {
    +  "name": "myapp",
    +  "version": "1.0.0",
    +  "description": "",
    +  "main": "index.js",
    +  "scripts": {
    +    "test": "echo \"Error: no test specified\" && exit 1"
    +  },
    +  "author": "",
    +  "license": "ISC"
    +}
    +
    +
  4. +
  5. Agora, instale o Express dentro do diretório myapp. O pacote será salvo automaticamente na lista de dependências do seu package.json.
  6. +
  7. +
    npm install express
    + +

    A lista de dependências do package.json agora mostra também a versão do Express que estamos usando. Está grifada no final do arquivo.

    + +
    {
    +  "name": "myapp",
    +  "version": "1.0.0",
    +  "description": "",
    +  "main": "index.js",
    +  "scripts": {
    +    "test": "echo \"Error: no test specified\" && exit 1"
    +  },
    +  "author": "",
    +  "license": "ISC",
    +  "dependencies": {
    +    "express": "^4.16.2"
    +  }
    +}
    +
    +
  8. +
  9. Para usar o Express, é preciso incluir a função require() no arquivo index.js dentro da sua aplicação. Crie esse arquivo agora mesmo na pasta raiz "myapp" e inclua o código a seguir. +
    var express = require('express')
    +var app = express()
    +
    +app.get('/', function (req, res) {
    +  res.send('Hello World!')
    +})
    +
    +app.listen(8000, function () {
    +  console.log('Example app listening on port 8000!')
    +})
    +
    + +

    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 (app) 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 app.get() 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 Hello World!

    +
  10. +
  11. Rode a linha de comando abaixo para iniciar o servidor. +
    >node index.js
    +Example app listening on port 8000
    +
    +
  12. +
  13. Vá para a seguinte URL (http://127.0.0.1:8000/). Se tudo estiver funcionando corretamente, o browser vai mostrar a mensagem "Hello World!".
  14. +
+ +

Desenvolvendo dependências

+ +

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 esling (JavaScript Linting), você faria a instalação via NPM da seguinte forma.

+ +
npm install eslint --save-dev
+ +

Assim, a esling vai aparecer da seguinte forma na lista de dependências do package.json.

+ +
  "devDependencies": {
+    "eslint": "^4.12.1"
+  }
+
+ +
+

Note: "Linters" são ferramentas que nos ajudam a identificar e reportar que o código está sendo escrito dentro das melhores práticas.

+
+ +

Rodando tarefas

+ +

Além de definir e buscar dependências, você também pode nomear scripts dentro do seu arquivo package.json e chamar o NPM para executá-lo a partir de um run-script 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).

+ +
+

Nota: Ferramentas de automação de tarefas como o Gulp e o Grunt também podem ser utilizados, além de outros pacotes externos. 

+
+ +

Para definir o script que roda o esling, citado na seção acima, nós precisamos adicionar o seguinte bloco no nosso package.json (importante: sua aplicação precisa ter como source está na pasta /src/js):

+ +
"scripts": {
+  ...
+  "lint": "eslint src/js"
+  ...
+}
+
+ +

Explicando um pouco mais: eslint src/js é o comando que colocamos no nosso terminal para rodar o eslint nos arquivos JavaScript situados no diretório src/js dentro do diretório do nosso app. Incluindo o comando, criamos o comando de atalho - lint.

+ +
npm run-script lint
+# OR (using the alias)
+npm run lint
+
+ +

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.

+ +

Instalando o Express Application Generator

+ +

Express Application Generator é uma ferramenta que cria "esqueleto" para aplicações Express. A instalação é realizada via NPM como mostrada a seguir (o comando -g instala a pacote globalmente, ou seja, você pode acessá-lo de qualquer lugar do seu computador).

+ +
npm install express-generator -g
+ +

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:

+ +
express helloworld
+ +
+

Nota:  Você também pode definir a biblioteca de template que pretende usar e muitas outras configurações. Use o comando help para ver todas as opções. 

+ +
express --help
+
+
+ +

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.

+ +
+

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) .

+ +
{
+  "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"
+  }
+}
+
+ +

Instale todas as dependências para o app helloworld com o NPM, de acordo com os comandos abaixo:

+ +
cd helloworld
+npm install
+
+ +

Agora, rode o aplicativo (o comando muda um pouco entre Windows, Linux/macOS), como está no código a seguir:

+ +
# Rode o helloworld no Windows
+SET DEBUG=helloworld:* & npm start
+
+# Rode helloworld no Linux/macOS
+DEBUG=helloworld:* npm start
+
+ +

O comando DEBUG gera um loggin bem útil, apresentando resultados, como abaixo:

+ +
>SET DEBUG=helloworld:* & npm start
+
+> helloworld@0.0.0 start D:\Github\expresstests\helloworld
+> node ./bin/www
+
+  helloworld:server Listening on port 3000 +0ms
+ +

Abre um browser e navegue para http://127.0.0.1:3000/ e veja a página default apresentada pelo aplicativo.

+ +

Express - Generated App Default Screen

+ +

Vamos falar mais sobre o "gerador" quando chegarmos ao artigo referente à geração de esqueletos de uma aplicação.

+ + + +

Sumário

+ +

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.

+ +

No próximo artigo, nós vamos iniciar um tutorial para construir uma aplicação web completa utilizando esse ambiente junto com as ferramentas.

+ +

Veja também

+ + + +

{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Introduction", "Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs")}}

+ +

Outros módulos

+ + 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 +--- +
{{LearnSidebar}}
+ +
{{PreviousMenu("Learn/Server-side/Express_Nodejs/forms", "Learn/Server-side/Express_Nodejs")}}
+ +

Now you've created (and tested) an awesome LocalLibrary 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.

+ + + + + + + + + + + + +
Pré-requisitos:Complete todos os tópicos anteriores do turotrial, inclusive o Express Tutorial Part 6: Working with forms.
Objetivo:Aprender onde e como você pode implantar um app Express app em produção.
+ +

Overview

+ +

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.

+ +

Up to now you've been working in a development environment, 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:

+ + + +

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 Heroku cloud hosting service.

+ +

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 Install LocalLibrary on PWS/Cloud Foundry.

+ +

What is a production environment?

+ +

The production environment is the environment provided by the server computer where you will run your website for external consumption. The environment includes:

+ + + +

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.

+ +

This sort of remotely accessible computing/networking hardware is referred to as Infrastructure as a Service (IaaS). 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.

+ +
+

Note: 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!

+
+ +

Other hosting providers support Express as part of a Platform as a Service (PaaS) 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.

+ +

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.

+ +
+

Tip: 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 Digital Ocean Node community docs.

+
+ +

Choosing a hosting provider

+ +

There are numerous hosting providers that are known to either actively support or work well with Node (and Express). These vendors provide different types of environments (IaaS, PaaS), and different levels of computing and network resources at different prices.

+ +
+

Tip: 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.

+
+ +

Some of the things to consider when choosing a host:

+ + + +

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, Heroku provides a free but resource-limited PaaS environment "forever", while Amazon Web Services, Microsoft Azure, and the open source option PWS/Cloud Foundry provide free credit when you first join.

+ +

Many providers also have a "basic" tier that provides more useful levels of computing power and fewer limitations. Digital Ocean 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).

+ +
+

Note: 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.

+
+ +

Getting your website ready to publish

+ +

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.

+ +

In the following subsections we outline the most important changes that you should make to your app.

+ +
+

Tip: There are other useful tips in the Express docs — see Production best practices: performance and reliability and Production Best Practices: Security.

+
+ +

Set NODE_ENV to 'production'

+ +

We can remove stack traces in error pages by setting the NODE_ENV environment variable to production (it is set to 'development' by default). In addition to generating less-verbose error messages, setting the variable to production caches view templates and CSS files generated from CSS extensions. Tests indicate that setting NODE_ENV to production can improve app performance by a factor of three!

+ +

This change can be made either by using export or an environment file, or using the OS initialisation system.  

+ +
+

Note: 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. 

+
+ +

Log appropriately

+ +

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.

+ +

One way to minimise "debug" logging in production is to use a module like debug 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.

+ +
var debug = require('debug')('author');
+
+// 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) {
+            debug('update error:' + err);
+            return next(err);
+        }
+        //On success
+        res.render('author_form', { title: 'Update Author', author: author });
+    });
+
+};
+ +

You can then enable a particular set of logs by specifying them as a comma-separated list in the DEBUG environment variable. You can set the variables for displaying author and book logs as shown (wildcards are also supported).

+ +
#Windows
+set DEBUG=author,book
+
+#Linux
+export DEBUG="author,book"
+
+ +
+

Challenge: Calls to debug can replace logging you might previously have done using console.log() or console.error(). Replace any console.log() calls in your code with logging via the debug module. Turn the logging on and off in your development environment by setting the DEBUG variable and observe the impact this has on logging.

+
+ +

If you need to log website activity you can use a logging library like Winston or Bunyan. For more information on this topic see: Production best practices: performance and reliability.

+ +

Use gzip/deflate compression for responses

+ +

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).

+ +

You can add this to your site using compression middleware. Install this to your project by running the following command at the root of the project.

+ +
npm install compression
+ +

Open ./app.js and require the compression library as shown. Add the compression library to the middleware chain with the use() method (this should appear before any routes that you want compressed — in this case all of them!)

+ +
var catalog = require('./routes/catalog'); //Import routes for "catalog" area of site
+var compression = require('compression');
+
+// Create the Express application object
+var app = express();
+
+...
+
+app.use(compression()); //Compress all routes
+
+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.
+
+...
+
+ +
+

Note: For a high-traffic website in production you wouldn't use this middleware. Instead you would use a reverse proxy like Nginx.

+
+ +

Use Helmet to protect against well known vulnerabilities

+ +

Helmet is a middleware package that can help protect your app from some well-known web vulnerabilities by setting appropriate HTTP headers (see the docs for more information on what headers it sets/vulnerabilities it protects against). 

+ +

Install this to your project by running the following command at the root of the project.

+ +
npm install helmet
+
+ +

Open ./app.js and require the helmet library as shown. Then add the module to the middleware chain with the use() method.

+ +
var compression = require('compression');
+var helmet = require('helmet');
+
+// Create the Express application object
+var app = express();
+
+app.use(helmet());
+...
+ +
+

Note: The command above adds the subset of available headers that makes sense for most sites. You can add/disable specific headers as needed by following the instructions on npm.

+
+ +

Example: Installing LocalLibrary on Heroku

+ +

This section provides a practical demonstration of how to install LocalLibrary on the Heroku PaaS cloud.

+ +

Why Heroku?

+ +

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)!

+ +

We are choosing to use Heroku for several reasons:

+ + + +

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.

+ +

How does Heroku work?

+ +

Heroku runs websites within one or more "Dynos", which are isolated, virtualized Unix containers that provide the environment required to run an application. The dynos are completely isolated and have an ephemeral 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 configuration variables. 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).

+ +

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.

+ +

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 package.json file.

+ +

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!

+ +

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.

+ +

That's all the overview you need in order to get started (see Getting Started on Heroku with Node.js for a more comprehensive guide).

+ +

Creating an application repository in Github

+ +

Heroku is closely integrated with the git 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 heroku 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.

+ +
+

Note: 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.

+
+ +

There are a lot of ways of to work with git, but one of the easiest is to first set up an account on GitHub, create the repository there, and then sync to it locally:

+ +
    +
  1. Visit https://github.com/ and create an account.
  2. +
  3. Once you are logged in, click the + link in the top toolbar and select New repository.
  4. +
  5. Fill in all the fields on this form. While these are not compulsory, they are strongly recommended. +
      +
    • Enter a new repository name (e.g. express-locallibrary-tutorial), and description (e.g. "Local Library website written in Express (Node)".
    • +
    • Choose Node in the Add .gitignore selection list.
    • +
    • Choose your preferred license in the Add license selection list.
    • +
    • Check Initialize this repository with a README.
    • +
    +
  6. +
  7. Press Create repository.
  8. +
  9. Click the green "Clone or download" button on your new repo page.
  10. +
  11. Copy the URL value from the text field inside the dialog box that appears (it should be something like: https://github.com/<your_git_user_id>/express-locallibrary-tutorial.git).
  12. +
+ +

Now the repository ("repo") is created we are going to want to clone it on our local computer:

+ +
    +
  1. Install git for your local computer (you can find versions for different platforms here).
  2. +
  3. Open a command prompt/terminal and clone your repository using the URL you copied above: +
    git clone https://github.com/<your_git_user_id>/express-locallibrary-tutorial.git
    +
    + This will create the repository below the current point.
  4. +
  5. Navigate into the new repo. +
    cd express-locallibrary-tutorial
    +
  6. +
+ +

The final step is to copy in your application and then add the files to your repo using git:

+ +
    +
  1. Copy your Express application into this folder (excluding /node_modules, which contains dependency files that you should fetch from NPM as needed).
  2. +
  3. Open a command prompt/terminal and use the add command to add all files to git.
  4. +
  5. +
    git add -A
    +
    +
  6. +
  7. 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. +
    > 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:   ...
    +
  8. +
  9. When you're satisfied commit the files to your local repository: +
    git commit -m "First version of application moved into github"
    +
  10. +
  11. Then synchronise your local repository to the Github website, using the following: +
    git push origin master
    +
  12. +
+ +

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.

+ +
+

Tip: 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.

+ +

The best way to do this is to use git to manage your revisions. With git 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. Learning Git is well worth the effort, but is beyond the scope of this topic.

+ +

The easiest way to do this is to just copy your files into another location. Use whichever approach best matches your knowledge of git!

+
+ +

Update the app for Heroku

+ +

This section explains the changes you'll need to make to our LocalLibrary application to get it to work on Heroku.

+ +

Set node version 

+ +

The package.json 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.

+ +

The only useful information missing in our current package.json is the version of node. We can find the version of node we're using for development by entering the command:

+ +
>node --version
+v8.9.1
+ +

Open package.json, and add this information as an engines > node section as shown (using the version number for your system).

+ +
{
+  "name": "express-locallibrary-tutorial",
+  "version": "0.0.0",
+  "engines": {
+    "node": "8.9.1"
+  },
+  "private": true,
+  ...
+
+ +

Database configuration

+ +

So far in this tutorial we've used a single database that is hard coded into app.js. 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.

+ +

Open app.js and find the line that sets the mongoDB connection variable. It will look something like this:

+ +
var mongoDB = 'mongodb://your_user_id:your_password@ds119748.mlab.com:19748/local_library';
+ +

Replace the line with the following code that uses process.env.MONGODB_URI to get the connection string from an environment variable named MONGODB_URI if has been set (use your own database URL instead of the placeholder below.)

+ +
var mongoDB = process.env.MONGODB_URI || 'mongodb://your_user_id:your_password@ds119748.mlab.com:19748/local_library';
+
+ +

Get dependencies and re-test

+ +

Before we proceed, let's test the site again and make sure it wasn't affected by any of our changes. 

+ +

First we will need to fetch our dependencies (you will recall we didn't copy the node_modules folder into our git tree). You can do this by running the following command in your terminal at the root of the project:

+ +
npm install
+
+ +

Now run the site (see Testing the routes for the relevant commands) and check that the site still behaves as you expect.

+ +

Save changes to Github

+ +

Next let's save all our changes to Github. In the terminal (whilst inside our repository), enter the following commands:

+ +
git add -A
+git commit -m "Added files and changes required for deployment to heroku"
+git push origin master
+ +

We should now be ready to start deploying LocalLibrary on Heroku.

+ +

Get a Heroku account

+ +

To start using Heroku you will first need to create an account (skip ahead to Create and upload the website if you've already got an account and installed the Heroku client):

+ + + +

Install the client

+ +

Download and install the Heroku client by following the instructions on Heroku here.

+ +

After the client is installed you will be able run commands. For example to get help on the client:

+ +
heroku help
+
+ +

Create and upload the website

+ +

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 heroku in our local git environment.

+ +
heroku create
+ +
+

Note: 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.

+
+ +

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.

+ +
git push heroku master
+ +

If we're lucky, the app is now "running" on the site. To open your browser and run the new website, use the command:

+ +
heroku open
+ +
+

Note: 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.

+
+ +

Setting configuration variables

+ +

You will recall from a preceding section that we need to set NODE_ENV to 'production' in order to improve our performance and generate less-verbose error messages. We do this by entering the following command:

+ +
>heroku config:set NODE_ENV='production'
+Setting NODE_ENV and restarting limitless-tor-18923... done, v13
+NODE_ENV: production
+
+ +

We should also use a separate database for production, setting its URI in the MONGODB_URI  environment variable. You can set up a new database and database-user exactly as we did originally, and get its URI. You can set the URI as shown (obviously, using your own URI!)

+ +
>heroku config:set MONGODB_URI='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
+
+ +

You can inspect your configuration variables at any time using the heroku config command — try this now:

+ +
>heroku config
+=== limitless-tor-18923 Config Vars
+MONGODB_URI: mongodb://your_user:your_password@ds139278.mlab.com:39278/local_library_production
+NODE_ENV:    production
+
+ +

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.

+ +

Managing addons

+ +

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 Managing Add-ons (Heroku docs).

+ +

Debugging

+ +

The Heroku client provides a few tools for debugging:

+ +
heroku logs  # Show current logs
+heroku logs --tail # Show current logs and keep updating with any new results
+heroku ps   #Display dyno status
+
+ + + +

Summary

+ +

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 source code on Github here.

+ +

See also

+ + + +

{{PreviousMenu("Learn/Server-side/Express_Nodejs/forms", "Learn/Server-side/Express_Nodejs")}}

+ +

 

+ +

In this module

+ + + +

 

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 +--- +

O código da Controller, 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 async.

+ +
+

Nota: 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 Promises

+
+ +

Async has a lot of useful methods (check out the documentation). Some of the more important functions are:

+ + + +

Por que isso é necessário ?

+ +

A maioria dos métodos que usamos no Express são assíncronos - você especifica uma operação para executar, passando um callback. O método retorna imediatamente e o callback é invocado quando a operação solicitada é concluída. Por convenção no Express, as funções de callback 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.

+ +

Se uma Controller só precisa executar uma operação assíncrona para obter as informações necessárias para renderizar uma página, a implementação é fácil —simplesmente renderizamos o template no callback. O código abaixo ilustra uma função que renderiza a contagem de um model ExampleModel (usando o método count()  do Mongoose.

+ +
exports.example_model_count = function(req, res, next) {
+
+  ExampleModel .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 } );
+  });
+}
+
+ +

However what if you need to make multiple 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 callback hell.

+ +

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 Async module makes easy!

+ +

Operações assíncronas em paralelo

+ +

The method async.parallel() is used to run multiple asynchronous operations in parallel.

+ +

The first argument to async.parallel() is a collection of the asynchronous functions to run (an array, object or other iterable). Each function is passed a callback(err, result) which it must call on completion with an error err (which can be null) and an optional results value.

+ +

The optional second argument to  async.parallel() 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).

+ +

The example below shows how this works when we pass an object as the first argument. As you can see, the results are returned in an object with the same property names as the original functions that were passed in.

+ +
async.parallel({
+  one: function(callback) { ... },
+  two: function(callback) { ... },
+  ...
+  something_else: function(callback) { ... }
+  },
+  // optional callback
+  function(err, results) {
+    // 'results' is now equal to: {one: 1, two: 2, ..., something_else: some_value}
+  }
+);
+ +

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).

+ +

Operações assíncronas em série

+ +

The method async.series() 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 async.parallel().

+ +
async.series({
+  one: function(callback) { ... },
+  two: function(callback) { ... },
+  ...
+  something_else: function(callback) { ... }
+  },
+  // optional callback after the last asynchronous function completes.
+  function(err, results) {
+    // 'results' is now equals to: {one: 1, two: 2, ..., something_else: some_value} 
+  }
+);
+ +
+

Note: 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.

+
+ +
async.series([
+  function(callback) {
+    // do some stuff ...
+    callback(null, 'one');
+  },
+  function(callback) {
+    // do some more stuff ... 
+    callback(null, 'two');
+  }
+ ],
+  // optional callback
+  function(err, results) {
+  // results is now equal to ['one', 'two'] 
+  }
+);
+ +

Operações assíncronas dependentes em série

+ +

The method async.waterfall() is used to run multiple asynchronous operations in sequence when each operation is dependent on the result of the previous operation.

+ +

The callback invoked by each asynchronous function contains null 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 async documentation):

+ +
async.waterfall([
+  function(callback) {
+    callback(null, 'one', 'two');
+  },
+  function(arg1, arg2, callback) {
+    // arg1 now equals 'one' and arg2 now equals 'two' 
+    callback(null, 'three');
+  },
+  function(arg1, callback) {
+    // arg1 now equals 'three'
+    callback(null, 'done');
+  }
+], function (err, result) {
+  // result now equals 'done'
+}
+);
+ +

Instalando o async

+ +

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 LocalLibrary project and enter the following command:

+ +
npm install async
+ +

Next steps

+ + 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 +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs/forms", "Learn/Server-side/Express_Nodejs")}}
+ +

We're now ready to add the pages that display the LocalLibrary 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.

+ + + + + + + + + + + + +
Pré-requisitos:Complete previous tutorial topics (including Express Tutorial Part 4: Routes and controllers).
Objetivo:To understand how to use the async module and Pug template language, and how to get data from the URL in our controller functions.
+ +

Overview

+ +

In our previous tutorial articles we defined Mongoose models that we can use to interact with a database and created some initial library records. We then created all the routes 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).

+ +

The next step is to provide proper implementations for the pages that display 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.

+ +

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.

+ +

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.

+ +

Displaying library data tutorial subarticles

+ +

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.

+ +
    +
  1. Asynchronous flow control using async
  2. +
  3. Template primer
  4. +
  5. The LocalLibrary base template
  6. +
  7. Home page
  8. +
  9. Book list page
  10. +
  11. BookInstance list page
  12. +
  13. Date formatting using moment
  14. +
  15. Author list page and Genre list page challenge
  16. +
  17. Genre detail page
  18. +
  19. Book detail page
  20. +
  21. Author detail page
  22. +
  23. BookInstance detail page and challenge
  24. +
+ +

Summary

+ +

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 Pug, 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 moment.

+ +

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.

+ +

Veja mais

+ + + +

{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs/forms", "Learn/Server-side/Express_Nodejs")}}

+ +

 

+ +

Neste módulo

+ + + +

 

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 +--- +
{{LearnSidebar}}
+ +

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.

+ +

Pré-requisitos

+ +

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 Módulo de primeiros passos da programação de sites do lado servidor. Um conhecimento geral de conceitos de programação e JavaScript é altamente recomendado, mas não é essencial para a compreensão dos conceitos fundamentais.

+ +
+

Nota: 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.

+ +

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).

+
+ +

Tutoriais

+ +
+
Express/Node introdução
+
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).
+
Configurando um ambiente de desenvolvimento em Node (Express) 
+
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.
+
Tutorial Express: O site da Biblioteca Local
+
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.
+
+
Express Tutorial Part 2: Creating a skeleton website
+
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.
+
Express Tutorial Part 3: Using a Database (with Mongoose)
+
This article briefly introduces databases for Node/Express. It then goes on to show how we can use Mongoose to provide database access for the LocalLibrary 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.
+
Express Tutorial Part 4: Routes and controllers
+
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 LocalLibrary 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.
+
Express Tutorial Part 5: Displaying library data
+
We're now ready to add the pages that display the LocalLibrary 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.
+
Express Tutorial Part 6: Working with forms
+
In this tutorial we'll show you how to work with HTML Forms in Express, using Pug, and in particular how to write forms to create, update, and delete documents from the database.
+
Express Tutorial Part 7: Deploying to production
+
Now you've created an awesome LocalLibrary 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.
+
+ +

See also

+ +
+
Installing LocalLibrary on PWS/Cloud Foundry
+
This article provides a practical demonstration of how to install LocalLibrary on the Pivotal Web Services PaaS cloud — 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.
+
+ +

Adding more tutorials

+ +
+

That's the end of the tutorial articles (for now). If you would like to extend it, other interesting topics to cover are:

+ + + +

And of course it would be excellent to have an assessment task!

+
diff --git "a/files/pt-br/learn/server-side/express_nodejs/introdu\303\247\303\243o/index.html" "b/files/pt-br/learn/server-side/express_nodejs/introdu\303\247\303\243o/index.html" new file mode 100644 index 0000000000..15ccfc6145 --- /dev/null +++ "b/files/pt-br/learn/server-side/express_nodejs/introdu\303\247\303\243o/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 +--- +
{{LearnSidebar}}
+ +
{{NextMenu("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs")}}
+ +

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 (embora neste momento você ainda não tenha um ambiente de desenvolvimento para testá-lo).

+ + + + + + + + + + + + +
Pré-requisitos:Conhecimentos básicos em informática. Uma compreensão geral de programação web no lado servidor (backend), em particular, nos mecanismos de interação cliente-servidor de websites.
Objetivos:Familiarizar-se com Express, como este framework trabalha junto ao Node, quais as funcionalidades que fornece e quais são os principais blocos de construção de um aplicativo Express.
+ +

O que é Express e Node ?

+ +

Node (ou formalmente Node.js) é 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 JavaScript.  Node é usado fora do contexto de um navegador (ou seja executado diretamente no computador ou no servidor). Como tal, 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.

+ +

Do ponto de vista do desenvolvimento de um servidor web, o Node possui vários benefícios:

+ + + +

Você pode utilizar o Node.js para criar um simples servidor web, utilizando o pacote Node HTTP.

+ +

Olá, Node.js

+ +

O exemplo a seguir cria um servidor web que escuta qualquer tipo de requisição HTTP na URL  http://127.0.0.1:8000/  --  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.

+ +
    +
  1. Abre o Terminal (no Windows, abra o prompt da linha de comando)
  2. +
  3. Crie uma pasta onde você quer salvar o programa, por exemplo, test-node. Então, entre na pasta com o seguinte comando no terminal:
  4. +
+ +
cd test-node
+
+ +

Use o seu editor de texto preferido, crie um arquivo chamado hello.js e cole o código a seguir:

+ +
// 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/');
+ +

Salve o arquivo na pasta que você criou acima.

+ +

Por último, vá para o terminal e digite o comando a seguir:

+ +

node hello.js

+ +

Enfim, abra o browser e digite  http://localhost:8000. Você verá o texto "Olá, Mundo", no canto superior esquerdo.

+ +

Web Frameworks

+ +

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 GET, POST, DELETE, 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.

+ +

Introduzindo o Express

+ +

Express é o framework Node mais popular e a biblioteca subjacente para uma série de outros frameworks do Node. O Express oferece soluções para:

+ + + +

O Express é 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 Express Middleware (juntamente com uma lista de pacotes populares desenvolvidos por terceiros).

+ +
+

Nota: Essa flexibilidade do Express é uma espada de dois gumes. 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. 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.

+
+ +

De onde o Node e o Express vieram?

+ +

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 Long Term Support (LTS) é 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 Wikipédia.

+ +

O Express foi lançado em novembro de 2010 e atualmente está na versão 4.16 da API. Você pode verificar o changelog para obter informações sobre as mudanças na versão atual e o GitHub para obter notas detalhadas das versões históricas.

+ + + +

É 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.

+ +

Não há nenhum número capaz de medir precisamente a popularidade de um framework (apesar de que alguns sites como o Hot Frameworks avaliarem a popularidade a partir do número de projetos do GitHub e do número de perguntas do StackOverflow relativas a cada tecnologia). 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.

+ +

O Node e o Express continuam a evoluir ? Você pode obter ajuda na comunidade caso precise? Existe uma oportunidade para você receber trabalho remunerado ao dominar o Node e o Express ?

+ +

Baseado no número de empresas de alto perfil 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!

+ +

Express é opinativo ?

+ +

Os frameworks web costumam se autodeclararem "opinativos" ou "não opinativos".

+ +

Os frameworks opinativos são aqueles com "opiniões" sobre o "caminho certo" para lidar com qualquer tarefa específica. 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. 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.

+ +

Frameworks não opinativos, 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. 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.

+ +

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.

+ +

Como se parece o código do Express ?

+ +

Em um site tradicional baseado em dados, um aplicativo da Web aguarda pedidos HTTP do navegador da web (ou outro cliente). 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. 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. 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.

+ +

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 arquivos estão localizados e qual modelo usar para renderizar uma resposta. 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).

+ +

As seções a seguir explicam algumas das coisas comuns que você verá ao trabalhar com o código Express e Node.

+ +

Olá Mundo Express

+ +

Primeiro, considere o padrão do exemplo do Express Olá Mundo (discutiremos cada trecho do código nas seções abaixo e nas seções a seguir).

+ +
+

Dica: Se você tiver o Node e o Express já instalados (ou se você os instalar como mostrado no próximo artigo, você pode salvar este código em um arquivo chamado app.js e executá-lo em um prompt, ao digitar o comando node app.js.

+
+ +
var express = require('express');
+var app = express();
+
+app.get('/', function(req, res) {
+  res.send('Olá Mundo!');
+});
+
+app.listen(3000, function() {
+  console.log('App de Exemplo escutando na porta 3000!');
+});
+
+ +

As duas primeiras linhas require() importam o módulo Express e criam uma aplicação Express. Esse objeto (tradicionalmente nomeado de app), tem métodos de roteamento de requisições HTTP, configurações de middleware, renderização de views HTML, registro de engines de templates e modificação das configurações 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).

+ +

A parte do meio do código (as três linhas que começam com app.get) mostra uma definição de rota. O método app.get() especifica uma função de retorno de chamada que será invocada sempre que exista uma solicitação HTTP GET com um caminho ('/') relativo à raiz do site. A função de retorno de chamada requer uma solicitação e um objeto de resposta como argumentos, e simplesmente chama send() na resposta para retornar a string "Olá Mundo!"

+ +

O bloco final inicia o servidor na porta '3000' e imprime um comentário de log no console. Com o servidor em execução, você pode acessar o localhost:3000 em seu navegador para ver o exemplo de resposta retornado.

+ +

Importando e criando módulos

+ +

Um módulo é uma biblioteca/arquivo de JavaScript que você pode importar para outro código usando a função require() do Node. Express por si é um módulo, assim como as bibliotecas de middleware e banco de dados que usamos em nossos aplicativos Express.

+ +

O código abaixo mostra como importamos um módulo por nome, usando o quadro Express como um exemplo. Primeiro invocamos a função require(), especificando o nome do módulo como uma string ('express'), e chamando o objeto retornado para criar um aplicativo Express. Podemos então acessar as propriedades e funções do objeto da aplicação.

+ +
var express = require('express');
+var app = express();
+
+ +

Você também pode criar seus próprios módulos para serem importados da mesma maneira.

+ +
+

Dica: Você vai querer criar seus próprios módulos 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. 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.

+
+ +

Para tornar os objetos disponíveis fora do módulo, você precisa apenas atribuí-los ao objeto exports. Por Exemplo, o módulo square.js abaixo é um arquivo que exporta os métodos area() e perimeter():

+ +
exports.area = function(width) { return width * width; };
+exports.perimeter = function(width) { return 4 * width; };
+
+ +

Nós podemos importar este módulo usando require(). Depois, conecte ao(s) método(s) exportado(s) como mostrado a seguir:

+ +
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));
+ +
+

Nota: Você também pode especificar um caminho absoluto para o módulo (ou um nome, como fizemos inicialmente).

+
+ +

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):

+ +
module.exports = {
+  area: function(width) {
+    return width * width;
+  },
+
+  perimeter: function(width) {
+    return 4 * width;
+  }
+};
+
+ +

Para muitas outras informações sobre módulos veja Módulos (Node API docs).

+ +

Usando APIs assíncronas

+ +

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. Uma API síncrona é aquela em que cada operação deve ser concluída antes que a próxima operação seja iniciada. Por exemplo, as seguintes funções de log são síncronas e imprimirão o texto no console em ordem (Primeiro, Segundo).

+ +
console.log('Primeiro');
+console.log('Segundo');
+ +
+
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). Assim que a operação terminar, a API usará algum mecanismo para executar operações adicionais. Por exemplo, o código abaixo imprimirá "Segundo, Primeiro". Isso porque, mesmo que o método setTimeout() seja chamado primeiro e retornae imediatamente, a operação precisa de três segundos para finalizar.
+ +
+
+ +
setTimeout(function() {
+   console.log('Primeiro');
+   }, 3000);
+console.log('Segundo');
+
+ +

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). "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). 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 sua aplicação web.

+ +

Há várias maneiras de uma API assíncrona notificar para a aplicação que alguma função chegou ao fim. 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. Usamos essa abordagem acima.

+ +
+

Dica: 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 http://callbackhell.com/), utilizar um módulo como async, ou mesmo adotar recursos do ES6, como Promises.

+
+ +
+

Dica: Uma convenção comum para Node e Express é usar as devoluções de retorno de erro. 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. Há uma boa explicação de por que essa abordagem é útil neste blog: The Node.js Way - Understanding Error-First Callbacks (fredkschott.com).

+
+ +

Criando manipuladores de rotas

+ +

No nosso Olá Mundo em Express (veja acima), nós definimos uma (callback) função manipuladora de rota para requisição GET HTTP para a raiz do site ('/').

+ +
app.get('/', function(req, res) {
+  res.send('Olá Mundo');
+});
+
+ +

A função de retorno de chamada requer uma solicitação e um objeto de resposta como argumento. Neste caso, o método simplesmente chama send() na resposta para retornar a string "Olá Mundo!" Há uma série de outros métodos de resposta para encerrar o ciclo de solicitação / resposta, por exemplo, você poderia chamar res.json() para enviar uma resposta JSON ou res.sendFile() para enviar um arquivo.

+ +
+

Dica JavaScript: Você pode usar qualquer argumento que você gosta nas funções de retorno de chamada. Quando o retorno de chamada é invocado, o primeiro argumento sempre será o pedido e o segundo sempre será a resposta. Faz sentido nomeá-los de tal forma que você possa identificar o objeto que você está trabalhando no corpo do retorno de chamada.

+
+ +

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: post(), put(), delete(), options(), trace(), copy(), lock(), mkcol(), move(), purge(), propfind(), proppatch(), unlock(), report(), mkactivity(), checkout(), merge(), m-search(), notify(), subscribe(), unsubscribe(), patch(), search(), e connect().

+ +

Há um método de roteamento especial, app.all(), que será chamado em resposta a qualquer método HTTP. É usado para carregar funções de middleware em um caminho específico para todos os métodos de solicitação. O exemplo a seguir (da documentação Express) mostra um manipulador que será executado para solicitações /secret, independentemente do verbo HTTP usado (desde que seja suportado pelo módulo http).

+ +
app.all('/secret', function(req, res, next) {
+  console.log('Acessando a sessão secreta...');
+  next(); // passa o controle para o próximo manipulador
+});
+ +

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).

+ +

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 de / wiki /). Em Express, isso é alcançado usando o objeto express.Router. Por exemplo, podemos criar nossa rota wiki em um módulo chamado wiki.js e, em seguida, exportar o objeto Router, conforme mostrado abaixo:

+ +
// 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;
+
+ +
+

Nota: Adicionar rotas ao objeto Router é como adicionar rotas ao objeto app (como mostrado anteriormente).

+
+ +

Para usar o roteador em nosso arquivo de aplicativo principal, então, require() o módulo de rota (wiki.js) e depois use() no aplicativo Express para adicionar o Router ao caminho de gerenciamento de middleware. As duas rotas serão acessíveis a partir de /wiki/ e /wiki/about/.

+ +
var wiki = require('./wiki.js');
+// ...
+app.use('/wiki', wiki);
+ +

Vamos mostrar-lhe muito mais sobre trabalhar com rotas e, em particular, sobre o uso do Router, mais tarde, na seção vinculada Rotas e controladores.

+ +

Usando middleware

+ +

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. 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 manipuladora. A ordem em que o middleware é chamado depende do desenvolvedor do aplicativo.

+ +
+

Nota: 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. Se não terminar o ciclo, ele deve chamar o next() para passar o controle para a próxima função de middleware (ou a solicitação ficará pendurada).

+
+ +

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 POST e JSON, log, etc. Você pode encontrar uma lista de pacotes de middleware mantidos pela equipe Express (que também inclui outros pacotes populares de terceiros). Outros pacotes Express estão disponíveis no gerenciador de pacotes do NPM.

+ +

Para usar middleware de terceiros, primeiro você precisa instalá-lo em seu aplicativo usando NPM. Por exemplo, para instalar o logger morgan HTTP, você faria isso:

+ +
$ npm install morgan
+
+ +

Você pode então chamar use() no objeto do aplicativo Express para adicionar o middleware à pilha:

+ +
var express = require('express');
+var logger = require('morgan');
+var app = express();
+app.use(logger('dev'));
+...
+ +
+

Nota: O middleware e as funções de roteamento são chamadas na ordem em que são declaradas. 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). É 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.

+
+ +

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). 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 next, 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 que deve ser chamado).

+ +

Você pode adicionar uma função de middleware à cadeia de processamento com app.use() ou app.add(), dependendo se você deseja aplicar o middleware a todas as respostas ou a respostas com um verbo HTTP específico (GET, POST, etc. ). Você especifica rotas o mesmo em ambos os casos, embora a rota seja opcional ao chamar app.use().

+ +

O exemplo abaixo mostra como você pode adicionar a função middleware usando ambos os métodos e com/sem rota.

+ +
var express = require('express');
+var app = express();
+
+// Um exemplo de função middleware
+var a_middleware_function = function(req, res, next) {
+  // ... 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);
+ +
+

Dica JavaScript: Acima, declaramos a função de middleware separadamente e, em seguida, configuramos como retorno de chamada. Na nossa função anterior do operador de rotas, declaramos a função de retorno de chamada quando foi utilizada. Em JavaScript, ambas abordagens são válidas.

+
+ +

A documentação Express possui uma documentação excelente sobre como usar e escrever o middleware Express.

+ +

Servindo arquivos estáticos

+ +

Você pode usar o middleware express.static para servir arquivos estáticos, incluindo suas imagens, CSS e JavaScript (static() é a única função de middleware que é realmente parte do Express). 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ó:

+ +
app.use(express.static('public'));
+
+ +

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. Então, por exemplo:

+ +
http://localhost:3000/images/dog.jpg
+http://localhost:3000/css/style.css
+http://localhost:3000/js/app.js
+http://localhost:3000/about.html
+
+ +

Você pode chamar static() várias vezes para atender vários diretórios. 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).

+ +
app.use(express.static('public'));
+app.use(express.static('media'));
+
+ +

Você também pode criar um prefixo virtual para seus URL estáticos, em vez de ter os arquivos adicionados ao URL base. Por exemplo, aqui especificamos um caminho de montagem para que os arquivos sejam carregados com o prefixo "/media":

+ +
app.use('/media', express.static('public'));
+
+ +

Agora, você pode carregar os arquivos que estão no diretório public a partir do prefixo de caminho /media.

+ +
http://localhost:3000/media/images/dog.jpg
+http://localhost:3000/media/video/cat.mp4
+http://localhost:3000/media/cry.mp3
+
+ +

Para obter mais informações, consulte Servindo arquivos estáticos no Express.

+ +

Erros de manipulação

+ +

Os erros são tratados por uma ou mais funções de middleware especiais que possuem quatro argumentos, em vez dos três habituais: (err, req, res, next). Por exemplo:

+ +
app.use(function(err, req, res, next) {
+  console.error(err.stack);
+  res.status(500).send('Something broke!');
+});
+
+ +

Isso pode retornar qualquer conteúdo exigido, mas deve ser chamado depois de todas as outras chamadas app.use() e rotas para que sejam o último middleware no processo de solicitação de pedidos!

+ +

Express vem com um manipulador de erros embutido, que cuida de todos os erros que podem ser encontrados no aplicativo. Essa função de middleware de gerenciamento de erros padrão é adicionada no final da pilha de funções do middleware. Se você passar um erro para next() e você não lidar com isso em um manipulador de erro, ele será tratado pelo manipulador de erros incorporado; o erro será gravado no cliente com o rastreamento da pilha.

+ +
+

Nota: O rastreamento da pilha não está incluído no ambiente de produção. Para executá-lo no modo de produção, você precisa configurar a variável de ambiente NODE_ENV para 'production'.

+
+ +
+

Nota: HTTP404 e outros códigos de status de "erro" não são tratados como erros. Se você quiser lidar com isso, você pode adicionar uma função de middleware para fazê-lo. Para mais informações, consulte as FAQ.

+
+ +

Para obter mais informações, consulte Gerenciamento de erros (Express docs).

+ +

Usando Banco de Dados

+ +

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). Existem muitas opções, incluindo PostgreSQL, MySQL, Redis, SQLite, MongoDB, etc.

+ +

Para usá-los, você deve primeiro instalar o driver do banco de dados usando NPM. Por exemplo, para instalar o driver para o popular NoSQL MongoDB você usaria o comando:

+ +
$ npm install mongodb
+
+ +

O próprio banco de dados pode ser instalado localmente ou em um servidor em nuvem. 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). O exemplo abaixo (da documentação Express) mostra como você pode encontrar registros de "mamíferos" usando MongoDB.

+ +
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);
+  });
+});
+ +

Outra abordagem popular é acessar seu banco de dados indiretamente, através de um Object Relational Mapper ("ORM"). Nesta abordagem, você define seus dados como "objetos" ou "modelos" e o ORM mapeia estes para o formato de banco de dados subjacente. 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. Falaremos mais sobre bancos de dados em um artigo posterior.

+ +

Para obter mais informações, consulte integração com banco de dados (documentos express).

+ +

Renderizando dados (views)

+ +

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. Os modelos geralmente são usados para criar HTML, mas também podem criar outros tipos de documentos. Express tem suporte para uma série de mecanismos de modelos, e há uma comparação útil dos motores mais populares aqui: Comparing JavaScript Templating Engines: Jade, Mustache, Dust and More.

+ +

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 !)

+ +
var express = require('express');
+var app = express();
+
+//  Definir o diretório para conter os modelos ('views')
+app.set('views', path.join(__dirname, 'views'));
+
+// Definir o motor de visualização para usar, neste caso 'some_template_engine_name'
+app.set('view engine', 'some_template_engine_name');
+
+ +

A aparência do modelo dependerá do mecanismo que você usa. 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 Response.render() em uma função de roteador de rotas para criar e enviar a resposta HTML :

+ +
app.get('/', function(req, res) {
+  res.render('index', { title: 'About dogs', message: 'Dogs rock!' });
+});
+ +

Para obter mais informações, consulte usando motores de modelo com Express (Express docs).

+ +

Estrutura de Arquivos

+ +

Express não faz suposições em termos de estrutura ou quais os componentes que você usa. 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. 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 você está usando uma arquitetura MVC).

+ +

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.

+ + + +

Sumário

+ +

Parabéns, você completou o primeiro passo em sua viagem Express/Node! 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). Por ser um framework não opinativo, o Express permite que você defina a maneira como essas partes e essas bibliotecas são integradas.

+ +

Claro que Express é deliberadamente uma estrutura de aplicativos web muito leve, tanto seu benefício e potencial vem de bibliotecas e recursos de terceiros. Examinaremos essa questão com mais detalhes nos próximos artigos. 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.

+ +

Veja também

+ + + +
{{NextMenu("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs")}}
+ +

Próximos módulos

+ + 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 +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs")}}
+ +

Este artigo introduz brevemente bancos de dados e como usá-los com aplicativos Node/Express. Depois demonstra como podemos usar o Mongoose para prover acesso ao banco de dados para o website LocalLibrary. 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.

+ + + + + + + + + + + + +
Pré-requisitos:Tutorial Express Parte 2: Criando o esqueleto de um website
Objetivo:Ser capaz de projetar e criar seus próprios modelos usando Mongoose.
+ +

Visão geral

+ +

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 banco de dados.

+ +

Aplicativos Express 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.

+ +

Quais bancos de dados eu posso usar?

+ +

Aplicativos Express podem usar qualquer banco de dados suportado pelo Node (O Express por si só não define nenhum requerimento ou comportamento adicional específico para gerenciamento de bancos de dados). Há muitas opções populares, incluindo PostgreSQL, MySQL, Redis, SQLite, and MongoDB.

+ +

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.

+ +

Para mais informações sobre as opções veja Integração com o Banco de dados (documentação do Express).

+ +

Qual o melhor jeito de interagir com um banco de dados?

+ +

There are two approaches for interacting with a database: 

+ + + +

The very best performance 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).

+ +

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.

+ +
+

Tip:  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.

+
+ +

Qual ORM/ODM eu devo usar?

+ +

There are many ODM/ORM solutions available on the NPM package manager site (check out the odm and orm tags for a subset!).

+ +

A few solutions that were popular at the time of writing are:

+ + + +

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.

+ +

Usando Mongoose e MongoDb para a LocalLibrary

+ +

Para o exemplo da Local Library (e para o resto do tópico) nós iremos usar o  Mongoose ODM para acessar os dados da nossa aplicação. Mongoose funciona como uma interface para o MongoDB, um banco de dados de código aberto e NoSQL que usa um modelo de dados orientado a documentos. Uma “coleção” de “documentos”, em uma base de dados do MongoDB, é semelhante a uma “tabela” com “linhas” em uma base dados relacional.

+ +

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.

+ +
+

Dica: Você não precisa conhecer o MongoDB antes de usar o Mongoose, apesar de que partes da documentação do Mongoose são mais fáceis de entender se você já está familiarizado com o MongoDB.

+
+ +

O resto desse tutorial mostra como definir e acessar os modelos e schemas no Mongoose para o nosso website da LocalLibrary.

+ +

Projetando os modelos da aplicação LocalLibrary

+ + + +

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.

+ +

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.

+ +

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).

+ +

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.).

+ +

Uma vez que nós decidimos nossos modelos e os seus atributos, nós precisamos pensar sobre o relacionamento entre eles.

+ +

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  BookInstance:status  — 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.

+ +

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 Booke Genre mostram que as duas coleções têm uma relação. Os números próximos ao modelo Book mostra que Genre pode ter zero ou mais Book (quantos você quiser), enquanto no outro fim da linha de conexão próximo a Genre  mostra que ele pode ter zero ou mais livros associados.

+ +
+

Nota: Assim como discutido abaixo em Iniciando com Mongoose  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 _id 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.

+
+ +

Mongoose Library Model  with correct cardinality

+ +
+

Nota: 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.

+
+ +

Iniciando com Mongoose

+ +

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.

+ +
+

Nota: Esse guia é "bastante influenciado" pelo conteúdo encontrado no Mongoose quick start do npm e pela documentação oficial.

+
+ +

Instalando Mongoose e MongoDB

+ +

O Mongoose é instalado no seu projeto (package.json) assim como outra dependência qualquer — usando NPM. Para instalá-lo, use a seguinte linha de comando dentro da pasta do seu projeto:

+ +
npm install mongoose
+
+ +

Installing Mongoose 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 download installers from here for various operating systems and install it locally. You can also use cloud-based MongoDB instances.

+ +
+

Note: For this tutorial, we'll be using the MongoDB Atlas cloud-based database as a service free tier 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).

+
+ +

Conectando ao MongoDB

+ +

Mongoose requires a connection to a MongoDB database. You can require() and connect to a locally hosted database with mongoose.connect(), as shown below.

+ +
//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:'));
+ +

You can get the default Connection object with mongoose.connection. Once connected, the open event is fired on the Connection instance.

+ +
+

Tip: If you need to create additional connections you can use mongoose.createConnection(). This takes the same form of database URI (with host, database, port, options etc.) as connect() and returns a Connection object).

+
+ +

Definindo e criando modelos

+ +

Models are defined using the Schema 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).

+ +

Schemas are then "compiled" into models using the mongoose.model() method. Once you have a model you can use it to find, create, update, and delete objects of the given type.

+ +
+

Note: Each model maps to a collection of documents in the MongoDB database. The documents will contain the fields/schema types defined in the model Schema.

+
+ +

Defining schemas

+ +

The code fragment below shows how you might define a simple schema. First you require() mongoose, then use the Schema constructor to create a new schema instance, defining the various fields inside it in the constructor's object parameter.

+ +
//Require Mongoose
+var mongoose = require('mongoose');
+
+//Define a schema
+var Schema = mongoose.Schema;
+
+var SomeModelSchema = new Schema({
+  a_string: String,
+  a_date: Date
+});
+
+ +

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.

+ +

Criando um modelo

+ +

Models are created from schemas using the mongoose.model() method:

+ +
// Define schema
+var Schema = mongoose.Schema;
+
+var SomeModelSchema = new Schema({
+  a_string: String,
+  a_date: Date
+});
+
+// Compile model from schema
+var SomeModel = mongoose.model('SomeModel', SomeModelSchema );
+ +

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 SomeModel above), and the second argument is the schema you want to use in creating the model.

+ +
+

Note: 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 Using models section, and when we create our views.

+
+ +

Schema types (fields)

+ +

A schema can have an arbitrary number of fields — each one represents a field in the documents stored in MongoDB. An example schema showing many of the common field types and how they are declared is shown below.

+ +
var schema = new Schema(
+{
+  name: String,
+  binary: Buffer,
+  living: Boolean,
+  updated: { type: Date, default: Date.now() },
+  age: { type: Number, min: 18, max: 65, required: true },
+  mixed: Schema.Types.Mixed,
+  _someId: Schema.Types.ObjectId,
+  array: [],
+  ofString: [String], // You can also have an array of each of the other types too.
+  nested: { stuff: { type: String, lowercase: true, trim: true } }
+})
+ +

Most of the SchemaTypes (the descriptors after “type:” or after field names) are self-explanatory. The exceptions are:

+ + + +

The code also shows both ways of declaring a field:

+ + + +

For more information about options see SchemaTypes (Mongoose docs).

+ +

Validação

+ +

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.

+ +

The built-in validators include:

+ + + +

The example below (slightly modified from the Mongoose documents) shows how you can specify some of the validator types and error messages:

+ +
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',]
+  }
+});
+
+ +

For complete information on field validation see Validation (Mongoose docs).

+ +

Propriedades virtuais

+ +

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.

+ +
+

Note: 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 _id value.

+
+ +

For more information see Virtuals (Mongoose documentation).

+ +

Methods and query helpers

+ +

A schema can also have instance methods, static methods, and query helpers. 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 chainable query builder API (for example, allowing you to add a query "byName" in addition to the find(), findOne() and findById() methods).

+ +

Usando modelos

+ +

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.

+ +

We provide a brief overview below. For more information see: Models (Mongoose docs).

+ +

Criando e modificando documentos

+ +

To create a record you can define an instance of the model and then call save(). The examples below assume SomeModel is a model (with a single field "name") that we have created from our schema.

+ +
// 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!
+});
+
+ +

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.

+ +

You can also use create() 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.

+ +
SomeModel.create({ name: 'also_awesome' }, function (err, awesome_instance) {
+  if (err) return handleError(err);
+  // saved!
+});
+ +

Every model has an associated connection (this will be the default connection when you use mongoose.model()). You create a new connection and call .model() on it to create the documents on a different database.

+ +

You can access the fields in this new record using the dot syntax, and change the values. You have to call save() or update() to store modified values back to the database.

+ +
// 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!
+});
+
+ +

Pesquisando por registros

+ +

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 name and age. 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.

+ +
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.
+})
+ +

If you specify a callback, as shown above, the query will execute immediately. The callback will be invoked when the search completes.

+ +
+

Note: All callbacks in Mongoose use the pattern callback(error, result). If an error occurs executing the query, the error parameter will contain an error document and result will be null. If the query is successful, the error parameter will be null, and the result will be populated with the results of the query.

+
+ +
+

Note: It is important to remember that not finding any results is not an error 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 (results==null) or daisy chain the method orFail() on the query. 

+
+ +

If you don't specify a callback then the API will return a variable of type Query. You can use this query object to build up your query and then execute it (with a callback) later using the exec() method.

+ +
// 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
+})
+ +

Above we've defined the query conditions in the find() method. We can also do this using a where() 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.

+ +
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.
+ +

The find() method gets all matching records, but often you just want to get one match. The following methods query for a single record:

+ + + +
+

Note: There is also a count() 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.

+
+ +

There is a lot more you can do with queries. For more information see: Queries (Mongoose docs).

+ + + +

You can create references from one document/model instance to another using the ObjectId schema field, or from one document to many using an array of ObjectIds. The field stores the id of the related model. If you need the actual content of the associated document, you can use the populate() method in a query to replace the id with the actual data.

+ +

For example, the following schema defines authors and stories. Each author can have multiple stories, which we represent as an array of ObjectId. Each story can have a single author. The "ref" (highlighted in bold below) tells the schema which model can be assigned to this field.

+ +
var mongoose = require('mongoose')
+  , Schema = mongoose.Schema
+
+var authorSchema = Schema({
+  name    : String,
+  stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
+});
+
+var storySchema = Schema({
+  author : { type: Schema.Types.ObjectId, ref: 'Author' },
+  title    : String
+});
+
+var Story  = mongoose.model('Story', storySchema);
+var Author = mongoose.model('Author', authorSchema);
+ +

We can save our references to the related document by assigning the _id value. Below we create an author, then a story, and assign the author id to our stories author field.

+ +
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
+  });
+});
+ +

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 populate(), as shown below.

+ +
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"
+});
+ +
+

Note: 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 stories 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.

+ +

A better way is to get the _id of our author, then use find() to search for this in the author field across all stories.

+ +
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.
+});
+
+
+ +

This is almost everything you need to know about working with related items for this tutorial. For more detailed information see Population (Mongoose docs).

+ +

One schema/model per file

+ +

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:

+ +
// 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,
+});
+
+//Export function to create "SomeModel" model class
+module.exports = mongoose.model('SomeModel', SomeModelSchema );
+ +

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.

+ +
//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);
+ +

Configurando o banco de dados MongoDB

+ +

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 LocalLibrary website. The very first thing we want to do is set up a MongoDb database that we can use to store our library data.

+ +

For this tutorial, we're going to use the MongoDB Atlas free cloud-hosted sandbox 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 database as a service vendor that you might reasonably choose for your production database (other popular choices at the time of writing include Compose, ScaleGrid and ObjectRocket).

+ +
+

Note: If you prefer you can set up a MongoDb database locally by downloading and installing the appropriate binaries for your system. The rest of the instructions in this article would be similar, except for the database URL you would specify when connecting.

+
+ +

You will first need to create an account with MongoDB Atlas (this is free, and just requires that you enter basic contact details and acknowledge their terms of service). 

+ +

After logging in, you'll be taken to the home screen:

+ +
    +
  1. Click Buid a Cluster button in the Clusters Overview section.
    + Create a cluster on MongoDB Atlas.
  2. +
  3. This will open the Create New Cluster screen.
    + Choose a cloud provider when using MongoDB Atlas. +
      +
    • Select any provider from the Cloud Provider & Region section. Different providers offer different regions.
    • +
    • Select any region marked "FREE TIER AVAILABLE".
    • +
    • Click the Create Cluster button (creation of the cluster will take some minutes).
    • +
    +
  4. +
  5. +

    You will return to the Cluster Overview screen.
    + Setup a collection on MongoDB Atlas.

    + +
      +
    • +

      Click the Collections button.

      +
    • +
    +
  6. +
  7. This will open the Collections section.
    + Create a database on MongoDB Atlas. +
      +
    • Click the Create Database button.
    • +
    +
  8. +
  9. This will open the Create Database screen.
    + Details during database creation on MongoDB Atlas. +
      +
    • Enter the name for the new database as local_library.
    • +
    • Enter the name of the collection as Collection0.
    • +
    • Click the Create button to create the database.
    • +
    +
  10. +
  11. You will return to the Collection screen with your database created.
    + Database creation confirmation on MongoDB Atlas. +
      +
    • Click the Overview tab to return the cluster overview.
    • +
    +
  12. +
  13. From the Cluster0 Overview screen click the Connect button.
    + Configure a connection when after setting up a cluster in MongoDB Atlas.
  14. +
  15. This will open the Connect to Cluster screen.
    + Setup a connection when using MongoDB Atlas. +
      +
    • Click the Add a Different IP Address button, enter 0.0.0.0/0 for the IP Address and click Add IP Address button. +
      +

      Note: 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.

      +
      +
    • +
    • Enter a username and password and click Create MongoDB User button. +
      +

      Note: Avoid using special characters in your MongoDB user password as mongoose may not parse the connection string properly.

      +
      +
    • +
    • If you have completed the 2 previous steps, the button Choose a connection method will turn green.
    • +
    • Click the Choose a connection method button.
    • +
    +
  16. +
  17. This will access the Choose a connection method tab.
    + Choose a connection type when connecting with MongoDB Atlas. +
      +
    • Click the Connect Your Application option.
    • +
    +
  18. +
  19. This will open the Connect screen.
    + Choose the Short SRV connection when settinup a connection on MongoDB Atalas. +
      +
    • Click the Short SRV connection string option to copy the connection string.
    • +
    +
  20. +
  21. This will open the connection string URL.
    + Copy the Short SRV connection string when setting up a connection on MongoDB Atlas +
      +
    • Choose Copy button to copy the string.
    • +
    • Save this string somewhere safe.
    • +
    • Update the password with your users password.
    • +
    • Replace test with local_library.
    • +
    +
  22. +
+ +

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: mongodb+srv://your_user_name:your_password@cluster0-mbdj7.mongodb.net/local_library?retryWrites=true

+ +

Instalando Mongoose

+ +

Open a command prompt and navigate to the directory where you created your skeleton Local Library website. Enter the following command to install Mongoose (and its dependencies) and add it to your package.json file, unless you have already done so when reading the Mongoose Primer above.

+ +
npm install mongoose
+
+ +

Conectando ao MongoDB

+ +

Open /app.js (in the root of your project) and copy the following text below where you declare the Express application object (after the line var app = express();). Replace the database url string ('insert_your_database_url_here') with the location URL representing your own database (i.e. using the information from mongoDB Atlas).

+ +
//Set up mongoose connection
+var mongoose = require('mongoose');
+var mongoDB = 'insert_your_database_url_here';
+mongoose.connect(mongoDB, { useNewUrlParser: true });
+var db = mongoose.connection;
+db.on('error', console.error.bind(console, 'MongoDB connection error:'));
+ +

As discussed in the Mongoose primer above, this code creates the default connection to the database and binds to the error event (so that errors will be printed to the console). 

+ +

Defining the LocalLibrary Schema

+ +

We will define a separate module for each model, as discussed above. Start by creating a folder for our models in the project root (/models) and then create separate files for each of the models:

+ +
/express-locallibrary-tutorial  //the project root
+  /models
+    author.js
+    book.js
+    bookinstance.js
+    genre.js
+
+ +

Author model

+ +

Copy the Author schema code shown below and paste it into your ./models/author.js file. The scheme defines an author has having String SchemaTypes for the first and family names, that are required and have a maximum of 100 characters, and Date fields for the date of birth and death.

+ +
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},
+  }
+);
+
+// Virtual for author's full name
+AuthorSchema
+.virtual('name')
+.get(function () {
+  return this.family_name + ', ' + this.first_name;
+});
+
+// Virtual for author's lifespan
+AuthorSchema
+.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);
+
+
+ +

We've also declared a virtual 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.

+ +
+

Note: 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.
+ 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!

+
+ +

At the end of the module, we export the model.

+ +

Book model

+ +

Copy the Book schema code shown below and paste it into your ./models/book.js 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.

+ +
var mongoose = require('mongoose');
+
+var Schema = mongoose.Schema;
+
+var BookSchema = new Schema(
+  {
+    title: {type: String, required: true},
+    author: {type: Schema.Types.ObjectId, ref: 'Author', required: true},
+    summary: {type: String, required: true},
+    isbn: {type: String, required: true},
+    genre: [{type: Schema.Types.ObjectId, ref: 'Genre'}]
+  }
+);
+
+// Virtual for book's URL
+BookSchema
+.virtual('url')
+.get(function () {
+  return '/catalog/book/' + this._id;
+});
+
+//Export model
+module.exports = mongoose.model('Book', BookSchema);
+
+ +

The main difference here is that we've created two references to other models:

+ + + +

BookInstance model

+ +

Finally, copy the BookInstance schema code shown below and paste it into your ./models/bookinstance.js file. The BookInstance 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.

+ +
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, enum: ['Available', 'Maintenance', 'Loaned', 'Reserved'], default: 'Maintenance'},
+    due_back: {type: Date, default: Date.now}
+  }
+);
+
+// Virtual for bookinstance's URL
+BookInstanceSchema
+.virtual('url')
+.get(function () {
+  return '/catalog/bookinstance/' + this._id;
+});
+
+//Export model
+module.exports = mongoose.model('BookInstance', BookInstanceSchema);
+ +

The new things we show here are the field options:

+ + + +

Everything else should be familiar from our previous schema.

+ +

Genre model - challenge!

+ +

Open your ./models/genre.js 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).

+ +

The definition will be very similar to the other models:

+ + + +

Testando — criando alguns itens

+ +

That's it. We now have all models for the site set up!

+ +

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 independent script to create items of each type:

+ +
    +
  1. Download (or otherwise create) the file populatedb.js inside your express-locallibrary-tutorial directory (in the same level as package.json). + +
    +

    Note: You don't need to know how populatedb.js works; it just adds sample data into the database.

    +
    +
  2. +
  3. Enter the following commands in the project root to install the async module that is required by the script (we'll discuss this in later tutorials, ) +
    npm install async
    +
  4. +
  5. Run the script using node in your command prompt, passing in the URL of your MongoDB database (the same one you replaced the insert_your_database_url_here placeholder with, inside app.js earlier): +
    node populatedb <your mongodb url>​​​​
    + +
    +

    Note for Windows operating system users: If the above command results in the error DeprecationWarning: current URL string parser is deprecated, change the mongoose.connect(mongoDB); line in populatedb.js file with mongoose.connect(mongoDB, { useNewUrlParser:true });

    +
    +
  6. +
  7. The script should run through to completion, displaying items as it creates them in the terminal.
  8. +
+ +
+

Tip: Go to your database on mongoDB Atlas (in the Collections tab). You should now be able to drill down into individual collections of Books, Authors, Genres and BookInstances, and check out individual documents.

+
+ +

Resumo

+ +

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 Book, BookInstance, Author and Genre models for the LocalLibrary website.

+ +

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.

+ +

Veja também

+ + + +

{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs")}}

+ +

Neste módulo

+ + 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 +--- +
{{LearnSidebar}}
+ +

{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs/mongoose", "Learn/Server-side/Express_Nodejs")}}

+ +

Neste  segundo Express Tutorial , mostrará como criar a estrutura do website que depois você poderá colocar templates, chamadas de banco de dados ou rotas específicas.

+ + + + + + + + + + + + +
Pré-requisitos:Preparar o ambiente de desenvolvimento do Node . Revise o Tutorial Express.
Objetivo:Iniciar nosso website usando o "Express Application Generator".
+ +

Visão Geral

+ +

Nesse artigo mostraremos como criar a estrutura do website usando a ferramenta "Express Application Generator ". Neste caso, usaremos a ferramenta para criar o framework para nosso website "LocalLibrary" , 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 template do site e o gerador de CSS. 

+ +

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.

+ +
+

Nota: O "Express Application Generator"  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  "minimal Express", veja Exemplo"Hello world" .

+
+ +

Usando o "Application Generator"

+ +

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:

+ +
npm install express-generator -g
+ +

O gerador tem algumas opções que podem ser visualizadas usando o comando --help (or -h):

+ +
> 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
+
+ +

Você pode simplesmente especificar express para criar um projeto dentro do diretório atual usando Jade view e CSS simples (se você especificar um nome de diretório, o projeto será criado em uma subpasta com esse nome).

+ +
express
+ +

Também pode ser escolhido um "view" (template) usando--view e/ou um gerador de CSS usando --css.

+ +
+

Nota:  As outras opções para escolher os mecanismos de modelo (e.g. --hogan, --ejs, --hbs etc.) são preteridas. Use --view (ou -v)!

+
+ +

Qual engine de "view" devo usar?

+ +

The Express Application Generator allows you to configure a number of popular view/templating engines, including EJS, Hbs, Pug (Jade), Twig, and Vash, 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 out of the box.

+ +
+

Note: If you want to use a template engine that isn't supported by the generator then see Using template engines with Express (Express docs) and the documentation for your target view engine.

+
+ +

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:

+ + + +
+

Tip: There are many resources on the Internet to help you compare the different options!

+
+ +

For this project, we'll use the Pug 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.

+ +

What CSS stylesheet engine should I use?

+ +

The Express Application Generator allows you to create a project that is configured to use the most common CSS stylesheet engines: LESS, SASS, Compass, Stylus.

+ +
+

Note: 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.

+
+ +

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.

+ +

What database should I use?

+ +

The generated code doesn't use/include any databases. Express apps can use any database mechanism supported by Node (Express itself doesn't define any specific additional behavior/requirements for database management).

+ +

We'll discuss how to integrate with a database in a later article.

+ +

Creating the project

+ +

For the sample Local Library app we're going to build, we'll create a project named express-locallibrary-tutorial using the Pug template library and no CSS stylesheet engine.

+ +

First, navigate to where you want to create the project and then run the Express Application Generator in the command prompt as shown:

+ +
express express-locallibrary-tutorial --view=pug
+
+ +

The generator will create (and list) the project's files.

+ +
   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
+ +

At the end of the output, the generator provides instructions on how you install the dependencies (as listed in the package.json file) and then how to run the application (the instructions above are for Windows; on Linux/macOS they will be slightly different).

+ +
+

Note: 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. 

+
+ +

Running the skeleton website

+ +

At this point, we have a complete skeleton project. The website doesn't actually do very much yet, but it's worth running it to show how it works.

+ +
    +
  1. First, install the dependencies (the install command will fetch all the dependency packages listed in the project's package.json file). + +
    cd express-locallibrary-tutorial
    +npm install
    +
  2. +
  3. Then run the application. +
      +
    • On Windows, use this command: +
      SET DEBUG=express-locallibrary-tutorial:* & npm start
      +
    • +
    • On macOS or Linux, use this command: +
      DEBUG=express-locallibrary-tutorial:* npm start
      +
      +
    • +
    +
  4. +
  5. Then load http://localhost:3000/ in your browser to access the app.
  6. +
+ +

You should see a browser page that looks like this:

+ +

Browser for default Express app generator website

+ +

You have a working Express application, serving itself to localhost:3000.

+ +
+

Note: You could also start the app just using the npm start 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:

+ +
>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
+
+
+ +

Enable server restart on file changes

+ +

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.

+ +

One of the easiest such tools for this purpose is nodemon. This is usually installed globally (as it is a "tool"), but here we'll install and use it locally as a developer dependency, 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:

+ +
npm install --save-dev nodemon
+ +

If you still choose to install nodemon globally to your machine, and not only to your project's package.json file:

+ +
npm install -g nodemon
+ +

If you open your project's package.json file you'll now see a new section with this dependency:

+ +
 "devDependencies": {
+    "nodemon": "^1.18.10"
+}
+
+ +

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 scripts section of your package.json. Initially, it will contain one line, which begins with "start". Update it by putting a comma at the end of that line, and adding the "devstart" line seen below:

+ +
  "scripts": {
+    "start": "node ./bin/www",
+    "devstart": "nodemon ./bin/www"
+  },
+
+ +

We can now start the server in almost exactly the same way as previously, but with the devstart command specified:

+ + + +
+

Note: Now if you edit any file in the project the server will restart (or you can restart it by typing rs on the command prompt at any time). You will still need to reload the browser to refresh the page.

+ +

We now have to call "npm run <scriptname>" rather than just npm start, because "start" is actually an NPM command that is mapped to the named script. We could have replaced the command in the start script but we only want to use nodemon during development, so it makes sense to create a new script command.

+
+ +

The generated project

+ +

Let's now take a look at the project we just created.

+ +

Directory structure

+ +

The generated project, now that you have installed dependencies, has the following file structure (files are the items not prefixed with "/"). The package.json file defines the application dependencies and other information. It also defines a startup script that will call the application entry point, the JavaScript file /bin/www. This sets up some of the application error handling and then loads app.js to do the rest of the work. The app routes are stored in separate modules under the routes/ directory. The templates are stored under the /views directory.

+ +
/express-locallibrary-tutorial
+    app.js
+    /bin
+        www
+    package.json
+    package-lock.json
+    /node_modules
+        [about 6700 subdirectories and files]
+    /public
+        /images
+        /javascripts
+        /stylesheets
+            style.css
+    /routes
+        index.jsusers.js
+    /views
+        error.pug
+        index.puglayout.pug
+
+
+ +

The following sections describe the files in a little more detail.

+ +

package.json

+ +

The package.json file defines the application dependencies and other information:

+ +
{
+  "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"
+  }
+}
+
+ +

The dependencies include the express package and the package for our selected view engine (pug). In addition, we have the following packages that are useful in many web applications:

+ + + +

The scripts section defines a "start" script, which is what we are invoking when we call npm start to start the server. From the script definition, you can see that this actually starts the JavaScript file ./bin/www with node. It also defines a "devstart" script, which we invoke when calling npm run devstart instead. This starts the same ./bin/www file, but with nodemon rather than node.

+ +
  "scripts": {
+    "start": "node ./bin/www",
+    "devstart": "nodemon ./bin/www"
+  },
+
+ +

www file

+ +

The file /bin/www is the application entry point! The very first thing this does is require() the "real" application entry point (app.js, in the project root) that sets up and returns the express() application object.

+ +
#!/usr/bin/env node
+
+/**
+ * Module dependencies.
+ */
+
+var app = require('../app');
+
+ +
+

Note: require() is a global node function that is used to import modules into the current file. Here we specify app.js module using a relative path and omitting the optional (.js) file extension.

+
+ +

The remainder of the code in this file sets up a node HTTP server with app 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.

+ +

app.js

+ +

This file creates an express application object (named app, 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:

+ +
var express = require('express');
+var app = express();
+...
+module.exports = app;
+
+ +

Back in the www entry point file above, it is this module.exports object that is supplied to the caller when this file is imported.

+ +

Let's work through the app.js file in detail. First, we import some useful node libraries into the file using require(), including http-errors, expressmorgan and cookie-parser that we previously downloaded for our application using NPM; and path, which is a core Node library for parsing file and directory paths.

+ +
var createError = require('http-errors');
+var express = require('express');
+var path = require('path');
+var cookieParser = require('cookie-parser');
+var logger = require('morgan');
+
+ +

Then we require() 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.

+ +
var indexRouter = require('./routes/index');
+var usersRouter = require('./routes/users');
+
+ +
+

Note: At this point, we have just imported the module; we haven't actually used its routes yet (this happens just a little bit further down the file).

+
+ +

Next, we create the app object using our imported express 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 'views' value to specify the folder where the templates will be stored (in this case the subfolder /views). Then we set the 'view engine' value to specify the template library (in this case "pug").

+ +
var app = express();
+
+// view engine setup
+app.set('views', path.join(__dirname, 'views'));
+app.set('view engine', 'pug');
+
+ +

The next set of functions call app.use() to add the middleware libraries into the request handling chain. In addition to the 3rd party libraries we imported previously, we use the express.static middleware to get Express to serve all the static files in the /public directory in the project root.

+ +
app.use(logger('dev'));
+app.use(express.json());
+app.use(express.urlencoded({ extended: false }));
+app.use(cookieParser());
+app.use(express.static(path.join(__dirname, 'public')));
+
+ +

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 parts of the site:

+ +
app.use('/', indexRouter);
+app.use('/users', usersRouter);
+
+ +
+

Note: The paths specified above ('/' and '/users') are treated as a prefix to routes defined in the imported files. So for example, if the imported users module defines a route for /profile, you would access that route at /users/profile. We'll talk more about routes in a later article.

+
+ +

The last middleware in the file adds handler methods for errors and HTTP 404 responses.

+ +
// 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');
+});
+
+ +

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 /bin/www).

+ +
module.exports = app;
+ +

Routes

+ +

The route file /routes/users.js is shown below (route files share a similar structure, so we don't need to also show index.js). First, it loads the express module and uses it to get an express.Router 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 app.js).

+ +
var express = require('express');
+var router = express.Router();
+
+/* GET users listing. */
+router.get('/', function(req, res, next) {
+  res.send('respond with a resource');
+});
+
+module.exports = router;
+
+ +

The route defines a callback that will be invoked whenever an HTTP GET request with the correct pattern is detected. The matching pattern is the route specified when the module is imported ('/users') plus whatever is defined in this file ('/'). In other words, this route will be used when an URL of /users/ is received.

+ +
+

Tip: Try this out by running the server with node and visiting the URL in your browser: http://localhost:3000/users/. You should see a message: 'respond with a resource'.

+
+ +

One thing of interest above is that the callback function has the third argument 'next', and is hence a middleware function rather than a simple route callback. While the code doesn't currently use the next argument, it may be useful in the future if you want to add multiple route handlers to the '/' route path.

+ +

Views (templates)

+ +

The views (templates) are stored in the /views directory (as specified in app.js) and are given the file extension .pug. The method Response.render() 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 /routes/index.js you can see how that route renders a response using the template "index" passing the template variable "title".

+ +
/* GET home page. */
+router.get('/', function(req, res, next) {
+  res.render('index', { title: 'Express' });
+});
+
+ +

The corresponding template for the above route is given below (index.pug). We'll talk more about the syntax later. All you need to know for now is that the title variable (with value 'Express') is inserted where specified in the template.

+ +
extends layout
+
+block content
+  h1= title
+  p Welcome to #{title}
+
+ +

Challenge yourself

+ +

Create a new route in /routes/users.js that will display the text "You're so cool" at URL /users/cool/. Test it by running the server and visiting http://localhost:3000/users/cool/ in your browser

+ + + +

Summary

+ +

You have now created a skeleton website project for the Local Library and verified that it runs using node. 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.

+ +

Next, we'll start modifying the skeleton so that it works as a library website.

+ +

See also

+ + + +

{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs/mongoose", "Learn/Server-side/Express_Nodejs")}}

+ +

In this module

+ + 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 +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs")}}
+ +

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).

+ + + + + + + + + + + + +
Pré-requisitos:Leia a Indrodução ao Express. Para os próximos artigos, você também precisa ler Conhecendo Node como ambiente de desenvolvimento
Objetivos:Apresentar a aplicação que será desenvolvida ao longo deste tutorial e permitir aos leitores entender quais tópicos serão abordados.
+ +

Visão Geral

+ +

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. 

+ +

Neste passo a passo você vai: 

+ + + +

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.

+ +

O site da Biblioteca Local

+ +

LocalLibrary 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. 

+ +

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:

+ + + +

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).

+ +

Estou perdido, onde encontro o código-fonte?

+ +

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.

+ +

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.

+ +

Se ficar perdido no meio do caminho, fique calmo. Você pode acessar o código inteiro pelo Github.

+ +
+

Nota:  As versões específicas do Node, Express e outros módulos que adotados no tutorial estão listados no arquivo package.json.

+
+ +

Sumário

+ +

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.

+ +

{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs")}}

+ +

Neste módulo

+ + 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 +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/First_steps/Introduction", "Learn/Server-side/First_steps/Web_frameworks", "Learn/Server-side/First_steps")}}
+ +

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.

+ +

+ + + + + + + + + + + + +
Pré requisitos:Conhecimento básico em informática. Uma compreensão básica do que é um servidor web.
Objetivos: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.
+ +

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.

+ +

Web servers e HTTP (uma introdução)

+ +

Navegadores Web se comunicam com servidores Web usando o HyperTextTransfer Protocol (HTTP). 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.

+ +

A requisição inclui:

+ + + +

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( HTTP Response status code) um código de status de resposta HTTP que indica se a solicitação foi bem sucedida ou não (e.g. "200 OK" para sucesso, "404 Not Found" se o recurso não puder ser encontrado, "403 Forbidden" se o usuário não estiver autorizado para ver o recurso, etc). O corpo de uma resposta bem sucedida a uma solicitação  GET conteria o recurso solicitado.

+ +

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.

+ +

Os sites estáticos e dinâmicos (discutidos nas seções a seguir) usam exatamente o mesmo protocolo / padrões de comunicação.

+ +

Exemplo de requisição/resposta GET

+ +

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.

+ +
+

O formato das mensagens HTTP é definido em um "padrão da  web" (RFC7230). Você não precisa saber esse nível de detalhe, mas pelo menos agora você sabe de onde vem tudo isso.

+
+ +

A requisição

+ +

Cada linha da solicitação contém informações sobre ela. A primeira parte é chamada de  header, e contém informações úteis sobre o pedido, Da mesma forma que um HTML head contém informações úteis sobre um documento HTML(mas não o conteúdo real em si, que está no corpo):

+ +
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
+Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7
+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
+
+ +

A primeira e a segunda linhas contêm a maioria das informações sobre as quais falamos acima:

+ + + +

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 (Cookie: sessionid=6ynxs23n521lu21b1t136rhbv7ezngie; ...).

+ +

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:

+ + + +

As solicitações HTTP também podem ter um corpo, mas está vazio neste caso

+ +

A resposta

+ +

A primeira parte da resposta para esta solicitação é mostrada abaixo. O header(cabeçalho) contém informações, como as seguintes:

+ + + +

No final da mensagem vemos o conteúdo do corpo( body content) — que contém o HTML real retornado pela solicitação.

+ +
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>
+  ...
+
+ +

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 X-Frame-Options: DENY  diz ao navegador para não permitir que esta página seja incorporada em outros sites {{htmlelement("iframe")}} ).

+ +

Exemplo de request(solicitação)/response(resposta) POST

+ +

Um HTTP POST é feito quando você envia um formulário contendo informações a serem salvas no servidor.

+ +

A requisição

+ +

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 GET mostrado anteriormente, embora a primeira linha reconheça esta solicitação como um POST

+ +
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=
+ +

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: &user-fullname=Hamish+Willee).

+ +

A resposta

+ +

A resposta de solicitação é mostrada abaixo. O código de status "302 Found" 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( Location field). As informações são semelhantes às da resposta a uma solicitação GET .

+ +
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
+
+ +
+

Note: As respostas e solicitações HTTP  mostradas nesse exemplo foram capturadas utilizando o aplicativo Fiddler , mas você pode obter informações semelhantes utilizando web sniffers (e.g. Websniffer) ou extensões de navegador como o  HttpFox. 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 Network Monitor  no Firefox).

+
+ +

Sites estáticos

+ +

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 /static/myproduct1.html, 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. myproduct2.html) 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.

+ +
+

Note: 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.

+
+ +

Vamos recapitular como isso funciona, olhando novamente para o diagrama de arquitetura de site estático que vimos no último artigo.

+ +

A simplified diagram of a static web server.

+ +

Quando o usuário deseja navegar em uma página, O navegador envia uma solicitação HTTP GET  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 HTTP Response status code de "200 OK" (indicando). O servidor pode retornar um diferente código de status,  por exemplo "404 Not Found" se o arquivo não estiver presente no servidor, ou "301 Moved Permanently" se o arquivo existe, mas foi redirecionado para um local diferente.

+ +

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).

+ +

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.

+ +

Sites dinâmicos

+ +

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 GET 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:

+ +

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

+ +

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.

+ +

Anatomia de uma solicitação dinâmica

+ +

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.

+ +

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.

+ +

This is a diagram of a simple web server with step numbers for each of step of the client-server interaction.

+ +

Após o treinador enviar o formulário com o nome da equipe e número de jogadores, a sequência de operações é:

+ +
    +
  1. O navegador cria uma solicitação HTTP GET  para o servidor usando a URL base para o recurso(/best) e codifica o número do time e do jogador como parâmetros de URL (e.g. /best?team=my_team_name&show=11) ou como parte do padrão de URL (e.g. /best/my_team_name/11/). A solicitação GETé usada porque a solicitação está apenas buscando dados (não modificando dados).
  2. +
  3. 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).
  4. +
  5. Web Application identifica que a intenção da solicitação é obter a "lista da melhor equipe" com base no URL(/best/)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).
  6. +
  7. 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.
  8. +
  9. +

    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.

    +
  10. +
  11. 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).
  12. +
  13. 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).
  14. +
+ +

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 POST

+ +

Fazendo outro trabalho

+ +

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.

+ +

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.

+ +

Retornando algo diferente de HTML

+ +

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.).

+ +

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.).

+ +


+ Web frameworks simplificam a programação da Web do lado do servidor

+ +

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.

+ +

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.

+ +

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 /best será passado para uma função chamada index() no módulo views. Uma solicitação que tem o padrão "/best/junior", será passada para a fução view junior() .

+ +
# 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),
+]
+ +
+

Nota : Os primeiros parâmetros da função url() pode parecer um pouco estranho (e.g. r'^junior/$') 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."

+
+ +

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.

+ +

O exemplo abaixo obtém uma lista de todas as equipes que têm o exato (diferencia maiúsculas de minúsculas) team_type de  "junior" —Observe o formato field name (team_type) seguido por sublinhado duplo e, em seguida, o tipo de correspondência a usar (neste caso exact). 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.

+ +
#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)
+
+ +

Depois da função junior()  obter a lista de junior teams, é chamada a função render() , passando o original HttpRequest, um modelo HTML e um objeto de "contexto" que define as informações a serem incluídas no modelo. A função render() é uma função de conveniência que gera HTML usando um contexto e um modelo HTML e o retorna em um objeto HttpResponse .

+ +

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.

+ +

Resumo

+ +

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.

+ +

Em um módulo a seguir, vamos ajudá-lo a escolher o melhor Web Framework para seu primeiro site.

+ +

{{PreviousMenuNext("Learn/Server-side/First_steps/Introduction", "Learn/Server-side/First_steps/Web_frameworks", "Learn/Server-side/First_steps")}}

+ +

Neste módulo

+ + 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 +--- +
{{LearnSidebar}}
+ +

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?".

+ +

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.

+ +

Por fim, fornecemos um artigo introdutório de alto nível sobre segurança do servidor da web

+ +

Finalmente,nós iremos fornecer uma introdução de alto nível. 

+ +

Pré-requisitos

+ +

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.

+ +

Entretanto,você precisa saber como a web funciona.Nós recomendamos que você leia primeiro os seguintes tópicos:

+ + + +

Com o entendimento básico disso, você estará pronto para trabalhar nos módulos desta seção.

+ +

Guias

+ +
+
 Introdução ao serve-side
+
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.
+
Visão geral do cliente-servidor
+
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.
+
Framework  server-side
+
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.
+
Segurança do website
+
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.
+
+ +

Avaliação

+ + + +

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.

diff --git "a/files/pt-br/learn/server-side/first_steps/introdu\303\247\303\243o/index.html" "b/files/pt-br/learn/server-side/first_steps/introdu\303\247\303\243o/index.html" new file mode 100644 index 0000000000..e5cc0b991c --- /dev/null +++ "b/files/pt-br/learn/server-side/first_steps/introdu\303\247\303\243o/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 +--- +
{{LearnSidebar}}
+ +
{{NextMenu("Learn/Server-side/First_steps/Client-Server_overview", "Learn/Server-side/First_steps")}}
+ +

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.

+ + + + + + + + + + + + +
Pré-requisitos :Conhecimento básico de informática. Uma compreensão básica do que é um servidor web
+

Objetivo :

+
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.
+ +

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).

+ +

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.

+ +

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.

+ +

No mundo moderno do desenvolvimento web, aprender sobre desenvolvimento do lado do servidor é extremamente recomendado.

+ +

O que é programação de site do lado do servidor ?

+ +

Navegadores comunicam-se com  web servers  utilizando o HyperText Transfer Protocol ({{glossary("HTTP")}}). Quando você clica em um link em uma página da web, envia um formulário ou faz uma pesquisa, uma HTTP request(solicitação HTTP) é enviada do seu navegador para o servidor de destino.

+ +

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 query string), como dados POST (dados enviados pelo método HTTP POST ), ou em associado {{glossary("Cookie", "cookies")}} .

+ +

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 HTTP response . 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). 

+ +

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.

+ +

Sites estáticos

+ +

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.

+ +

O servidor recupera o documento solicitado de seu sistema de arquivos e retorna uma resposta HTTP contendo o documento e um success status (geralmente, 200 OK). Se o arquivo não puder ser recuperado por algum motivo, um status de erro será retornado(Veja client error responses e server error responses).

+ +

A simplified diagram of a static web server.

+ +

Sites dinâmicos

+ +

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). 

+ +

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).

+ +

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 "server-side programming" (ou às vezes "back-end scripting").

+ +

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.

+ +

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.).

+ +

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.

+ +

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).

+ +
+

A programação do lado do servidor e do lado cliente são iguais ?

+
+ +

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:

+ + + +

O código em execução no navegador  é conhecido como client-side code 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.

+ +

O código do lado do cliente é geralmente escrito em HTMLCSS, e JavaScript — 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)

+ +

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.

+ +

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.

+ +

Desenvolvedores geralmente escrevem seus códigos utilizando web frameworks. 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.

+ +

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.).

+ +
+

Nota : 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.

+ +

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.

+
+ +
+

O que você pode fazer no lado do servidor ?

+ +

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.

+
+ +

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.

+ +

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 .

+ +

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!

+ +

Armazenamento eficiente e entrega de informações

+ +

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.

+ +

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).

+ +

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.

+ +

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).

+ +
+

Nota : 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:

+ +
    +
  1. Vá em Amazon ou em outro site comercial.
  2. +
  3. Pesquise várias palavras-chave e observe como a estrutura da página não muda, embora os resultados mudem.
  4. +
  5. 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.
  6. +
+ +

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.

+
+ +

Experiência de usuário personalizada

+ +

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.

+ +

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.

+ +
+

Nota: Google Maps salva sua pesquisa e histórico de visitas. Locais visitados ou pesquisados ​​com frequência são destacados mais do que outros.

+ +

Os resultados de pesquisa do Google são otimizados com base em pesquisas anteriores.

+ +
    +
  1.  Vá em Google search.
  2. +
  3.  Pesquise por "futeboll".
  4. +
  5. Agora tente digitar "favorito" na caixa de pesquisa e observe as previsões de pesquisa do preenchimento automático.
  6. +
+ +

Coincidência ? Nada!

+
+ +

Acesso controlado ao conteúdo

+ +

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.

+ +

Exemplos do mundo real, incluem :

+ + + +
+

Nota : 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?

+
+ +

Sessão de armazenamento / informações de estado

+ +

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.

+ +

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.

+ +
+

Note: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.

+
+ +

Notificações e comunicação

+ +

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.

+ +

Alguns exemplos, incluem :

+ + + +
+

Nota: 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.

+
+ +

Análise de dados

+ +

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.

+ +

Por exemplo, Amazon e Google anunciam produtos com base em pesquisas anteriores (e compras).

+ +
+

Nota: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.

+ +

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!

+
+ +

Resumo

+ +

Parabéns, você chegou ao final do primeiro artigo sobre programação do lado do servidor.

+ +

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) .

+ +

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.

+ +

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.

+ +

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.

+ +

{{NextMenu("Learn/Server-side/First_steps/Client-Server_overview", "Learn/Server-side/First_steps")}}

+ +

Nesse módulo

+ + 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 +--- +
{{LearnSidebar}}
+ +
{{PreviousMenu("Learn/Server-side/First_steps/Web_frameworks", "Learn/Server-side/First_steps")}}
+ +

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.

+ + + + + + + + + + + + +
Pré-requisitos:Conhecimento básico em informática.
Objetivo: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.
+ +

O que é segurança no site?

+ +

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.

+ +

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.

+ +

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 framework (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.

+ +

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.

+ +
+

Nota: Este é um tópico introdutório projetado para ajudá-lo a começar a pensar na segurança do site, mas não é exaustivo.

+
+ +

Ameaças à segurança do site

+ +

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 não é paranóico o suficiente sobre os dados provenientes do navegador.

+ +

Cross-Site Scripting (XSS)

+ +

XSS é um termo usado para descrever uma classe de ataques que permitem que um invasor injete scripts do lado do cliente através do site nos navegadores de outros usuários. Como o código injetado chega ao navegador a partir do site, o código é confiável 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.

+ +
+

Nota: As vulnerabilidades XSS têm sido historicamente mais comuns do que qualquer outro tipo de ameaça à segurança.

+
+ +

As vulnerabilidades do XSS são divididas em refletidas e persistentes, de acordo como o site retorna os scripts injetados para um navegador.

+ + + +

Embora os dados das solicitações POST ou GET 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.

+ +

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 <script>, <object>, <embed> e <link> .

+ +

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.

+ +

Injeção de SQL

+ +

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.

+ +

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.

+ +

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 (nomeUsuario) fornecido a partir de um formulário HTML:

+ +
statement = "SELECT * FROM usuarios WHERE name = '" + nomeUsuario + "';"
+ +

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 nomeUsuario.

+ +
SELECT * FROM usuarios WHERE name = 'a';DROP TABLE usuarios; SELECT * FROM userinfo WHERE 't' = 't';
+
+ +

A instrução modificada cria uma instrução SQL válida que exclui a tabela de usuarios e seleciona todos os dados da tabela userinfo (que revela as informações de cada usuário). Isso funciona porque a primeira parte do texto injetado ( a';) completa a declaração original.

+ +

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 'escape' em todos os caracteres na entrada do usuário que tenham um significado especial no SQL.

+ +
+

Nota: A instrução SQL trata o caractere ' como o início e o final de uma cadeia de caracteres literal. Ao colocar uma barra invertida na frente desse caractere (\'), "escapamos" do símbolo e dizemos ao SQL para tratá-lo como um caractere (apenas uma parte da string).

+
+ +

Na declaração a seguir, escapamos o caractere '. O SQL agora interpretará o nome como toda a string em negrito (que é um nome muito estranho, mas não prejudicial).

+ +
SELECT * FROM usarios WHERE name = 'a\';DROP TABLE usuarios; SELECT * FROM userinfo WHERE \'t\' = \'t';
+
+
+ +

Frameworks web 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.

+ +
+

Nota: Esta seção baseia-se fortemente nas informações da Wikipedia.

+
+ +

Cross-Site Request Forgery (CSRF)

+ +

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.

+ +

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 POST 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 Enviar, disfarçado como um link para um site "fique rico rapidamente").

+ +

Se um usuário clicar no botão enviar, uma solicitação HTTP POST 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.

+ +

O resultado é que qualquer usuário que clicar no botão Enviar enquanto estiver conectado ao site de negociação fará a transação. John fica rico.

+ +
+

Nota: 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.

+
+ +

Uma maneira de impedir esse tipo de ataque é o servidor exigir que as solicitações POST 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.

+ +

Frameworks web geralmente incluem esses mecanismos de prevenção para CSRF.

+ +

Outras ameaças

+ +

Outros ataques e vulnerabilidades comuns incluem:

+ + + +

Para obter uma lista abrangente das ameaças à segurança do site, consulte Categoria: explorações de segurança da Web (Wikipedia) e Categoria: Ataque (Projeto de Segurança para Aplicações Web Abertos).

+ +

Algumas mensagens-chave

+ +

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.

+ +
+

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 GET, POST, cabeçalhos HTTP, cookies e arquivos enviados por usuários. Sempre verifique e limpe todos os dados recebidos. Sempre assuma o pior.

+
+ +

Uma série de outras etapas concretas que você pode executar são:

+ + + +

Frameworks web podem ajudar a mitigar muitas das vulnerabilidades mais comuns.

+ +

Resumo

+ +

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.

+ +

Com este artigo, você chegou ao final deste módulo, 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 Framework web e iniciar a programação.

+ +

{{PreviousMenu("Learn/Server-side/First_steps/Web_frameworks", "Learn/Server-side/First_steps")}}

+ +

Neste módulo

+ + 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 +--- +
{{LearnSidebar}}
+ +

O tópico de Websites Dinâmicos - Programação do lado do servidor é 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.

+ +

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  HTML, CSS, e JavaScript), 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.

+ +

No mundo moderno do desenvolvimento web, aprender sobre o desenvolvimento do lado do servidor é altamente recomendado.

+ +

Caminho de aprendizagem

+ +

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.

+ +

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.

+ +

Você precisará entender "como a web funciona". Recomendamos que você leia primeiro os seguintes tópicos:

+ + + +

Com essa compreensão básica, você estará pronto para percorrer os módulos desta seção.

+ +

Modulos

+ +

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.

+ +
+
Primeiros passos de programação do site do lado do servidor
+
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.
+
Framework Web Django (Python)
+
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.
+
Framework Web Express (Node.js/JavaScript)
+
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.
+
-- cgit v1.2.3-54-g00ecf