Django Tutorial Parte 2: Criando o "esqueleto" de um site - Aprendendo desenvolvimento web

Django Tutorial Parte 2: Criando o "esqueleto" de um site
=========================================================

* Anterior
* Menu: Django
* Próxima

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. 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.
3. Registre os novos aplicativos para inclui-los no projeto.
4. Conecte o mapeador de url/path para cada aplicativo.

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:

```bash
locallibrary/         # Pasta do website
    manage.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:

```bash
mkdir locallibrary
cd locallibrary
```

Crie um novo projeto usando o comando `django-admin startproject`, como mostrado abaixo, e entre nessa pasta.

```bash
django-admin startproject locallibrary
cd locallibrary
```

O comando `django-admin` cria uma estrutura com pastas e arquivos como a mostrada abaixo:

```bash
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:

* **\_\_init\_\_.py** é um arquivo em branco que instrui o Python a tratar esse diretório como um pacote Python.
* **settings.py** contém todas as definições do website. É onde nós registramos qualquer aplicação que criarmos, a localização de nossos arquivos estáticos, configurações de banco de dados etc.
* **urls.py** define os mapeamentos de URL para visualização do site. Mesmo que esse arquivo possa conter *todo* o código para mapeamento de URL, é mais comum delegar apenas o mapeamento para aplicativos específicos, como será visto mais adiante.
* **wsgi.py** é usado para ajudar na comunicação entre seu aplicativo Django e o web server. Você pode tratar isso como um boilerplate.

O script **manage.py** é usado para criar aplicações, trabalhar com bancos de dados, e iniciar o webserver de desenvolvimento.

Criando o aplicativo de catálogo
--------------------------------

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

```bash
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:

```bash
locallibrary/
    manage.py
    locallibrary/
    catalog/
        admin.py
        apps.py
        models.py
        tests.py
        views.py
        __init__.py
        migrations/
```

Além disso, nós temos:

* Uma pasta *migrations*, usada para guardar "*migrações*" — arquivos que permitem atualizar automaticamente seu banco de dados à medida que você modifica seus models.
* **\_\_init\_\_.py** — Um arquivo em branco criado de modo que Django/Python reconheça a pasta como um Python Package e permita que você use seus objetos dentro de outras partes do projeto.

**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 precisaremos em nosso exemplo).

Registrando o aplicativo de catálogo
------------------------------------

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.

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

```python
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:

```python
TIME_ZONE = 'America/Sao\_Paulo'
```

Tem outras duas definições que você não vai mudar agora, mas que deve ficar ciente:

* `SECRET_KEY`. É uma chave secreta que é usada como parte da estratégia de segurança dos websites Django. Se você não está protegendo seu código durante o desenvolvimento, você precisará usar um código diferente (que talvez seja lido de uma variável de ambiente ou arquivo) quando colocar no ambiente de produção.
* `DEBUG`. Isto habilita a depuração de logs sejam exibidos em um erro ao invés de respostas de status de código HTTP. Isso deve ser definido como `False` na produção, já que informações de debug são úteis para invasores, mas por enquanto nós manteremos `True.`
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.

```python
"""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**).

```python
# 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:

```python
#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.

```python
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.

```python
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.

```python
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**):

```bash
python3 manage.py makemigrations
python3 manage.py migrate
```

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

```bash
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](/pt-BR/docs/Learn/Server-side/Django/skeleton_website/django_404_debug_page.png)

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

* Codificando seu primeiro app Django - parte 1 (Documentação Django)
* Aplicativos (Documentação Django). Contém informações de como configurar aplicativos.
* Anterior
* Menu: Django
* Próxima


Tutorial Django Parte 3: Usando models - Aprendendo desenvolvimento web

Tutorial Django Parte 3: Usando models
======================================

* Anterior
* Menu: Django
* Próxima

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](/pt-BR/docs/Learn/Server-side/Django/Models/local_library_model_uml.png)

 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:

```python
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:

* `max_length=20` — Afima que o valor máximo do comprimento desse campo é de 20 caracteres.
* `help_text='Enter field documentation'` — fornece um rótulo de texto para exibir uma ajuda para os usuários saberem qual valor fornecer, quando esse valor é inserido por um usuário por meio de um formulário HTML.

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:

