A API de formulários

Sobre este documento

Este documento cobre os detalhes arenosos da API de formulário do Django. Você deve ler a introdução ao trabalho com formulários primeiro.

Bound e unbound formulários

Uma instância de Form, pode ser ambos, bound para um conjunto de dados, ou unbound.

  • Se ela for bound para um conjunto de dados, ela será capaz de validar estes dados renderizando o formulário como um HTML com os dados exibidos dentro do HTML.
  • Se ela for unbound ela não fará validação (pois não há dados para validar!), mas ela ainda poderá renderizar o formulário em branco em HTML.

Para criar uma instância Form, simplesmente instancie a classe:

>>> f = ContactForm()

Para embutir dados no formulário, passe um dicionário como o primeiro parâmetro para o construtor da sua classe Form:

>>> data = {'subject': 'hello',
...         'message': 'Hi there',
...         'sender': 'foo@example.com',
...         'cc_myself': True}
>>> f = ContactForm(data)

No dicionário, as chaves são os nomes dos campos, que correspondem aos atributos na sua classe Form. Os valores são os ados que você está tentando validar. Estes normalmente serão strings, mas não há exigências para sejam strings. o tipo de dado que você passa depende do Field, como veremos em breve.

Form.is_bound

Se você precisa distinguir entre instâncias formulários bound e unbound em tempo de execução, verifique o valor do atributo is_bound:

>>> f = ContactForm()
>>> f.is_bound
False
>>> f = ContactForm({'subject': 'hello'})
>>> f.is_bound
True

Note que passando um dicionário vazio você cria um formulário bound sem dados:

>>> f = ContactForm({})
>>> f.is_bound
True

Se você tem uma instância Form e deseja mudar os dados de alguma forma, ou se você quer vincular uma instância unbound para algum dado, crie outra instância Form. Não há formas de mudar os dados numa instância Form. Uma vez que uma instância de Form foi criada, você deve considerar seus dados imutável, tendo ela dados ou não.

Usando formulários para validar dados

Form.is_valid()

A primeira tarefa de um objeto Form é validar dados. Com uma instância de preenchida de um formulário, chame o método is_valid() para executar a validação e retornar um booleano designando se ele foi validado:

>>> data = {'subject': 'hello',
...         'message': 'Hi there',
...         'sender': 'foo@example.com',
...         'cc_myself': True}
>>> f = ContactForm(data)
>>> f.is_valid()
True

Vamos tentar com algum dado inválido. Neste caso, subject esta em branco (um erro, pois todos os campos são obrigatórios por padrão) e sender é um endereço de email inválido:

>>> data = {'subject': '',
...         'message': 'Hi there',
...         'sender': 'invalid e-mail address',
...         'cc_myself': True}
>>> f = ContactForm(data)
>>> f.is_valid()
False
Form.errors

Acesse o atributo erros para pegar um dicionários com as mensagens de erro:

>>> f.errors
{'sender': [u'Enter a valid e-mail address.'], 'subject': [u'This field is required.']}

Neste dicionário, as chaves são nomes de campos, e os valores são listas de strings Unicode representando as mensagens de erro. As mensagens de erro são armazenadas na lista porque um campo pode ter mais de uma mensagem de erro.

Você pode acessar errors sem ter de chamar is_valid() primeiro. Os dados do formulário estarão validados na primeira vez que você chamar Form.is_valid() ou acessar o errors.

As rotinas de validação serão chamadas somente uma vez, indiferente de quantas vezes você acessar errors ou chamar is_valid(). Isso significa que se a validação tem efeitos de sentido único, estes efeitos somente serão disparados uma vez.

Comportamento de formulário vazios

É sem sentido validar um formulário sem dados, mas, para registro, aqui está o que acontece com formulários vazios:

>>> f = ContactForm()
>>> f.is_valid()
False
>>> f.errors
{}

Valores iniciais dinâmicos

Form.initial

Use initial para declarar valores iniciais de campos de formulários em tempo de execução. Por exemplo, você pode querer preencher um campo username com o nome de usuário da sessão atual.

Para realizar isso, use o argumento initial de um Form. Este argumento, se fornecido, deve ser um dicionário mapeando os nomes dos campos com valores iniciais. Somente inclua os campos que você estiver especificando um valor inicial; não é necessário incluír todos os campos do seu formulário. Por exemplo:

>>> f = ContactForm(initial={'subject': 'Hi there!'})

Estes valores são somente mostrados para formulários vazios, e eles não são usados como valores de recuo se um valor particular não é fornecido.

Note que se um Field define initial e você inclui initial quando instância o Form, então mais tarde initial terá prioridade. Neste exemplo, initial é fornecido a nível de campo e a nível de instância de formulário, e mais tarde terá prioridade:

>>> class CommentForm(forms.Form):
...     name = forms.CharField(initial='class')
...     url = forms.URLField()
...     comment = forms.CharField()
>>> f = CommentForm(initial={'name': 'instance'}, auto_id=False)
>>> print f
<tr><th>Name:</th><td><input type="text" name="name" value="instance" /></td></tr>
<tr><th>Url:</th><td><input type="text" name="url" /></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>

Acessando dados "limpos"

Cada Field numa classe Form é responsável não somente por validar dados, mas também por limpá-los -- normalizando-os para um formato consistente. Essa é funcionalidade legal, pois ela permite dados de um campo particular ser inserido de diversas formas, sempre resultando numa saída consistente.

Por exemplo, DateField normaliza a entrada num objeto datetime.date do Python. Indiferentemente de você passar a ele uma string no formato '1994-07-15', um objeto datetime.date ou um número de outros formatos, DateField sempre será normalizado para um objeto datetime.date assim que ele for validado.

Uma vez que você tenha criado uma instância do Form com um conjunto de dados e validado-os, você pode acessar os dados limpos via atributo cleaned_data do objeto Form:

>>> data = {'subject': 'hello',
...         'message': 'Hi there',
...         'sender': 'foo@example.com',
...         'cc_myself': True}
>>> f = ContactForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data
{'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'}
Alterado no Django 1.0: The cleaned_data attribute was called clean_data in earlier releases.

Note que qualquer campo baseado em texto -- como um CharField ou EmailField -- sempre limpa a entrada numa string Unicode. Nós iremos cobrir as implicações da codificação mais tarde nesse documento.

Se seus dados não validam, sua instância do Form não terá um atributo cleaned_data:

>>> data = {'subject': '',
...         'message': 'Hi there',
...         'sender': 'invalid e-mail address',
...         'cc_myself': True}
>>> f = ContactForm(data)
>>> f.is_valid()
False
>>> f.cleaned_data
Traceback (most recent call last):
...
AttributeError: 'ContactForm' object has no attribute 'cleaned_data'

cleaned_data sempre conterá somente uma chave para campos definidos no Form, mesmo se você passar um dados extra quando você definir o Form. Neste exemplo, nós passamos um grupo de campos extras ao construtor do ContactForm, mas o cleaned_data contém somente os campos do formulário:

>>> data = {'subject': 'hello',
...         'message': 'Hi there',
...         'sender': 'foo@example.com',
...         'cc_myself': True,
...         'extra_field_1': 'foo',
...         'extra_field_2': 'bar',
...         'extra_field_3': 'baz'}
>>> f = ContactForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data # Doesn't contain extra_field_1, etc.
{'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'}

cleanded_data incluirá uma chave e um valor para todos os campos definidos no Form, mesmo se os dados não incluem um valor por campo, pois isso não é obrigatório. Neste exemplo, o dicionário de dados não inclui um valor para o campo nick_name, mas cleaned_data o inclui, com um valor vazio:

>>> class OptionalPersonForm(Form):
...     first_name = CharField()
...     last_name = CharField()
...     nick_name = CharField(required=False)
>>> data = {'first_name': u'John', 'last_name': u'Lennon'}
>>> f = OptionalPersonForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data
{'nick_name': u'', 'first_name': u'John', 'last_name': u'Lennon'}

Neste exemplo acima, o valor cleaned_data para nick_name é setado para uma estring vazia, porque o nick_name é CharField, e CharFields tratam valores vazios como uma string vazia. Cada tipo de campo sabe como seus valores "brancos" são -- e.g., para DateField, ele é None ao invés de uma string vazia. Para detalhes completos sobre cada comportamento de campo neste caso, veja a nota "Valor vazio" para cada campos na seção "classes Field embutidas" abaixo.

