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 ++++ 15 files changed, 6602 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 (limited to 'files/pt-br/learn/server-side/django') 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

+ + -- cgit v1.2.3-54-g00ecf