* help\_text: Fornece um rótulo de texto para formulários HTML (por exemplo, no site admin), conforme descrito acima.
* verbose\_name: Um nome legível para o campo usado nos rótulos de campo. Se não for especificado, o Django irá inferir o nome detalhado do campo `name`.
* default: O valor padrão para o campo. Isso pode ser um valor ou um objeto que pode ser chamado. Cada vez que o objeto for chamado será criado um novo registro.
* null: Se for `True`, o Django armazenará valores em branco como `NULL` no banco de dados, para campos onde isso é apropriado (um `CharField` irá armazenar uma string vazia). O padrão é `False`.
* blank:Se for `True`, o campo poderá ficar em branco nos seus formulários. O padrão é `False`, o que significa que a validação de formulário do Django forçará você a inserir um valor. Isso é frequentemente usado com `null = True`, porque se você permitir valores em branco, também desejará que o banco de dados possa representá-los adequadamente.
* choices: Um grupo de escolhas para este campo. Se isso for fornecido, o padrão widget de formulário correspondente será uma caixa de seleção com essas opções, em vez do campo de texto padrão.
* primary\_key:Se `True`, define o campo atual como a chave primária do modelo (uma chave primária é uma coluna especial do banco de dados, designada para identificar exclusivamente as diferentes tabelas) . Se nenhum campo for especificado como a chave primária, o Django adicionará automaticamente um campo para essa finalidade.

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.

* CharField é usado para definir um tamanho fixo (médio a curto) para a string. Você deve especificar o `max_length (tamanho máximo) para o dado que será armazenado.`
* TextField é usado para grandes strings de comprimento variado. Você pode especificar um `max_length` (tamanho máximo) para o campo, mas isso é usado somente quando o campo é exibido em formulários (forms) (ele não é imposto no nível do banco de dados).
* IntegerField é um campo para armazenar números inteiros e para validar valores inseridos como números inteiros em formulários.
* DateField e DateTimeField são usados para armazenar / representar datas e informações de data / hora (como os objetos Python `datetime.date` in e `datetime.datetime`, respectivamente). Esses campos também podem declarar os parâmetros (mutuamente exclusivos) `auto_now = True` (para definir o campo para a data atual toda vez que o modelo é salvo), `auto_now_add` (para definir a data em que o primeiro modelo foi criado) e `default` (para definir uma data padrão que pode ser substituída pelo usuário).
* EmailField é usada para armazenara e validar em endereço de email.
* FileField e ImageField são usados para carregar arquivos e imagens respectivamente, (o `ImageField` simplesmente valida de forma adicional que o arquivo enviado é uma imagem). Eles têm parâmetros para definir como e onde os arquivos enviados são armazenados.
* AutoField é um tipo especial de `IntegerField` que é incrementada automaticamente. Uma chave primária desse tipo é adicionada de forma automatica ao seu modelo, se você não especificar explicitamente um.
* ForeignKey é usado para especificar um relacionamento um-para-muitos com outro modelo do banco de dados (por exemplo, um carro tem um fabricante, mas um fabricante pode fazer muitos carros). O lado "um" do relacionamento é o modelo que contém a "chave" (os modelos que contêm uma "chave estrangeira" referem-se a essa "chave" e estão no lado "muitos" de tal relacionamento).
* ManyToManyField é usado para especificar um relacionamento muitos-para-muitos (por exemplo, um livro pode ter vários gêneros e cada gênero pode conter vários livros). Em nosso aplicativo de biblioteca, usaremos isso de maneira muito semelhante às `ForeignKeys`, mas elas podem ser usadas de maneiras mais complicadas para descrever as relações entre os grupos. Eles têm o parâmetro `on_delete` para definir o que acontece quando o registro associado é excluído (por exemplo, um valor de `models.SET_NULL` simplesmente definiria o valor como `NULL`).

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.

```python
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:

```python
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:

```python
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.

```python
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.

```python
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 ()`.

```python
# 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.

```python
# 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.

```python
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.

```python
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:

```python
# 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.

```python
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

* `ForeignKey` para identificar o `Book` associado (cada livro pode ter muitos exemplares, porém uma cópia pode ter sometne um `Book`).
* `CharField` para representar o imprint (edição específica) do livro.

