Criando formulários a partir de models¶
ModelForm
¶
Se você está construindo uma aplicação baseada em banco de dados, existe uma
grande chance de que seus formulários corresponderão com os seus modelos
Django. Por exemplo, você tem um modelo BlogComment
, e quer criar um
formulário que possibilite que as pessoas enviem comentários. Neste caso, seria
redundante definir os tipos de campo no seu formulário, porque isso já foi
feito no seu modelo.
Por este motivo, o Django disponibiliza uma classe de ajuda que possibilita
a criação de uma classe Form
a partir de um modelo Django.
Por exemplo:
>>> from django.forms import ModelForm
# Cria a classe de formulário
>>> class ArticleForm(ModelForm):
... class Meta:
... model = Article
# Criando um formulário para adicionar um artigo.
>>> form = ArticleForm()
# Criando um formulário para atualizar dados de um artigo.
>>> article = Article.objects.get(pk=1)
>>> form = ArticleForm(instance=article)
Tipos de campos¶
A classe Form
gerada terá um campo de formulário para cada campo de modelo.
Cada campo de modelo tem um campo de formulário correspondente padrão. Por
exemplo, um CharField
num modelo é representado como um CharField
num
formulário. Um ManyToManyField
no modelo é representado como um
MultipleChoiceField
. Segue uma lista completa de conversões:
Campo de modelo | Campo de formulário |
---|---|
AutoField |
Não é representado no formulário |
BooleanField |
BooleanField |
CharField |
CharField com max_length igual ao
valor de max_length do campo do modelo |
CommaSeparatedIntegerField |
CharField |
DateField |
DateField |
DateTimeField |
DateTimeField |
DecimalField |
DecimalField |
EmailField |
EmailField |
FileField |
FileField |
FilePathField |
CharField |
FloatField |
FloatField |
ForeignKey |
ModelChoiceField (veja abaixo) |
ImageField |
ImageField |
IntegerField |
IntegerField |
IPAddressField |
IPAddressField |
ManyToManyField |
ModelMultipleChoiceField (veja
abaixo) |
NullBooleanField |
CharField |
PhoneNumberField |
USPhoneNumberField
(de django.contrib.localflavor.us ) |
PositiveIntegerField |
IntegerField |
PositiveSmallIntegerField |
IntegerField |
SlugField |
CharField |
SmallIntegerField |
IntegerField |
TextField |
CharField com
widget=forms.Textarea |
TimeField |
TimeField |
URLField |
URLField com verify_exists igual
ao valor de verify_exists do campo
do modelo |
XMLField |
CharField com widget=Textarea |
FloatField
juntamente com os campos de fomulário
e de modelo DecimalField
são novos no Django 1.0.Como esperado, os campos de modelo do tipo ForeignKey
e ManyToManyField
são casos especiais:
ForeignKey
é representado pordjango.forms.ModelChoiceField
, que é umChoiceField
em quechoices
é umQuerySet
do modelo.ManyToManyField
é representado pordjango.forms.ModelMultipleChoiceField
, que é umMultipleChoiceField
em quechoices
é umQuerySet
do modelo.
Além disso, cada campo de formulário gerado tem os valores de atributos definidos como asseguir:
- Se um campo de modelo tem
blank=True
, então o valor derequired
seráFalse
no campo de formulário. Caso contrário,required=True
. - O atributo
label
do campo de formulário será igual aoverbose_name
do campo de modelo, com o primeiro caractere em maiúsculo. - O
help_text
do campo de formulário é igual aohelp_text
do campo de modelo. - Se o campo de modelo tem o atributo
choices
definido, então owidget
do campo de formulário será oSelect
, com a lista de opções vindas do atributochoices
do campo de modelo. As opções normalmente incluirão o valor em branco, que é selecionado por padrão. Se o campo é requerido, isso força o usuário a fazer uma escolha. O valor em branco não será incluído se o campo de modelo tem atributoblank=False
e um valor dedefault
explícito (em vez disso o valor dedefault
será selecionado inicialmente).
Finalmente, note que você pode redefinir o campo de formulário utilizado por um determinado modelo. Veja Redefinindo os tipos de campo padrão abaixo.
Um exemplo completo¶
Considere este conjunto de modelos:
from django.db import models
from django.forms import ModelForm
TITLE_CHOICES = (
('MR', 'Mr.'),
('MRS', 'Mrs.'),
('MS', 'Ms.'),
)
class Author(models.Model):
name = models.CharField(max_length=100)
title = models.CharField(max_length=3, choices=TITLE_CHOICES)
birth_date = models.DateField(blank=True, null=True)
def __unicode__(self):
return self.name
class Book(models.Model):
name = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
class AuthorForm(ModelForm):
class Meta:
model = Author
class BookForm(ModelForm):
class Meta:
model = Book
Com estes modelos, as subclasses de ModelForm
acima seriam equivalentes
a isto (a única diferença sendo o método save()
, que discutiremos daqui
a pouco.):
class AuthorForm(forms.Form):
name = forms.CharField(max_length=100)
title = forms.CharField(max_length=3,
widget=forms.Select(choices=TITLE_CHOICES))
birth_date = forms.DateField(required=False)
class BookForm(forms.Form):
name = forms.CharField(max_length=100)
authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all())
O método save()
¶
Todo formulário produzido por ModelForm
tem também um método
save()
. Este método cria e grava um objeto no banco de dados a partir
dos dados atrelados ao formulário. Uma subclasse de ModelForm
pode
aceitar uma instância de modelo existente como uma argumento nomeado
instance
; se este argumento é fornecido, o save()
irá atualizar
a instância. Se não é fornecido, o save()
criará uma nova instância do
modelo especificado:
# Cria uma instância de formulário com dados do POST.
>>> f = ArticleForm(request.POST)
# Grava um novo objeto Article com os dados do formulário.
>>> new_article = f.save()
# Cria um formulário para editar um Article existente.
>>> a = Article.objects.get(pk=1)
>>> f = ArticleForm(instance=a)
>>> f.save()
# Cria um formulário para editar um Article existente, mas
# usa os dados do POST para popular o formulário.
>>> a = Article.objects.get(pk=1)
>>> f = ArticleForm(request.POST, instance=a)
>>> f.save()
Note que save()
irá levantar uma exceção ValueError
se os dados no
formulário não validarem – ou seja if form.errors
.
Este método save()
aceita um argumento nomeado opcional commit
, que
aceita ou True
ou False
. Se você chamar save()
com
commit=False
, então ele devolverá um objeto que ainda não foi gravado no
banco de dados. Neste caso, é sua responsabilidade chamar save()
na
instância de modelo. Isso é útil se você quer fazer algum custom processamento customizado
no objeto antes de gravá-lo, ou se você quer usar um umas das
opções de gravação de modelo especializadas. commit
é True
por padrão.
Um efeito colateral no uso de commit=False
é notado quando o seu modelo
tem um relacionamento de muitos para muitos com outro modelo. Se seu modelo tem
um relacionamento de muitos para muitos e você especifica commit=False
quando vai gravar um formulário, o Django não pode gravar od dados para o
relacionamento de muitos para muitos imediatamente. Isso se deve ao fato de
não ser possível gravar os dados de muitos para muitos para uma instância que
ainda não existe no banco de dados.
Para contornar este problema, cada vez que você grava um formulário usando
commit=False
, o Django adiciona um método save_m2m()
para a sua
subclasse de ModelForm
. Depois de de gravar manualmente a instância
produzida pelo formulário, você pode chamar save_m2m()
para gravar
os dados de muitos para muitos do formulário. Por exemplo:
# Cria uma instância de formulário com os dados de POST.
>>> f = AuthorForm(request.POST)
# Cria, mas não grava a nova instância de Author.
>>> new_author = f.save(commit=False)
# Modifica o Author de alguma maneira.
>>> new_author.some_field = 'some_value'
# Grava a nova instância.
>>> new_author.save()
# Agora, grava od dados de muitos para muitos para o formulário.
>>> f.save_m2m()
Só é necessário chamar o save_m2m()
se você usar save(commit=False)
.
Quando você simplesmente usa o save()
num formulário, todos os dados –
incluindo os dados de muitos para muitos – são gravados sem a necessidade de
chamadas a nenhum método adicional.
Por exemplo:
# Cria uma instância de formulário com os dados de POST.
>>> a = Author()
>>> f = AuthorForm(request.POST, instance=a)
# Cria e grava a nova instância de Author. Não há necessidade de fazer
# nada mais.
>>> new_author = f.save()
A não ser pelos métodos save()
e save_m2m()
, um ModelForm
funciona exatamente igual a qualquer outro formulário de forms
.
Por exemplo, o método is_valid()` é utilizado para validar os dados, o método
is_multipart()
para determinar se um formulário requer upload de arquivo
multipart (e se request.FILES
deve ser passado ao formulário), etc. Veja
Vinculando arquivos enviados a um formulário para mais informação.
Usando somente alguns campos no formulário¶
Em alguns casos, você não quer que todos os campos do modelo apareçam no
formulário gerado. Existem três maneiras de dizer ao ModelForm
para usar
somente alguns campos do modelo:
- Coloque
editable=False
no campo do modelo. Como resultado, qualquer formulário criado viaModelForm
não incluirá este campo. - Use o atributo
fields
da classe internaMeta
doModelForm
. Esse atributo, se especificado, deve ser uma lista de nomes de campos a serem incluídos no formulário. - Use o atributo
exclude
da classe internaMeta
doModelForm
. Esse atributo, se especificado, deve ser uma lista de nomes de campos a serem excluídos do formulário.
Por exemplo, se você quer que um formulário para o modelo Author
(definido acima) tenha somente os campos name
e title
,
você especificaria fields
ou exclude
assim:
class PartialAuthorForm(ModelForm):
class Meta:
model = Author
fields = ('name', 'title')
class PartialAuthorForm(ModelForm):
class Meta:
model = Author
exclude = ('birth_date',)
Já que o modelo Author tem somente três campos, ‘name’, ‘title’, e ‘birth_date’, os formulários acima conterão exatamente os mesmos campos.
Note
Se você especifica fields
ou exclude
na criação de um formulário
com ModelForm
, então na chamada do método save()
, não serão
atribuídos valores aos campos que não constam do formulário resultante.
O Django impedirá qualquer tentativa de gravar um modelo incompleto,
então se o modelo não permite que os campos faltantes sejam vazios, e não
existe um valor padrão definido para eles, qualquer tentativa de chamar
save()
num ModelForm
com campos faltantes não funcionará.
Para evitar esse erro, você deve instanciar seu modelo com valores iniciais
para os campos vazios, porém obrigatórios:
author = Author(title='Mr')
form = PartialAuthorForm(request.POST, instance=author)
form.save()
Alternatively, you can use save(commit=False)
and manually set
any extra required fields:
form = PartialAuthorForm(request.POST)
author = form.save(commit=False)
author.title = 'Mr'
author.save()
Veja a seção sobre gravação de formulários para mais detalhes no
uso de save(commit=False)
.
Redefinindo os tipos de campo padrão¶
Os tipos de campos padrão, como descritos na tabela Tipos de campos acima,
são padrões sensatos. Se você tem um DateField
no seu modelo, existem
grandes chances dq que você queira que ele seja representado como um
DateField
no seu formulário. Mas o ModelForm
te dá a flexibilidade
de mudar o campo de formulário para um determinado campo de modelo. Isso é
feito de maneira declarativa especificando os campos como faria num Form
normal. Campos declarados redefinirão os campós padrões gerados pelo uso
do atributo model
.
Por exemplo, se você quiser usar MyDateFormField
para o campo
pub_date
, faça o seguinte:
>>> class ArticleForm(ModelForm):
... pub_date = MyDateFormField()
...
... class Meta:
... model = Article
Se quiser redefiner um widget padrão de um campo, então especifique o parâmetro widget quando declarar o campo de formulário:
>>> class ArticleForm(ModelForm):
... pub_date = DateField(widget=MyDateWidget())
...
... class Meta:
... model = Article
Sobrescrevendo o método clean()¶
Você pode sobrescrever o método clean()
em um formulário de modelo para fornecer informações
adicionais como uma validação, da mesma forma que faria num formulário normal.
In this regard, model forms have two specific characteristics when compared to forms:
Por padrão o método clean()
valida a unicidade dos campos que são
marcados como unique
, unique_together
ou unique_for_date|month|year
no
modelo. Portanto, se você gostaria de sobrescrever o método clean()
e
manter a validação padrão, você deve chamar o método da clean()
da classe pai.
Also, a model form instance bound to a model object will contain a
self.instance
attribute that gives model form methods access to that
specific model instance.
Herança de formulário¶
Como nos formulários básicos, você pode extender e reutilizar ModelForms
através da herança. Isso é útil se você precisa declarar campos ou métodos
adicionais em uma classe pai para uso em alguns formulários derivados de
modelos. Por exemplo, usando a classe ArticleForm
anterior:
>>> class EnhancedArticleForm(ArticleForm):
... def clean_pub_date(self):
... ...
Isso cria um formulário que se comporta da mesma maneira que ArticleForm
,
exceto por alguma validação e limpeza de dados adicional para o campo
pub_date
.
Você pode criar uma subclasse da classe interna Meta
da classe pai se você
quer mudar as listas Meta.fields
ou Meta.excludes
:
>>> class RestrictedArticleForm(EnhancedArticleForm):
... class Meta(ArticleForm.Meta):
... exclude = ['body']
Isso adiciona o método de EnhancedArticleForm
e modifica o
ArticleForm.Meta
original para remover um campo.
Entretanto, existem algumas coisas a serem notadas.
- As regras normais de resolução de nomes Python se aplicam. Se você tem
múltiplas classes base que declaram uma classe interna
Meta
, somente a primeira será utilizada. Isso significa oMeta
do filho, se existir, caso contrário oMeta
do primeiro pai, etc. - Pela mesma razão, uma subclasse não pode herdar de
ModelForm
eForm
simultaneamente.
É bem provável que estas notas não te afetarão, a não ser que esteja tentando fazer algo complexo utilizando subclasses.
Model Formsets¶
Como nos formsets comuns, o Django fornece um par de
classes avançadas de formset que tornam facil trabalhar com modelos do Django. Vamos
reutilizar o modelo Author
do exemplo acima:
>>> from django.forms.models import modelformset_factory
>>> AuthorFormSet = modelformset_factory(Author)
Isso criará um formset que é capaz de funcionar com os dados associados ao
modelo Author
que funciona exatamente igual a um formset comum:
>>> formset = AuthorFormSet()
>>> print formset
<input type="hidden" name="form-TOTAL_FORMS" value="1" id="id_form-TOTAL_FORMS" /><input type="hidden" name="form-INITIAL_FORMS" value="0" id="id_form-INITIAL_FORMS" />
<tr><th><label for="id_form-0-name">Name:</label></th><td><input id="id_form-0-name" type="text" name="form-0-name" maxlength="100" /></td></tr>
<tr><th><label for="id_form-0-title">Title:</label></th><td><select name="form-0-title" id="id_form-0-title">
<option value="" selected="selected">---------</option>
<option value="MR">Mr.</option>
<option value="MRS">Mrs.</option>
<option value="MS">Ms.</option>
</select></td></tr>
<tr><th><label for="id_form-0-birth_date">Birth date:</label></th><td><input type="text" name="form-0-birth_date" id="id_form-0-birth_date" /><input type="hidden" name="form-0-id" id="id_form-0-id" /></td></tr>
Note
Uma coisa para se notar é que modelformset_factory
usa
formset_factory
para gerar formsets. Isto significa que um formeset de
model é somente uma extensão de um formset básico que sabe como interagir
com um model em particular.
Mudando o queryset¶
Por padrão quando você cria um formset de um modelo o formset irá usar um
queryset que inclui todos os objetos no modelo (ex: Author.objects.all()
).
Você pode sobrescrever esse comportamento usando o argumento queryset
:
>>> formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith='O'))
Alternativamente, você pode criar uma subclasse que defina o self.queryset
no
__init__
:
from django.forms.models import BaseModelFormSet
class BaseAuthorFormSet(BaseModelFormSet):
def __init__(self, *args, **kwargs):
self.queryset = Author.objects.filter(name__startswith='O')
super(BaseAuthorFormSet, self).__init__(*args, **kwargs)
Então, passe sua classe BaseAuthorFormSet
para a função factory:
>>> AuthorFormSet = modelformset_factory(Author, formset=BaseAuthorFormSet)
Controlando quais campos são usados com fields
e exclude
¶
Por padrão um model formset usará todos os campos do model, que não estão
marcados com editable=False
, Entretanto, isto pode ser sobrescrito no nível
do formset:
>>> AuthorFormSet = modelformset_factory(Author, fields=('name', 'title'))
Usando fields
você irá restringir o formset para usar somente os campos
fornecidos. Alternativamente, você pode ter uma abordagem de “out-put”,
especificando quais campos serão excluídos:
>>> AuthorFormSet = modelformset_factory(Author, exclude=('birth_date',))
Usando exclude
você irá evistar que dados campos sejam usados em um formset.
Gravando objetos num formset¶
Como num ModelForm
você pode gravar os dados no objeto do modelo. Isso é
feito com o método save()
do formset:
# Cria uma instância de formset com os dados do POST.
>>> formset = AuthorFormSet(request.POST)
# Supondo que tudo está válido, grave os dados
>>> instances = formset.save()
O método save()
devolverá as instâncias que foram gravadas no banco de
dados. Se uma instância não mudar seus nos dados atrelados ela não será gravada
no banco e não será encontrada no valor de retorn (instances
no exemplo acima).
Pass commit=False
to return the unsaved model instances:
# não grava no banco de dados
>>> instances = formset.save(commit=False)
>>> for instance in instances:
... # faz alguma coisa com a instância
... instance.save()
Isso dá a habilidade de anexar dados às instâncias antes de gravá-las no banco
de dados. Se seu formset contém um ManyToManyField
você precisará também
chamar formset.save_m2m()
para assegurar que os relacionamentos de muitos
para muitos serão gravados apropriadamente.
Limitando o número de objetos editáveis¶
Como em formsets comuns você pode usar um parâmetro max_num
no
modelformset_factory
para limitar o número de formulários mostrados.
Com formsets de modelo, isso limitará apropriadamente a query para selecionar
somente o máximo de objetos necessários:
>>> Author.objects.order_by('name')
[<Author: Charles Baudelaire>, <Author: Paul Verlaine>, <Author: Walt Whitman>]
>>> AuthorFormSet = modelformset_factory(Author, max_num=2, extra=1)
>>> formset = AuthorFormSet(queryset=Author.objects.order_by('name'))
>>> formset.initial
[{'id': 1, 'name': u'Charles Baudelaire'}, {'id': 3, 'name': u'Paul Verlaine'}]
Se o valor de max_num
é maior que o número de objetos retornados,
formulários em branco extra
serão adicionados ao formset, tão logo o total
de formulários não exceda max_num
:
>>> AuthorFormSet = modelformset_factory(Author, max_num=4, extra=2)
>>> formset = AuthorFormSet(queryset=Author.objects.order_by('name'))
>>> for form in formset.forms:
... print form.as_table()
<tr><th><label for="id_form-0-name">Name:</label></th><td><input id="id_form-0-name" type="text" name="form-0-name" value="Charles Baudelaire" maxlength="100" /><input type="hidden" name="form-0-id" value="1" id="id_form-0-id" /></td></tr>
<tr><th><label for="id_form-1-name">Name:</label></th><td><input id="id_form-1-name" type="text" name="form-1-name" value="Paul Verlaine" maxlength="100" /><input type="hidden" name="form-1-id" value="3" id="id_form-1-id" /></td></tr>
<tr><th><label for="id_form-2-name">Name:</label></th><td><input id="id_form-2-name" type="text" name="form-2-name" value="Walt Whitman" maxlength="100" /><input type="hidden" name="form-2-id" value="2" id="id_form-2-id" /></td></tr>
<tr><th><label for="id_form-3-name">Name:</label></th><td><input id="id_form-3-name" type="text" name="form-3-name" maxlength="100" /><input type="hidden" name="form-3-id" id="id_form-3-id" /></td></tr>
Usando um model formset em uma visão¶
Models formsets são muito similares a formsets. Digamos que queiramos apresentar um
formset para editar instâncias do modelo Author
:
def manage_authors(request):
AuthorFormSet = modelformset_factory(Author)
if request.method == 'POST':
formset = AuthorFormSet(request.POST, request.FILES)
if formset.is_valid():
formset.save()
# Faça algo.
else:
formset = AuthorFormSet()
return render_to_response("manage_authors.html", {
"formset": formset,
})
Como você pode ver a lógica da visão de um formset de modelo não é drasticamente diferente
de como usar um formset “normal”. A única diferença é que nos chamamos
formset.save()
para salvar os dados no banco de dados. (Isto foi descrito acima em
Gravando objetos num formset.)
Sobrescrevendo o clean()
sobre um model_formset
¶
Assim como com ModelForms
, por padrão o método clean()
de um
model_formset
irá validar se nenhum dos ítens do formset viola as restrições
de unicidade do seu model (qualquer uma unique
, unique_together
ou
unique_for_date|month|year
). Se você quiser sobrescrever o método
clean()
de um model_formset
e manter esta validação, você deve chamar
o método clean
da classe pai:
class MyModelFormSet(BaseModelFormSet):
def clean(self):
super(MyModelFormSet, self).clean()
# exemplo de validação customizada de forms do formset:
for form in self.forms:
# your custom formset validation
# sua validação personalizada de formset
Usando um queryset customizado¶
Como já foi dito, você pode sobrescrever o queryset padrão usado pelo model formset:
def manage_authors(request):
AuthorFormSet = modelformset_factory(Author)
if request.method == "POST":
formset = AuthorFormSet(request.POST, request.FILES,
queryset=Author.objects.filter(name__startswith='O'))
if formset.is_valid():
formset.save()
# Faça algo.
else:
formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith='O'))
return render_to_response("manage_authors.html", {
"formset": formset,
})
Note que nós passamos o argumento queryset
em ambos os casos POST
e
GET
neste exemplo.
Usando o formset no template¶
Já três formas de renderizar um formset num template Django.
Primeiro, você pode deixar o formset fazer a maior parte do trabalho:
<form method="POST" action="">
{{ formset }}
</form>
Segundo, você pode manualmente renderizar o formset, mas deixe o form trabalhar por contra própria:
<form method="POST" action="">
{{ formset.management_form }}
{% for form in formset.forms %}
{{ form }}
{% endfor %}
</form>
Quando você renderizar formulários manualmente, certifique-se de renderizar o management_form como mostrado acima. Veja a documentação do management form.
Terceiro, você pode renderizar manualmente cada campo:
<form method="POST" action="">
{{ formset.management_form }}
{% for form in formset.forms %}
{% for field in form %}
{{ field.label_tag }}: {{ field }}
{% endfor %}
{% endfor %}
</form>
Se você optar por usar este terceiro método e você não iterar sobre os campos
com um loop {% for %}
, você precisará renderizar a chave primária.
Por exemplo, se você renderizou os campos name
e age
de um model:
<form method="POST" action="">
{{ formset.management_form }}
{% for form in formset.forms %}
{{ form.id }}
<ul>
<li>{{ form.name }}</li>
<li>{{ form.age }}</li>
</ul>
{% endfor %}
</form>
Observe como é preciso, explicitamente, renderizar {{form.id}}
. Isto garante
que o formset do model, no caso do POST
, irá funcionar perfeitamente. (Este
exemplo assume uma chave primária chamada id
, certifique-se de
renderizá-la.)
Formsets em linha (inline)¶
Formsets em linha é uma pequena camada de abstração sobre os formsets de model. Este simplificam o caso de trabalhar com objetos relacionados através de uma chave estrangeira. Suponhamos que você tenha dois models:
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
author = models.ForeignKey(Author)
title = models.CharField(max_length=100)
Se você quiser criar um formset que permita editar books pertencentes a um author em particular, você pode fazer isto:
>>> from django.forms.models import inlineformset_factory
>>> BookFormSet = inlineformset_factory(Author, Book)
>>> author = Author.objects.get(name=u'Mike Royko')
>>> formset = BookFormSet(instance=author)
Note
inlineformset_factory
usa modelformset_factory
e marca
can_delete=True
.
Mais de uma chave estrangeira para o mesmo model¶
Se o seu model contém mais de uma chave estrangeira para o mesmo model, você
precisará resolver a ambiguidade manualmente utilizando fk_name
. Por
exemplo, considere o seguinte model:
class Friendship(models.Model):
from_friend = models.ForeignKey(Friend)
to_friend = models.ForeignKey(Friend)
length_in_months = models.IntegerField()
Para resolver isto, você pode usar fk_name
para inlineformset_factory
:
>>> FriendshipFormSet = inlineformset_factory(Friend, Friendship, fk_name="from_friend")
Usando um formset em linha em um view¶
Você pode querer prover um view que permite um usuário editar os objetos relacionados de um model. Aqui tem uma maneira de se fazer isso:
def manage_books(request, author_id):
author = Author.objects.get(pk=author_id)
BookInlineFormSet = inlineformset_factory(Author, Book)
if request.method == "POST":
formset = BookInlineFormSet(request.POST, request.FILES, instance=author)
if formset.is_valid():
formset.save()
# Do something.
else:
formset = BookInlineFormSet(instance=author)
return render_to_response("manage_books.html", {
"formset": formset,
})
Observe como passamos instance
em ambos os casos POST
e GET
.