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:

  1. pegamos o objeto na “view” (lido no banco de dados, por exemplo)
  2. o passamos para o “context” do template
  3. 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:

forms.py
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:

views.py
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:

forms.py
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:

views.py
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:

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

Reusable field group templates

New in Django 5.0.

Each field is available as an attribute of the form, using {{ form.name_of_field }} in a template. A field has a as_field_group() method which renders the related elements of the field as a group, its label, widget, errors, and help text.

This allows generic templates to be written that arrange fields elements in the required layout. For example:

{{ form.non_field_errors }}
<div class="fieldWrapper">
  {{ form.subject.as_field_group }}
</div>
<div class="fieldWrapper">
  {{ form.message.as_field_group }}
</div>
<div class="fieldWrapper">
  {{ form.sender.as_field_group }}
</div>
<div class="fieldWrapper">
  {{ form.cc_myself.as_field_group }}
</div>

By default Django uses the "django/forms/field.html" template which is designed for use with the default "django/forms/div.html" form style.

The default template can be customized by setting field_template_name in your project-level FORM_RENDERER:

from django.forms.renderers import TemplatesSetting


class CustomFormRenderer(TemplatesSetting):
    field_template_name = "field_snippet.html"

… or on a single field:

class MyForm(forms.Form):
    subject = forms.CharField(template_name="my_custom_template.html")
    ...

… or on a per-request basis by calling BoundField.render() and supplying a template name:

def index(request):
    form = ContactForm()
    subject = form["subject"]
    context = {"subject": subject.render("my_custom_template.html")}
    return render(request, "index.html", context)

Rendering fields manually

More fine grained control over field rendering is also possible. Likely this will be in a custom field template, to allow the template to be written once and reused for each field. However, it can also be directly accessed from the field attribute on the form. 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" id="{{ field.auto_id }}_helptext">
            {{ 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 this BoundField wraps. You can use it to access Field 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 of label_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 and False 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’s label_suffix. For example, the default label_suffix is a colon:

<label for="id_email">Email address:</label>
{{ field.legend_tag }}
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 }}
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.

Looping over hidden and visible fields

If you’re manually laying out a form in a template, as opposed to relying on Django’s default form layout, you might want to treat <input type="hidden"> fields differently from non-hidden fields. For example, because hidden fields don’t display anything, putting error messages “next to” the field could cause confusion for your users – so errors for those fields should be handled differently.

Django provides two methods on a form that allow you to loop over the hidden and visible fields independently: hidden_fields() and visible_fields(). Here’s a modification of an earlier example that uses these two methods:

{# Include the hidden fields #}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{# Include the visible fields #}
{% for field in form.visible_fields %}
    <div class="fieldWrapper">
        {{ field.errors }}
        {{ field.label_tag }} {{ field }}
    </div>
{% endfor %}

This example does not handle any errors in the hidden fields. Usually, an error in a hidden field is a sign of form tampering, since normal form interaction won’t alter them. However, you could easily insert some error displays for those form errors, as well.

Back to Top