Você pode escrever código para executar validação para campos de formulário específicos (baseados nos seus nomes) ou para um formulário como um todo (considerando combinações de vários campos). Mais informações sobre isso está em Validação de campos e formulários.

Mostrando os formulários como HTML

A segunda tarefa de um objeto Form é renderizar a si mesmo como HTML. Para fazê-lo, simplesmente chame print:

>>> f = ContactForm()
>>> print f
<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr>
<tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" /></td></tr>
<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>

Se o formulário está preenchido com dados, a saída HTML incluirá esses dados apropriadamente. Por exemplo, se um campo é representado por um <input type="text">, o dados estará no atributo value. Se um campo é representado por um <input type="checkbox">, quando este HTML incluir checked="checked" se apropriado:

>>> data = {'subject': 'hello',
...         'message': 'Hi there',
...         'sender': 'foo@example.com',
...         'cc_myself': True}
>>> f = ContactForm(data)
>>> print f
<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" value="hello" /></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" value="Hi there" /></td></tr>
<tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" value="foo@example.com" /></td></tr>
<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" checked="checked" /></td></tr>

Esta saída padrão é um tabela HTML com duas colunas, com um <tr> para cada campo: Note o seguinte:

  • Para flexibilidade, a saída não incluí as tags <table> e </table>, nem incluí as tags <form> </form> ou um <input type="submit">. É seu trabalho fazer isso.
  • Cada tipo de campo tem uma representação padrão do HTML. CharField e EmailField são representado por um <input type="text">. O BooleanField é representado por um <input type="checkbox">. Note estes são simplesmente padrões sensiveis; você pode especificar qual HTML usar para um dado campo usando widgets, que nós explanaremos logo.
  • O nome de cada tag HTML é dado diretamente por seu atributo name na classe ContactForm.
  • O texto da label de cada campo -- e.g. 'Subject:', 'Message:' e 'Cc myself:' é gerado a partir do nome do campo convertendo todos os undersocres em espaços e capitalizando a primeira letra. Novamente, perceba que estes são meramente padrões sensíveis; você pode também especificar labels manualmente.
  • Cada texto de label é envolvido por uma tag HTML <label>, que aponta para o campo de formulário apropriado, via id do campo. Seu id, por sua vez, é gerado prefixado por um 'id_' no nome do campo. Os atributo id e tag <label> são incluídos na saída por padrão, seguindo as melhores práticas, mas você pode mudar este comportamento.

Embora a saída <table> seja o estilo de saída padrão quando você imprime um formulário, outros estilos de saídas estão disponíveis. Cada estilo está disponível como um método no objeto form, e cada método de renderização retorna um objeto Unicode.

as_p()

Form.as_p() renderiza o formulário como uma série de tags <p>, com cada <p> contendo um campo:

>>> f = ContactForm()
>>> f.as_p()
u'<p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></p>\n<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></p>\n<p><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></p>\n<p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>'
>>> print f.as_p()
<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>

as_ul()

Form.as_ul() renderiza o formulário como uma séria de tags <li>, com cada <li> contendo um campo. Ele não inclui as tags <ul> ou </ul>, então você pode especificar quaisquer atributos sobre o <ul>:

>>> f = ContactForm()
>>> f.as_ul()
u'<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></li>\n<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></li>\n<li><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></li>\n<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></li>'
>>> print f.as_ul()
<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></li>
<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></li>
<li><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></li>
<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></li>

as_table()

Finalmente, Form.as_table() mostar o formulário como uma <table> HTML. Isso é exatamente o mesmo que o print. De fato, quando você executa um print um objeto form, ele chama seu método as_table() por trás das cenas:

>>> f = ContactForm()
>>> f.as_table()
u'<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr>\n<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr>\n<tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" /></td></tr>\n<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>'
>>> print f.as_table()
<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr>
<tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" /></td></tr>
<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>

Configurando tags HTML <label>

Uma tag HTML <label> designa que um texto está associado a um elemento do formulário. Este pequeno reforço faz o formulário mais usável e acessível para dispositivos de assistência. É sempre uma boa idéia usar as tags <label>.

Por padrão, os métodos de renderização incluem atributos id aos elementos do formulário e envolvem as labels com tags <label>. O atributo id terá seu valor gerado prefixando os nomes dos campos com um 'id_'. Este comportamento é configurável, contudo, se você desejar mudar a convenção do id ou remover os atributos id do HTML e as tags <label> inteiramente.

use o argumento auto_id no construtor do Form para controlar o comportamento das labels e id. Este argumento deve ser True, False ou uma string.

Se o auto_id for False, então o formulário mostrado não incluirá tags <label> nem atributos id:

>>> f = ContactForm(auto_id=False)
>>> print f.as_table()
<tr><th>Subject:</th><td><input type="text" name="subject" maxlength="100" /></td></tr>
<tr><th>Message:</th><td><input type="text" name="message" /></td></tr>
<tr><th>Sender:</th><td><input type="text" name="sender" /></td></tr>
<tr><th>Cc myself:</th><td><input type="checkbox" name="cc_myself" /></td></tr>
>>> print f.as_ul()
<li>Subject: <input type="text" name="subject" maxlength="100" /></li>
<li>Message: <input type="text" name="message" /></li>
<li>Sender: <input type="text" name="sender" /></li>
<li>Cc myself: <input type="checkbox" name="cc_myself" /></li>
>>> print f.as_p()
<p>Subject: <input type="text" name="subject" maxlength="100" /></p>
<p>Message: <input type="text" name="message" /></p>
<p>Sender: <input type="text" name="sender" /></p>
<p>Cc myself: <input type="checkbox" name="cc_myself" /></p>

Se o auto_id for True, então o formulário mostrado incluirá tags <label> e simplesmente usará o nome dos campos como seu id para cada campo do formulário:

>>> f = ContactForm(auto_id=True)
>>> print f.as_table()
<tr><th><label for="subject">Subject:</label></th><td><input id="subject" type="text" name="subject" maxlength="100" /></td></tr>
<tr><th><label for="message">Message:</label></th><td><input type="text" name="message" id="message" /></td></tr>
<tr><th><label for="sender">Sender:</label></th><td><input type="text" name="sender" id="sender" /></td></tr>
<tr><th><label for="cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="cc_myself" /></td></tr>
>>> print f.as_ul()
<li><label for="subject">Subject:</label> <input id="subject" type="text" name="subject" maxlength="100" /></li>
<li><label for="message">Message:</label> <input type="text" name="message" id="message" /></li>
<li><label for="sender">Sender:</label> <input type="text" name="sender" id="sender" /></li>
<li><label for="cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="cc_myself" /></li>
>>> print f.as_p()
<p><label for="subject">Subject:</label> <input id="subject" type="text" name="subject" maxlength="100" /></p>
<p><label for="message">Message:</label> <input type="text" name="message" id="message" /></p>
<p><label for="sender">Sender:</label> <input type="text" name="sender" id="sender" /></p>
<p><label for="cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="cc_myself" /></p>

Se auto_id for uma string contendo o caracter de formatação '%s', então o formulário mostrado incluirá as tags <label>, e será gerado um atributo id baseado na string passada. Por exemplo, para uma string de formatação 'field_%s', um nome de campo subject terá o valor do id igual a 'field_subject'. Continuando nosso exemplo:

>>> f = ContactForm(auto_id='id_for_%s')
>>> print f.as_table()
<tr><th><label for="id_for_subject">Subject:</label></th><td><input id="id_for_subject" type="text" name="subject" maxlength="100" /></td></tr>
<tr><th><label for="id_for_message">Message:</label></th><td><input type="text" name="message" id="id_for_message" /></td></tr>
<tr><th><label for="id_for_sender">Sender:</label></th><td><input type="text" name="sender" id="id_for_sender" /></td></tr>
<tr><th><label for="id_for_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></td></tr>
>>> print f.as_ul()
<li><label for="id_for_subject">Subject:</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" /></li>
<li><label for="id_for_message">Message:</label> <input type="text" name="message" id="id_for_message" /></li>
<li><label for="id_for_sender">Sender:</label> <input type="text" name="sender" id="id_for_sender" /></li>
<li><label for="id_for_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></li>
>>> print f.as_p()
<p><label for="id_for_subject">Subject:</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" /></p>
<p><label for="id_for_message">Message:</label> <input type="text" name="message" id="id_for_message" /></p>
<p><label for="id_for_sender">Sender:</label> <input type="text" name="sender" id="id_for_sender" /></p>
<p><label for="id_for_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></p>