```python
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:

* `UUIDField` é usado no campo `id` para definí-lo como `primary_key` deste model. Este tipo de campo aloca um valor único global para cada instância (um para cada livro encontrado na biblioteca).
* `DateField` é usado para a data `due_back` (na qual o livro deve retonar e ficar disponível após um empréstimo ou uma manutenção). O valor pode ser `blank` ou `null` (para quando o livro estiver disponível). O model metadata (`Class Meta`) usa este campo para ordenar os registros quando eles são retornados em uma query.
* `status` é um `CharField` que define uma lista de opção/seleção. Como pode ser visto, nós definimos uma dupla contendo pares de valores-chave e a passamos no argumento da opção. O valor do par valor-chave é um valor que o usuário pode selecionar, enquanto que a chave é o valor que realmetne será salvo se a opção for selecionada. Nós também definimos um valor default como "m" (maintenance), uma vez que os livros serão inicialmente criados como indisponíveis até que eles sejam disponibilizados nas prateleiras.

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:

* Começando com Python 3.6, pode ser usada a sintaxe de interpolação (também conhecida como f-strings): `f'{self.id} ({self.book.title})'`.
* Em versões anteriores deste tutorial, nós estávamos usando a sintaxe de formatted string, a qual também é uma maneira válida de formatar strings em Python (e.g. `'{0} ({1})'.format(self.id,self.book.title)`).

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

```python
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:

* O idioma seria associado ao `Book`, `BookInstance`, ou algum outro objeto?
* Os diferentes idiomas seriam representados usando model, como campo de texto livre ou codificado como uma lista de seleção?

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

* Escrevendo nossa primeira app Django, parte 2 (Django docs)
* Fazendo queries (Django Docs)
* Referência a QuerySet API (Django Docs)
* Anterior
* Menu: Django
* Próxima


Tutorial Django Parte 9: Trabalhando com formulários - Aprendendo desenvolvimento web

Tutorial Django Parte 9: Trabalhando com formulários
====================================================

* Anterior  (en-US)
* Menu: Django
* Próxima

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 (en-US).
  |
| 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](/pt-BR/docs/Learn/Server-side/Django/Forms/admin_book_add.png)

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 (en-US). 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](/pt-BR/docs/Learn/Server-side/Django/Forms/form_example_name_field.png)

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

```html
<form action="/team\_name\_url/" method="post">
  <label for="team\_name">Enter name: </label>
  <input
 id="team\_name"
 type="text"
 name="name\_field"
 value="Default name for team." />
  <input type="submit" value="OK" />
</form>
```

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

* `action`: O recurso/URL para onde os dados devem ser enviados para processamento quando o formulário é enviado. Se isso não estiver configurado (ou configurado para uma string vazia), o formulário será enviado de volta para URL da página atual.
* `method`: O método HTTP method utilizado para enviar os dados: *post* or *get*.
    + O método `POST` deve sempre ser utilizado se os dados forem resultar em uma alteração no banco de dados do servidor, pois é mais resistente a ataques de falsificação de solicitação entre sites.
    + O método `GET` deve ser utilizado somente para formulários que não alteram dados de usuário (um formulário de busca, por exemplo). Ele é recomendado para quando você quiser poder favoritar ou compartilhar a URL.

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.](/pt-BR/docs/Learn/Server-side/Django/Forms/form_handling_-_standard.png)

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. 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.
3. 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.)
4. 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.
5. 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.)
6. Quando todas as ações estiverem concluídas, redirecione o usuário para outra página.

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:

```python
from django import forms

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

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

* required: Se `True`, o campo não pode ser deixado em branco ou receber um valor `None`. Os campos são obrigatórios por padrão, então você deve definir `required=False` para permitir valores em branco no formulário.
* label: O label a ser usado ao renderizar o campo em HTML. Se um label não for especificado, o Django criará um a partir do nome do campo colocando em maiúscula a primeira letra e substituindo sublinhados por espaços (e.g. *Renewal date*).
* label\_suffix: Por padrão, dois pontos são exibidos após o rótulo (e.g. Renewal date\*\*:\*\*). Esse argumento permite especificar um sufixo diferente contendo outros caractere(s).
* initial: O valor inicial para o campo quando o formulário é exibido.
* widget: O widget de exibição a ser usado.
* help\_text (como visto no exemplo acima): Texto adicional que pode ser exibido em formulários para explicar como usar o campo.
* error\_messages: Uma lista de mensagens de erro para o campo. Você pode substituí-los por suas próprias mensagens, se necessário.
* validators: Uma lista de funções que serão chamadas no campo quando validadas.
* localize:Permite a localização da entrada de dados do formulário (consulte o link para obter mais informações).
* disabled: O campo é exibido, mas seu valor não pode ser editado se este for `True`. O padrão é `False`.

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

```python
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**.

```python
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.

```python
import datetime

from django.shortcuts import render, get_object_or_404
from django.http import HttpResponseRedirect
from django.urls import reverse

from catalog.forms import RenewBookForm

