Trabalhando com formulários

Sobre este documento

Este documento fornece uma introdução as funcionalidades de manipulação de formulários do Django. Para uma visão mais detalhada da API de forumulários, veja A API de formulários. Para documentação de tipos de campos disponíveis, veja Form fields.

django.forms é a biblioteca de manipulação de formulários.

Embora seja possível processar submissões de formulário somente usando a classe HttpRequest do Django, usando a biblioteca de formulários fica melhor para a realização de uma série de tarefas comunus relacionadas a formulários. Usando-o, você pode:

  1. Mostrar um formulário HTML com widgets gerados automaticamente.
  2. Verificar os dados submetidos conforme um conjuto de regras de validação.
  3. Re-exibir um formulário no caso de haver erros de validação.
  4. Converter dados de formulários submetidos a tipos relevantes do Python.

Visão geral

A biblioteca trabalha com os seguintes conceitos:

Widget
Uma classe que corresponde a um widget de formulário HTML, e.g. <input type="text"> ou <textarea>. Este manipula a renderização do widget como HTML.
Field
Uma classe que é responsável por fazer validação, e.g. um EmailField que assegura-se de que seu dado é um endereço de e-mail válido.
Form
Uma coleção de campos que sabem como validar e mostrar a si mesmo como HTML.
Form Media
Os recursos CSS e Javascript que são requeridos para renderizar um formulário.

A biblioteca é dissociada de outros componentes do Django, como a camada de banco de dados., views e templates. Ele invoca somente do Django settings, algumas funções helpers django.utils e hooks de internacionalização do Django (mas você não é obrigado a usar internacionalização para usar esta biblioteca).

Objetos Form

Um objeto Form encapsula uma sequencia de campos de formulário e uma coleção de regras de validação que devem ser preenchidas para que o furmulário seja aceito. Classes Form são criadas como subclasses de django.forms.Form e fazem uso de um estilo declarativo, que se você irá familiarizar-se, pois ele é usado nos models de banco de dados do Django.

Por exemplo, considere um formulário usado para implementar a funcionalidade “contact me” num Web site pessoal:

from django import forms

class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    message = forms.CharField()
    sender = forms.EmailField()
    cc_myself = forms.BooleanField(required=False)

Um formulário é composto de objetos Field. Neste caso, nosso formulário tem quatro campos: subject, message, sender e cc_myself. CharField, EmailField e BooleandField são somente três dos tipos tipos de campos disponíveis; uma lista completa pode ser encontrada em Form fields.

Se seu formulário será usado para adicionar ou editar um model do Django diretamente, você pode usar um ModelForm para evitar duplicações de suas descrições de model.

Usando um formulário num view

O padrão para processar um formulário num view parece com isso:

def contact(request):
    if request.method == 'POST': # If the form has been submitted...
        form = ContactForm(request.POST) # Um form com os dados de POST
        if form.is_valid(): # All validation rules pass
            # Processa os dados no form.cleaned_data
            # ...
            return HttpResponseRedirect('/thanks/') # Redireciona depois do POST
    else:
        form = ContactForm() # Um formulário vazio

    return render_to_response('contact.html', {
        'form': form,
    })

Existem três caminhos de código aqui:

  1. Se o form não foi submetido, uma instância unbound do ContactForm é criada e passada para o template.
  2. Se o form foi submetido, uma instância bound do form é criada usando o request.POST. Se os dados submetidos forem válidos, ele é processado e o usuário é redirecionado para uma página de “agradecimento”.
  3. Se o formulário foi submitetido mas é inválido, uma instância bound do form é passada ao template.
O atributo cleanded_data foi chamado de clean_data em versões anteriores.

A distinção entre formulários bound e unbound é importante. Um formulário unbound não tem qualquer dado associado a ele; quando o formlário for renderizado para o usuário, ele estará vazio ou conterá valores padrão. Um fomrulário bound possui dados submetidos, e por isso pode ser usado para dizer se os dados são válidos. Se um formulário bound e inválido for renderizado ele pode incluír mensagens de erros, dizendo ao usuário onde ele errou.

Veja Bound e unbound formulários para mais informações sobre diferenças entre formulários bound e unbound.

Manipulando upload de arquivos com um form

Para ver como manipular upload de arquivos com seu formulário veja Vinculando arquivos enviados a um formulário para mais informações.

Processando os dados de um formulário

Uma vez que is_valid() retorne True, você pode processar a submissão do formulário sabendo que ela está em conformidade com as regras de validação definidas por seu formulário. Embora você possa acessar request.POST diretamente deste ponto, é melhor acessar form.cleaned_data. Estes dados não serão somente válidos, mas estarão convertidos em tipos relevantes do Python. No exemplo acima, cc_myself será um valor booleano. Da mesma forma, campos como IntegerField e FloatField serão convertidos para int e float do Python respectivamente.

Extendendo o exemplo acima, aqui temos como os dados do formulário podem ser processados:

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)

    from django.core.mail import send_mail
    send_mail(subject, message, sender, recipients)
    return HttpResponseRedirect('/thanks/') # Redirect after POST

Para saber mais sobre como enviar e-mail do Django, veja Sending e-mail.

Mostrando um formulário usando um template

O Forms é projetados para trabalhar com a linguagem de templates do Django. No exemplo acima, nós passamos nossa instância do ContactForm para o template usando a variável de contexto form. Aqui temos um exemplo simples de template:

<form action=”/contact/” method=”POST”> {{ form.as_p }} <input type=”submit” value=”Submit” /> </form>

O form somente mostra seus próprios campos; ele não fornece tags <form> e o botão submit.

O forms.as_p mostrará o formulário com cada campo e sua respectiva label envolvidos por um parágrafo. Aqui temos uma saída para nosso template de exemplo:

<form action="/contact/" method="POST">
<p><label for="id_subject">Subject:</label>
    <input id="id_subject" type="text" name="subject" maxlength="100" /></p>
<p><label for="id_message">Message:</label>
    <input type="text" name="message" id="id_message" /></p>
<p><label for="id_sender">Sender:</label>
    <input type="text" name="sender" id="id_sender" /></p>
<p><label for="id_cc_myself">Cc myself:</label>
    <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>
<input type="submit" value="Submit" />
</form>

Note que cada campo de formulário tem um atributo ID setado para id_<field-name>, que é referenciado por uma tag label. Isto é importante para assegurar que os formulários sejam acessíveis para tecnologias assistivas como leitores de tela. Você também pode customizar a forma em que as labels e ids são gerados.

Você pode também usar forms.as_table para gerar saídas como linhas de tabela. (você precisará fornecer suas próprias tags <table>) e forms.as_ul para mostrar em items de lista.

Personalizando o templates de formulário

Se o HTML padrão gerado não é de seu gosto, você pode personalizar completamente a forma como o formulário é apresentado usando a linguagem de template do Django. Extendendo o exemplo acima:

<form action="/contact/" method="POST">
    <div class="fieldWrapper">
        {{ form.subject.errors }}
        <label for="id_subject">E-mail subject:</label>
        {{ form.subject }}
    </div>
    <div class="fieldWrapper">
        {{ form.message.errors }}
        <label for="id_message">Your message:</label>
        {{ form.message }}
    </div>
    <div class="fieldWrapper">
        {{ form.sender.errors }}
        <label for="id_sender">Your email address:</label>
        {{ form.sender }}
    </div>
    <div class="fieldWrapper">
        {{ form.cc_myself.errors }}
        <label for="id_cc_myself">CC yourself?</label>
        {{ form.cc_myself }}
    </div>
    <p><input type="submit" value="Send message" /></p>
</form>

Cada campo de formulário nomeado pode ser mostrado ao template usando {{ form.nome_do_campo }}, que produzirá o HTML necessário para mostrar o widget de formulário. Usando {{ form.nome_do_campo.errors }} mostra uma lista de erros de formulário, renderizado como uma lista não ordenada. Ele pode parecer com isso:

<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:: A lista tem uma classe CSS errorlist para permitir que você mude sua aparência. Se você desejar personalizar a exibição dos erros, você pode fazê-lo iterando sobre eles:

{% if form.subject.errors %}
    <ol>
    {% for error in form.subject.errors %}
        <li><strong>{{ error|escape }}</strong></li>
    {% endfor %}
    </ol>
{% endif %}

Iterando sobre os campos de formulário

Se você estiver usando o mesmo HTML para cada um dos seus campos de formulário, você pode reduzir a duplicidade de código iterando sobre os campos usando um loop {% for %}:

<form action="/contact/" method="POST">
    {% for field in form %}
        <div class="fieldWrapper">
            {{ field.errors }}
            {{ field.label_tag }}: {{ field }}
        </div>
    {% endfor %}
    <p><input type="submit" value="Send message" /></p>
</form>

Dentro deste loop, {{ field }} é uma instância de :class`BoundField`. O BoundField também tem os seguintes atributos, que podem ser úteis nos seus templates:

{{ field.label }}
A label do campo, e.g. E-mail address
{{ field.label_tag }}
A label do campo envolvida por uma tag HTML <label>, e.g. <label for="id_email">E-mail address</label>
{{ field.html_name }}
O nome do campo que será usado no nome do elemento campo input. Este ercebe o prefixo do formulário, se ele tiver sido definido
{{ field.help_text }}
Qualquer texto de ajuda que deva ser associado com o campo.
{{ field.errors }}
Gera um <ul class="errorlist"> contendo qualquer erro de validação correspondendo a este campo. Você pode personalizar a apresentação dos erros com um loop {% for error in field.errors %}. Neste caso, cada objeto no loop é uma string simples contendo a mensagem de erro.

Templates de formulário reusáveis

Se seu site usa a mesma lógica de renderização para formulários em vários lugares, você pode reduzir a duplicidade utilizando um loop de formulário num template autônomo e usando a tag include para reusá-lo noutros templates:

<form action="/contact/" method="POST">
    {% include "form_snippet.html" %}
    <p><input type="submit" value="Send message" /></p>
</form>

# No form_snippet.html:

{% for field in form %}
    <div class="fieldWrapper">
        {{ field.errors }}
        {{ field.label_tag }}: {{ field }}
    </div>
{% endfor %}

Se o objeto form passado a um template tem um nome diferente dentro do contexto, você pode criar um alias usando a tag with:

<form action="/comments/add/" method="POST">
    {% with comment_form as form %}
        {% include "form_snippet.html" %}
    {% endwith %}
    <p><input type="submit" value="Submit comment" /></p>
</form>

Se você se pegar fazendo isso frequentemente, você pode considerar criar uma inclusion tag personalizada.

Tópicos adicionais

Isto cobre o básido, mas os forms podem fazer muito mais: