Trabalhando com formulários¶
Sobre este documento
Este documento fornece uma introdução ao básico de formulários web e como eles são manipulados no Django. Para mais detalhes olhe nas áreas específica da API de formulários, veja The Forms API, Form fields, e Form and field validation.
A menos que você planeje construir websites e aplicações que não façam outra coisa além de publicar conteúdo, e não aceita entrada de seus visitantes, você irá precisar entender e usar formulários.
O Django fornece uma gama de ferramentas e bibliotecas para auxiliar a construção de formulários para entrada de dados vindos dos seus visitantes, e então os processa e responde àquela entrada.
Formulários HTML¶
Em HTML, um formulário é uma coleção de elementos dentro de <form>...</form>
que permitem que os visitantes façam coisas como escrever um texto, selecionar opções, manipular objetos ou controle e assim por diante, e então enviar esta informação de volta ao servidor.
Some of these form interface elements - text input or checkboxes - are built
into HTML itself. Others are much more complex; an interface that pops up a
date picker or allows you to move a slider or manipulate controls will
typically use JavaScript and CSS as well as HTML form <input>
elements to
achieve these effects.
Assim como seus elementos <input>
, um formulário precisa especificar duas coisas:
- onde: a URL para a qual o dado correspondente à entrada do usuário deve ser enviado.
- como: o método HTTP pelo qual o dado deve ser retornado
Como um exemplo, o formulário de autenticação do admin do Django contém vários elementos do tipo <input>
: um type="text"
para o nome do usuário, um de type="password"
para a senha, e um type="submit"
par ao botão “Log in”. Ele também contém alguns objetos escondidos do tipo texto que o usuário não vê, o qual o Django usa para determinar o que fazer depois.
Ele também diz ao navegador web que os dados do formulário devem ser enviados para a URL especificada no atributo <action>
do <form>
- /admin/
- e isso deve ser enviado usando o mecanismo HTTP especificado pelo atributo method
- post
.
Quando o elemento <input type="submit" value="Log in">
é disparado, os dados são retornados para /admin/
.
GET
e POST
¶
GET
e POST
são os únicos métodos HTTP a se usar enquanto lida com formulários.
O formulário de autenticação do Django é retornado usando o método POST
, no qual o navegador web empacota os dados do formulário, codifica-os para transmissão, envia para o servidor, e então recebe de volta sua resposta.
O GET
, em contraste, empacota os dados enviados em uma string, e usa isso para compor a URL. A URL contém o endereço para onde o dado deve ser enviado, bem como as chaves dos dados e valore. Você pode ver isso em ação se você fizer uma busca na documentação do Django, a qual irá produzir uma URL na forma de https://docs.djangoproject.com/search/?q=forms&release=1
.
GET
e POST
são tipicamente usados para propósitos distintos.
Qualquer requisição que pode ser usada para alterar o estado do sistema - por exemplo, uma requisição que faz alterações no banco de dados - deve usar POST
. O GET
deve ser usado somente para requisições que não afetam o estado do sistema.
GET
would also be unsuitable for a password form, because the password
would appear in the URL, and thus, also in browser history and server logs,
all in plain text. Neither would it be suitable for large quantities of data,
or for binary data, such as an image. A web application that uses GET
requests for admin forms is a security risk: it can be easy for an attacker to
mimic a form’s request to gain access to sensitive parts of the system.
POST
, coupled with other protections like Django’s CSRF protection offers more control over access.
Por outro lado, o GET
é adequado para coisas como um formulário web de busca, porque a URL que represente uma requisição do tipo GET
pode ser facilmente adicionado a lista de favoritos, comparilhada ou reenviada.
Regras do Django em formulários¶
Lidar com formulários é uma coisa complexa. Considere o admin do Django, onde inúmeros itens de dados de diferentes tipos precisam ser preparados para serem visualizados em um formulário, renderizados como HTML, editado usando uma interface conveniente, retornados ao servidor, validados e limpos, e então salvos ou passados adiante para mais processamento.
A funcionalidade de formulários do Django pode simplificar e automatizar uma boa parte deste trabalho, e pode também fazer isso de maneira mais segura que a maioria dos programadores poderiam ser capazes de fazer no código que escrevem.
O Django lida com três partes distintas do trabalho envolvendo formulários:
- Preparando e reestruturando os dados para torná-los prontos para rederização
- criando formulários HTML para os dados
- recebendo e processando formulário enviado e os dados vindos do cliente
É possível escrever código que faz tudo isso manualmente, mas o Django pode tomar conta de tudo isso pra você.
Formulários no Django¶
Descrevemos brevemente os formulários HTML, mas um <form>
HTML é apenas uma parte do maquinário requerido.
In the context of a web application, ‘form’ might refer to that HTML
<form>
, or to the Django Form
that produces it, or to the
structured data returned when it is submitted, or to the end-to-end working
collection of these parts.
A classe Form
do Django¶
No coração deste sistema de componentes está a classe Form
do Django. Mais ou menos como o modelo do Django descreve a estrutura lógica de um objeto, seu comportamento, e a maneira como suas partes são apresentadas para nós, uma classe Form
descreve um formulário e determina como este funciona e aparece.
De maneira similar que a classe de modelo mapeia os campos para o banco de dados, uma classe de formulário mapeia para os elementos <input>
do formulário HTML. (Uma ModelForm
mapeia os campos de uma classe de modelo para elementos <input>
do formulário HTML através da Form
; o admin do Django é baseado nisso.)
Os campos dos formulários são eles próprios classes; eles manipulam dados do formulário e fazem validações quando o formulário é enviado. A DateField
e a FileField
lidam com tipos de dados muito diferentes e tem que fazer coisas diferentes com isso.
Um campo de formulário, para o usuário, é representado como um “widget” HTML - um pedaço do maquinário de interface do usuário. Cada campo tem uma classe de Widget padrão, mas isso pode ser sobrescrito quando requerido.
Instanciando, processando, e renderizando formulários¶
Quando renderizar um objeto no Django, em geral:
- pegamos o objeto na “view” (lido no banco de dados, por exemplo)
- o passamos para o “context” do template
- expandimos para a marcação HTML usando variáveis de template
Mostrar um formulário em um template envolve quase o mesmo trabalho que mostrar qualquer outro tipo de objeto, mas existem algumas diferenças chave.
No caso de uma instância de modelo que não contém nenhum dado, é raramente útil ou talvez nunca seja útil para fazer nada com isso no template. Por outro lado, faz todo o sentido, mostrar um formulário vazio - que é o que fazemos quando queremos que o usuário o preencha.
Então quando lidamos com uma instância de modelo em uma “view”, nós tipicamente a recuperamos do banco de dados. Quando lidamos com um formulário, nós tipicamente o instanciamos na “view”.
When we instantiate a form, we can opt to leave it empty or prepopulate it, for example with:
- dados vindos de uma instância de modelo salva previamente (como no caso dos formulários do admin para edição)
- dados que tenhamos coletado de outras fontes
- dados recebidos de uma prévia submissão de formulário
O último destes casos é o mais interessante, porque é o que torna possível para um usuário não somente ler um site web, mas enviar informação de volta a ele.
Construindo um formulário¶
O trabalho que tem que ser feito¶
Suponha queira criar um formulário simples no seu site web, de modo a obter o nome do usuário. Você precisaria de algo como isso aqui no seu template:
<form action="/your-name/" method="post">
<label for="your_name">Your name: </label>
<input id="your_name" type="text" name="your_name" value="{{ current_name }}">
<input type="submit" value="OK">
</form>
Isso diz ao navegador web para retornar os dados do form para a URL /your-name/
, usando o métodos POST
. Ele irá mostrar um campo, chamado “Your name:”, e um botão com um “OK”. Se o “context” do template contiver uma variável chamada current_name
, esta será usada para pré-preencher o campo your_name
.
Você irá precisar uma “view” que renderiza o template contendo o formulário HTML, e que pode fornecer o campo current_name
apropriadamente.
Quando o formulário é submetido, a requisição do tipo POST
a qual é enviada ao servidor irá conter os dados do formulário.
Agora você irá também precisar de uma “view” que corresponda aquela URL /your-name/
a qual irá encontrar o par chave/valor apropriado na requisição e então processá-lo.
This is a very simple form. In practice, a form might contain dozens or hundreds of fields, many of which might need to be prepopulated, and we might expect the user to work through the edit-submit cycle several times before concluding the operation.
Nós podemos requerer que alguma validação ocorra no navegador web, mesmo antes do formulário ser submetido; nós podemos querer usar campos bem mais complexos, que possibilite ao usuário selecionar uma data de um calendário e assim por diante.
Neste ponto é muito mais fácil ter o Django fazendo a maior parte deste trabalho para nós.
Construindo um formulário no Django¶
A classe Form
¶
Nós já sabemos como queremos que o nosso formulário HTML se pareça. Nosso ponto de início para isso no Django é este:
from django import forms
class NameForm(forms.Form):
your_name = forms.CharField(label='Your name', max_length=100)
Este código define uma classe Form
com um único campo (your_name
). Nós aplicamos uma etiqueta ao campo mais legível a seres humanos, a qual irá aparecer na <label>
quando for renderizado (embora neste caso o label
que especificamos é o mesmo que seria gerado automaticamente se o tivéssemos omitido).
O tamanho máximo do conteúdo do campo é definido pelo max_length
. Isso faz duas coisas. Define a maxlength="100"
no <input>
HTML (então o navegador web impedirá que o usuário entre com um número de caracteres maio que aquele definido). Isso também significa que quando o Django receber o form de volta do navegador, o Django validará o comprimento do dado.
Uma instância da Form
tem um método is_valid()
, o qual executa rotinas de validações para todos os campos. Quando este método é chamado, se todos os campos contiverem dados válidos, ele irá:
- retornar
True
- colocar os dados do formulário no atributo
cleaned_data
do formulário.
O formulário, quando renderizado pela primeira vez, se parecerá com:
<label for="your_name">Your name: </label>
<input id="your_name" type="text" name="your_name" maxlength="100" required>
Repare que não estão incluídas as tags <form>
, ou o botão de submit. Teremos que fornecê-los nós mesmos no template.
A “view”¶
Os dados de formulários enviados para um site Django são processados por uma “view”, geralmente a mesma “view” que publica o formulário. Isso nos permiti reutilizar parte da mesma lógica.
Para lidar com o formulário precisamos instanciá-lo na “view” da URL onde queremos que seja publicado:
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import NameForm
def get_name(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = NameForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
return HttpResponseRedirect('/thanks/')
# if a GET (or any other method) we'll create a blank form
else:
form = NameForm()
return render(request, 'name.html', {'form': form})
Se chegarmos a essa “view” com uma requisição do tipo GET
, ela irá criar uma instância vazia de formulário e colocá-lo no “context” do template para renderizá-lo. Isso é o que esperamos que aconteça quando visitarmos a URL pela primeira vez.
Se o formulário for submetido usando uma requisição do tipo POST
, a “view” irá mais uma vez criar uma instância do formulário e preenchê-la com dados vindos da requisição form = NameForm(request.POST)
. Isso é chamado “carregar dados no formulário” (ele é agora um “bound form”).
Chamamos o método is_valid()``do formulário; se não é ``True
, nós retornamos ao template com o formulário. Desta vez o formulário não está mais vazio (unbound) então o formulário HTML será preenchido com os dados previamente submetidos, onde podem ser editados e corrigidos quando necessário.
Se is_valid()
é True
, seremos capazes de encontrar todos os dados do formulário no atributo cleaned_data
. Podemos usar estes dados para atualizar o banco de dados ou fazer outro processamento antes de enviar um redirecionamento HTTP para o navegador dizendo onde ir a seguir.
O template¶
We don’t need to do much in our name.html
template:
<form action="/your-name/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
Todos os campos dos formulário e seus atributos serão desempacotados dentro da marcação HTML vindos do {{ form }}
através da linguagem de templates do Django.
Formulários e a proteção contra “Falsificação de solicitação entre sites”
O Django traz uma proteção contra falsificação de solicitação entre sites (CSRF em Inglês). Quando se submete um formulário através de um POST
com a proteção CSRF habilitada você deve usar a template tag csrf_token
como no exemplo anterior. Porém, uma vez que a proteção CSRF não está diretamente ligada a formulários em templates, essa tag é omitida dos próximos exemplos neste documento.
Tipos de entradas HTML5 e validação do navegador
If your form includes a URLField
, an
EmailField
or any integer field type, Django will
use the url
, email
and number
HTML5 input types. By default,
browsers may apply their own validation on these fields, which may be
stricter than Django’s validation. If you would like to disable this
behavior, set the novalidate
attribute on the form
tag, or specify
a different widget on the field, like TextInput
.
Nós agora temos um formulário web funcional, descrito pela Form
do Django, processado pela “view”, e renderizado como um <form>
HTML.
Isso é tudo o que você precisa para iniciar, mas o framework de formulários lhe dá muito mais. Uma vez que tenha entendido o básico dos processos descritos acima, você deve estar preparado para entender outras características do sistema de formulários e pronto par aprender um pouco mais sobre maquinário por de trás disso.
Mais sobre as classes de Form
do Django¶
All form classes are created as subclasses of either django.forms.Form
or django.forms.ModelForm
. You can think of ModelForm
as a
subclass of Form
. Form
and ModelForm
actually inherit common
functionality from a (private) BaseForm
class, but this implementation
detail is rarely important.
Modelos e Formulários
In fact if your form is going to be used to directly add or edit a Django
model, a ModelForm can save you a great
deal of time, effort, and code, because it will build a form, along with the
appropriate fields and their attributes, from a Model
class.
Bound and unbound form instances¶
The distinction between Bound and unbound forms is important:
- An unbound form has no data associated with it. When rendered to the user, it will be empty or will contain default values.
- A bound form has submitted data, and hence can be used to tell if that data is valid. If an invalid bound form is rendered, it can include inline error messages telling the user what data to correct.
The form’s is_bound
attribute will tell you whether a form has
data bound to it or not.
More on fields¶
Consider a more useful form than our minimal example above, which we could use to implement “contact me” functionality on a personal website:
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField(widget=forms.Textarea)
sender = forms.EmailField()
cc_myself = forms.BooleanField(required=False)
Our earlier form used a single field, your_name
, a CharField
. In
this case, our form has four fields: subject
, message
, sender
and
cc_myself
. CharField
, EmailField
and
BooleanField
are just three of the available field types; a full list
can be found in Form fields.
Widgets¶
Each form field has a corresponding Widget class,
which in turn corresponds to an HTML form widget such as <input
type="text">
.
In most cases, the field will have a sensible default widget. For example, by
default, a CharField
will have a TextInput
widget, that
produces an <input type="text">
in the HTML. If you needed <textarea>
instead, you’d specify the appropriate widget when defining your form field,
as we have done for the message
field.
Dados do campo¶
Whatever the data submitted with a form, once it has been successfully
validated by calling is_valid()
(and is_valid()
has returned True
),
the validated form data will be in the form.cleaned_data
dictionary. This
data will have been nicely converted into Python types for you.
Nota
You can still access the unvalidated data directly from request.POST
at
this point, but the validated data is better.
In the contact form example above, cc_myself
will be a boolean value.
Likewise, fields such as IntegerField
and FloatField
convert
values to a Python int
and float
respectively.
Here’s how the form data could be processed in the view that handles this form:
from django.core.mail import send_mail
if form.is_valid():
subject = form.cleaned_data['subject']
message = form.cleaned_data['message']
sender = form.cleaned_data['sender']
cc_myself = form.cleaned_data['cc_myself']
recipients = ['info@example.com']
if cc_myself:
recipients.append(sender)
send_mail(subject, message, sender, recipients)
return HttpResponseRedirect('/thanks/')
Dica
For more on sending email from Django, see Enviando e-mail.
Some field types need some extra handling. For example, files that are uploaded
using a form need to be handled differently (they can be retrieved from
request.FILES
, rather than request.POST
). For details of how to handle
file uploads with your form, see Binding uploaded files to a form.
Working with form templates¶
All you need to do to get your form into a template is to place the form
instance into the template context. So if your form is called form
in the
context, {{ form }}
will render its <label>
and <input>
elements
appropriately.
Additional form template furniture
Don’t forget that a form’s output does not include the surrounding
<form>
tags, or the form’s submit
control. You will have to provide
these yourself.
Reusable form templates¶
The HTML output when rendering a form is itself generated via a template. You
can control this by creating an appropriate template file and setting a custom
FORM_RENDERER
to use that
form_template_name
site-wide. You
can also customize per-form by overriding the form’s
template_name
attribute to render the form using the
custom template, or by passing the template name directly to
Form.render()
.
The example below will result in {{ form }}
being rendered as the output of
the form_snippet.html
template.
In your templates:
# In your template:
{{ form }}
# In form_snippet.html:
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
Then you can configure the FORM_RENDERER
setting:
from django.forms.renderers import TemplatesSetting
class CustomFormRenderer(TemplatesSetting):
form_template_name = "form_snippet.html"
FORM_RENDERER = "project.settings.CustomFormRenderer"
… or for a single form:
class MyForm(forms.Form):
template_name = "form_snippet.html"
...
… or for a single render of a form instance, passing in the template name to
the Form.render()
. Here’s an example of this being used in a view:
def index(request):
form = MyForm()
rendered_form = form.render("form_snippet.html")
context = {'form': rendered_form}
return render(request, 'index.html', context)
See Outputting forms as HTML for more details.
Template rendering of forms was added.
The ability to set the default form_template_name
on the form renderer
was added.
Form rendering options¶
There are other output options though for the <label>
/<input>
pairs:
{{ form.as_div }}
will render them wrapped in<div>
tags.{{ form.as_table }}
will render them as table cells wrapped in<tr>
tags.{{ form.as_p }}
will render them wrapped in<p>
tags.{{ form.as_ul }}
will render them wrapped in<li>
tags.
Note that you’ll have to provide the surrounding <table>
or <ul>
elements yourself.
Here’s the output of {{ form.as_p }}
for our ContactForm
instance:
<p><label for="id_subject">Subject:</label>
<input id="id_subject" type="text" name="subject" maxlength="100" required></p>
<p><label for="id_message">Message:</label>
<textarea name="message" id="id_message" required></textarea></p>
<p><label for="id_sender">Sender:</label>
<input type="email" name="sender" id="id_sender" required></p>
<p><label for="id_cc_myself">Cc myself:</label>
<input type="checkbox" name="cc_myself" id="id_cc_myself"></p>
Note that each form field has an ID attribute set to id_<field-name>
, which
is referenced by the accompanying label tag. This is important in ensuring that
forms are accessible to assistive technology such as screen reader software.
You can also customize the way in which labels and ids are generated.
See Outputting forms as HTML for more on this.
Rendering fields manually¶
We don’t have to let Django unpack the form’s fields; we can do it manually if
we like (allowing us to reorder the fields, for example). Each field is
available as an attribute of the form using {{ form.name_of_field }}
, and
in a Django template, will be rendered appropriately. For example:
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.subject.errors }}
<label for="{{ form.subject.id_for_label }}">Email subject:</label>
{{ form.subject }}
</div>
<div class="fieldWrapper">
{{ form.message.errors }}
<label for="{{ form.message.id_for_label }}">Your message:</label>
{{ form.message }}
</div>
<div class="fieldWrapper">
{{ form.sender.errors }}
<label for="{{ form.sender.id_for_label }}">Your email address:</label>
{{ form.sender }}
</div>
<div class="fieldWrapper">
{{ form.cc_myself.errors }}
<label for="{{ form.cc_myself.id_for_label }}">CC yourself?</label>
{{ form.cc_myself }}
</div>
Complete <label>
elements can also be generated using the
label_tag()
. For example:
<div class="fieldWrapper">
{{ form.subject.errors }}
{{ form.subject.label_tag }}
{{ form.subject }}
</div>
Rendering form error messages¶
The price of this flexibility is a bit more work. Until now we haven’t had to
worry about how to display form errors, because that’s taken care of for us. In
this example we have had to make sure we take care of any errors for each field
and any errors for the form as a whole. Note {{ form.non_field_errors }}
at
the top of the form and the template lookup for errors on each field.
Using {{ form.name_of_field.errors }}
displays a list of form errors,
rendered as an unordered list. This might look like:
<ul class="errorlist">
<li>Sender is required.</li>
</ul>
The list has a CSS class of errorlist
to allow you to style its appearance.
If you wish to further customize the display of errors you can do so by looping
over them:
{% if form.subject.errors %}
<ol>
{% for error in form.subject.errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
</ol>
{% endif %}
Non-field errors (and/or hidden field errors that are rendered at the top of
the form when using helpers like form.as_p()
) will be rendered with an
additional class of nonfield
to help distinguish them from field-specific
errors. For example, {{ form.non_field_errors }}
would look like:
<ul class="errorlist nonfield">
<li>Generic validation error</li>
</ul>
See The Forms API for more on errors, styling, and working with form attributes in templates.
Looping over the form’s fields¶
If you’re using the same HTML for each of your form fields, you can reduce
duplicate code by looping through each field in turn using a {% for %}
loop:
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
Useful attributes on {{ field }}
include:
{{ field.errors }}
- Outputs a
<ul class="errorlist">
containing any validation errors corresponding to this field. You can customize the presentation of the errors with a{% for error in field.errors %}
loop. In this case, each object in the loop is a string containing the error message. {{ field.field }}
- The
Field
instance from the form class that thisBoundField
wraps. You can use it to accessField
attributes, e.g.{{ char_field.field.max_length }}
. {{ field.help_text }}
- Any help text that has been associated with the field.
{{ field.html_name }}
- The name of the field that will be used in the input element’s name field. This takes the form prefix into account, if it has been set.
{{ field.id_for_label }}
- The ID that will be used for this field (
id_email
in the example above). If you are constructing the label manually, you may want to use this in lieu oflabel_tag
. It’s also useful, for example, if you have some inline JavaScript and want to avoid hardcoding the field’s ID. {{ field.is_hidden }}
- This attribute is
True
if the form field is a hidden field andFalse
otherwise. It’s not particularly useful as a template variable, but could be useful in conditional tests such as:
{% if field.is_hidden %}
{# Do something special #}
{% endif %}
{{ field.label }}
- The label of the field, e.g.
Email address
. {{ field.label_tag }}
The field’s label wrapped in the appropriate HTML
<label>
tag. This includes the form’slabel_suffix
. For example, the defaultlabel_suffix
is a colon:<label for="id_email">Email address:</label>
{{ field.legend_tag }}
New in Django 4.1.Similar to
field.label_tag
but uses a<legend>
tag in place of<label>
, for widgets with multiple inputs wrapped in a<fieldset>
.
{{ field.use_fieldset }}
New in Django 4.1.This attribute is
True
if the form field’s widget contains multiple inputs that should be semantically grouped in a<fieldset>
with a<legend>
to improve accessibility. An example use in a template:
{% if field.use_fieldset %}
<fieldset>
{% if field.label %}{{ field.legend_tag }}{% endif %}
{% else %}
{% if field.label %}{{ field.label_tag }}{% endif %}
{% endif %}
{{ field }}
{% if field.use_fieldset %}</fieldset>{% endif %}
{{ field.value }}
- The value of the field. e.g
someone@example.com
.
Ver também
For a complete list of attributes and methods, see
BoundField
.
Further topics¶
This covers the basics, but forms can do a whole lot more:
- Formsets
- Using initial data with a formset
- Limiting the maximum number of forms
- Limiting the maximum number of instantiated forms
- Formset validation
- Validating the number of forms in a formset
- Dealing with ordering and deletion of forms
- Adding additional fields to a formset
- Passing custom parameters to formset forms
- Customizing a formset’s prefix
- Using a formset in views and templates
- Creating forms from models
- Form Assets (the
Media
class)
Ver também
- The Forms Reference
- Covers the full API reference, including form fields, form widgets, and form and field validation.