def renew\_book\_librarian(request, pk):
    book_instance = get_object_or_404(BookInstance, pk=pk)

    # If this is a POST request then process the Form data
    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*:

* `get_object_or_404()`: Retorna um objeto especificado de um modelo com base em seu valor de chave primária, e gera uma exceção `Http404` (não encontrada) se o registro não existir.
* `HttpResponseRedirect`: Isso cria um redirecionamento para uma URL especificada (código de status HTTP 302).
* `reverse()`: Isso gera uma URL a partir de uma configuração de nome de URL e um conjunto de argumentos. É o equivalente em Python da tag `url` que usamos em nossos *templates*.
* `datetime`: Uma biblioteca Python para a manipulação de dadas e tempo.

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

```python
    book_instance = get_object_or_404(BookInstance, pk=pk)

    # If this is a GET (or any other method) create the default form
    else:
        proposed_renewal_date = datetime.date.today() + datetime.timedelta(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.

```python
    book_instance = get_object_or_404(BookInstance, pk=pk)

    # If this is a POST request then process the Form data
    if request.method == 'POST':

        # Create a form instance and populate it with data from the request (binding):
        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 atributo`form.cleaned_data` (Ex. `data = form.cleaned_data['renewal_date']`). Aqui, apenas salvamos os dados no atributo `due_back` do objeto `BookInstance` associado.

**Aviso:** **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 (en-US)). 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:

```html
{% extends "base_generic.html" %}

{% block content %}
  <h1>Renew: {{ book_instance.book.title }}</h1>
  <p>Borrower: {{ book_instance.borrower }}</p>
  <p{% if book_instance.is_overdue %} class="text-danger"{% endif %}>Due date: {{ book_instance.due_back }}</p>

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

```html
<tr>
  <th><label for="id\_renewal\_date">Renewal date:</label></th>
  <td>
    <input
 id="id\_renewal\_date"
 name="renewal\_date"
 type="text"
 value="2016-11-08"
 required />
    <br />
    <span class="helptext"
 >Enter date between now and 4 weeks (default 3 weeks).</span
 >
  </td>
</tr>
```

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

```html
<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`:

* `{{ form.renewal_date }}:` O campo todo.
* `{{ form.renewal_date.errors }}`: A lista de erros.
* `{{ form.renewal_date.id_for_label }}`: O id do *label*.
* `{{ form.renewal_date.help_text }}`: O texto de ajuda do campo.

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 (en-US) 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.

```django
{% 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 campo`id`).

### Com o que se parece?

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

![](/pt-BR/docs/Learn/Server-side/Django/Forms/forms_example_renew_default.png)

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

![](/pt-BR/docs/Learn/Server-side/Django/Forms/forms_example_renew_invalid.png)

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

![](/pt-BR/docs/Learn/Server-side/Django/Forms/forms_example_renew_allbooks.png)

ModelForms
----------

Criar uma classe`Form` 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).

```python
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.

```python
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`.

```python
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:

```python
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy

from catalog.models import Author

class AuthorCreate(CreateView):
    model = Author
    fields = '\_\_all\_\_'
    initial = {'date\_of\_death': '05/01/2018'}

class AuthorUpdate(UpdateView):
    model = Author
    fields = ['first\_name', 'last\_name', 'date\_of\_birth', 'date\_of\_death']

class AuthorDelete(DeleteView):
    model = Author
    success_url = reverse_lazy('authors')
```

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.

```django
{% 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.

```django
{% 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:

```python
urlpatterns += [
    path('author/create/', views.AuthorCreate.as_view(), name='author\_create'),
    path('author/<int:pk>/update/', views.AuthorUpdate.as_view(), name='author\_update'),
    path('author/<int:pk>/delete/', views.AuthorDelete.as_view(), name='author\_delete'),
]
```

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](/pt-BR/docs/Learn/Server-side/Django/Forms/forms_example_create_author.png)

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.

![](/pt-BR/docs/Learn/Server-side/Django/Forms/forms_example_delete_author.png)

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:

![](/pt-BR/docs/Learn/Server-side/Django/Forms/forms_example_create_book.png)

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

* Trabalhando com formulários (Django docs)
* Escrevendo seu primeiro *app* Django, parte 4 > Escrevendo um formulário simples (Django docs)
* A API *Forms* (Django docs)
* Form fields (Django docs)
* Formulários e validação de campos (Django docs)
* Manipulação de formulários com *views* baseadas em classe (Django docs)
* Criando formulários com *models* (Django docs)
* Views genéricas de edição (Django docs)
* Anterior  (en-US)
* Menu: Django
* Próxima