Se o auto_id for setado para qualquer outro valor verdadeiro -- como uma string que não inclui %s -- então a biblioteca agirá como se o auto_id fosse True.

Por padrão, auto_id é setado como uma string 'id_%s'.

Normalmente, dois pontos (:) serão adicionados após qualquer nome de label quando um formulário for renderizado. É possível mudar os dois pontos por outro caracter, ou omiti-lo inteiramente, usando o paramêtro label_suffix:

>>> f = ContactForm(auto_id='id_for_%s', label_suffix='')
>>> print f.as_ul()
<li><label for="id_for_subject">Subject</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" /></li>
<li><label for="id_for_message">Message</label> <input type="text" name="message" id="id_for_message" /></li>
<li><label for="id_for_sender">Sender</label> <input type="text" name="sender" id="id_for_sender" /></li>
<li><label for="id_for_cc_myself">Cc myself</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></li>
>>> f = ContactForm(auto_id='id_for_%s', label_suffix=' ->')
>>> print f.as_ul()
<li><label for="id_for_subject">Subject -></label> <input id="id_for_subject" type="text" name="subject" maxlength="100" /></li>
<li><label for="id_for_message">Message -></label> <input type="text" name="message" id="id_for_message" /></li>
<li><label for="id_for_sender">Sender -></label> <input type="text" name="sender" id="id_for_sender" /></li>
<li><label for="id_for_cc_myself">Cc myself -></label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></li>

Note que o sufixo da label é adicionado somente se o último caracter da label não é um caracter de pontuação (., !, ? or :)

Notas sobre o campo de ordenação

Nos atalhos as_p(), as_ul() e as_table(), os campos são mostrados na ordem em que você definir na sua classe form. Por exemplo, no exemplo ContactForm, os campos são definidos nessa ordem: subject, message, sender, cc_myself. Para re-ordenar a saída HTML, é só mudar a ordem em que esses campos foram listados na classe.

Como os erros são mostrados

Se você renderiza um objeto Form bound, o ato de renderizar executará automaticamente a validação do formulário, caso ela ainda não tenha sido feita, e a saída HTML incluirá os erros de validação como um <ul class="errorlist"> perto de cada campo. O posicionamento das mensagens de erro depende da saída do método que você estiver usando:

>>> data = {'subject': '',
...         'message': 'Hi there',
...         'sender': 'invalid e-mail address',
...         'cc_myself': True}
>>> f = ContactForm(data, auto_id=False)
>>> print f.as_table()
<tr><th>Subject:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="subject" maxlength="100" /></td></tr>
<tr><th>Message:</th><td><input type="text" name="message" value="Hi there" /></td></tr>
<tr><th>Sender:</th><td><ul class="errorlist"><li>Enter a valid e-mail address.</li></ul><input type="text" name="sender" value="invalid e-mail address" /></td></tr>
<tr><th>Cc myself:</th><td><input checked="checked" type="checkbox" name="cc_myself" /></td></tr>
>>> print f.as_ul()
<li><ul class="errorlist"><li>This field is required.</li></ul>Subject: <input type="text" name="subject" maxlength="100" /></li>
<li>Message: <input type="text" name="message" value="Hi there" /></li>
<li><ul class="errorlist"><li>Enter a valid e-mail address.</li></ul>Sender: <input type="text" name="sender" value="invalid e-mail address" /></li>
<li>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></li>
>>> print f.as_p()
<p><ul class="errorlist"><li>This field is required.</li></ul></p>
<p>Subject: <input type="text" name="subject" maxlength="100" /></p>
<p>Message: <input type="text" name="message" value="Hi there" /></p>
<p><ul class="errorlist"><li>Enter a valid e-mail address.</li></ul></p>
<p>Sender: <input type="text" name="sender" value="invalid e-mail address" /></p>
<p>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></p>

Personalização do formato da lista de erros

Por padrão, formulários usam django.forms.util.ErrorList para formatar os erros de validação. Se você gostaria de usar uma classe alternativa para mostrar os erros, você pode passá-la na hora da construção:

>>> from django.forms.util import ErrorList
>>> class DivErrorList(ErrorList):
...     def __unicode__(self):
...         return self.as_divs()
...     def as_divs(self):
...         if not self: return u''
...         return u'<div class="errorlist">%s</div>' % ''.join([u'<div class="error">%s</div>' % e for e in self])
>>> f = ContactForm(data, auto_id=False, error_class=DivErrorList)
>>> f.as_p()
<div class="errorlist"><div class="error">This field is required.</div></div>
<p>Subject: <input type="text" name="subject" maxlength="100" /></p>
<p>Message: <input type="text" name="message" value="Hi there" /></p>
<div class="errorlist"><div class="error">Enter a valid e-mail address.</div></div>
<p>Sender: <input type="text" name="sender" value="invalid e-mail address" /></p>
<p>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></p>

Saída mais granular

Os métodos as_p(), as_ul() e as_table() são simplesmente atalhos para desenvolvedores preguiçosos -- eles não são a única forma de um objeto form ser mostrado.

Para mostrar o HTML para um único campo no seu formulário, use a sintaxe de acesso de dicionário, usando o nome do campo como chave, e imprimindo o objeto resultante:

>>> f = ContactForm()
>>> print f['subject']
<input id="id_subject" type="text" name="subject" maxlength="100" />
>>> print f['message']
<input type="text" name="message" id="id_message" />
>>> print f['sender']
<input type="text" name="sender" id="id_sender" />
>>> print f['cc_myself']
<input type="checkbox" name="cc_myself" id="id_cc_myself" />

Chame str() ou unicode() sobre um campo para obter seu HTML renderizado como uma string ou objeto Unicode, respectivamente:

>>> str(f['subject'])
'<input id="id_subject" type="text" name="subject" maxlength="100" />'
>>> unicode(f['subject'])
u'<input id="id_subject" type="text" name="subject" maxlength="100" />'

Objetos de formulário definem um método personalizado __iter__(), que permite você iterar sobre seus campos:

>>> f = ContactForm()
>>> for field in f: print field
<input id="id_subject" type="text" name="subject" maxlength="100" />
<input type="text" name="message" id="id_message" />
<input type="text" name="sender" id="id_sender" />
<input type="checkbox" name="cc_myself" id="id_cc_myself" />

A saída de um campo específico honra a configuração auto_id de objetos de formulários:

>>> f = ContactForm(auto_id=False)
>>> print f['message']
<input type="text" name="message" />
>>> f = ContactForm(auto_id='id_%s')
>>> print f['message']
<input type="text" name="message" id="id_message" />

Para uma lista de erros dos campos, acesse o atributo errors dos campos. Este é uma objeto tipo lista que é mostrado como um HTML <ul class="errorlist"> quando impresso:

>>> data = {'subject': 'hi', 'message': '', 'sender': '', 'cc_myself': ''}
>>> f = ContactForm(data, auto_id=False)
>>> print f['message']
<input type="text" name="message" />
>>> f['message'].errors
[u'This field is required.']
>>> print f['message'].errors
<ul class="errorlist"><li>This field is required.</li></ul>
>>> f['subject'].errors
[]
>>> print f['subject'].errors

>>> str(f['subject'].errors)
''

Vinculando arquivos enviados a um formulário

Novo no Django 1.0: Please, see the release notes

Lidar com formulários que possuem campos FileField e ImageField é um pouco mais complicado que um formulário normal.

Primeiramente, a fim de fazer o upload de arquivos, você precisará estar certo de que seu elemento <form> define corretamente o atributo enctype como "multipart/form-data":

<form enctype="multipart/form-data" method="post" action="/foo/">

Depois, quando você usar o formulário, você precisa tratar os dados do arquivo. Dados de arquivos são manipulados separadamente dos dados normais de formulário, então quando seu formulário contiver um FieldField e ImageField, você precisará especificar um segundo argumento quando for vincular o formulário. Então se nós extendemos nosso ContacForm para incluir um ImageField chamado mugshot, nós precisamos vincular os dados do arquivo que contém a imagem mugshot:

# Bound form with an image field
>>> from django.core.files.uploadedfile import SimpleUploadedFile
>>> data = {'subject': 'hello',
...         'message': 'Hi there',
...         'sender': 'foo@example.com',
...         'cc_myself': True}
>>> file_data = {'mugshot': SimpleUploadedFile('face.jpg', <file data>)}
>>> f = ContactFormWithMugshot(data, file_data)

Na prática, você normalemente especificará request.FILES como a fonte de dados do arquivo (da mesma forma do request.POST como a fonte de dados de formulários):

# Bound form with an image field, data from the request
>>> f = ContactFormWithMugshot(request.POST, request.FILES)

Constructing an unbound form is the same as always -- just omit both form data and file data:

# Unbound form with a image field
>>> f = ContactFormWithMugshot()

Testando formulários multipart

Se você está escrevendo views ou templates reusáveis, você pode não saber, antes do tempo, se seu formulário é um formulário multipart ou não. O método is_multipart() diz a você se o formulário requer codificação multipart para sua submissão:

>>> f = ContactFormWithMugshot()
>>> f.is_multipart()
True

Aqui temos um exemplo de como você pode usar isso num template:

{% if form.is_multipart %}
    <form enctype="multipart/form-data" method="post" action="/foo/">
{% else %}
    <form method="post" action="/foo/">
{% endif %}
{{ form }}
</form>

Extendendo formulários

Se você tem várias classes Form que compartilham campos, você pode usar herança para eliminar a redundância.

Quando você extende uma classe Form personalizada, à subclasse resultante será incluso todos os campos da(s) classe(s) pai, seguido pelos campos que você definiu na subclasse.

Neste exemplo, o ContactFormWithPriority contém todos os campos do ContactForm, mais um campo adicional, priority. Os campos do ContactForm são ordenados primeiro:

>>> class ContactFormWithPriority(ContactForm):
...     priority = forms.CharField()
>>> f = ContactFormWithPriority(auto_id=False)
>>> print f.as_ul()
<li>Subject: <input type="text" name="subject" maxlength="100" /></li>
<li>Message: <input type="text" name="message" /></li>
<li>Sender: <input type="text" name="sender" /></li>
<li>Cc myself: <input type="checkbox" name="cc_myself" /></li>
<li>Priority: <input type="text" name="priority" /></li>

É possível extender vários formulários, tratando formulários como "mix-ins". Neste exemplo, BeatleForm extende ambos PersonForm e InstrumentForm (nessa ordem), e sua lita de campos inclui os campos das classes pai:

>>> class PersonForm(Form):
...     first_name = CharField()
...     last_name = CharField()
>>> class InstrumentForm(Form):
...     instrument = CharField()
>>> class BeatleForm(PersonForm, InstrumentForm):
...     haircut_type = CharField()
>>> b = BeatleForm(auto_id=False)
>>> print b.as_ul()
<li>First name: <input type="text" name="first_name" /></li>
<li>Last name: <input type="text" name="last_name" /></li>
<li>Instrument: <input type="text" name="instrument" /></li>
<li>Haircut type: <input type="text" name="haircut_type" /></li>

Prefixes for forms

Form.prefix

Você pode colocar vários formulários Django dentro de uma tag <form>. Para dar a cada Form seu próprio namespace, use o argumento prefix:

>>> mother = PersonForm(prefix="mother")
>>> father = PersonForm(prefix="father")
>>> print mother.as_ul()
<li><label for="id_mother-first_name">First name:</label> <input type="text" name="mother-first_name" id="id_mother-first_name" /></li>
<li><label for="id_mother-last_name">Last name:</label> <input type="text" name="mother-last_name" id="id_mother-last_name" /></li>
>>> print father.as_ul()
<li><label for="id_father-first_name">First name:</label> <input type="text" name="father-first_name" id="id_father-first_name" /></li>
<li><label for="id_father-last_name">Last name:</label> <input type="text" name="father-last_name" id="id_father-last_name" /></li>