Django define o valor do campo depois que um formulário é inicializado


116

Estou tentando definir o campo para um determinado valor depois que o formulário é inicializado.

Por exemplo, tenho a seguinte aula.

class CustomForm(forms.Form):
    Email = forms.EmailField(min_length=1, max_length=200)

Na visualização, quero ser capaz de fazer algo assim:

form = CustomForm()
form["Email"] = GetEmailString()

return HttpResponse(t.render(c))

Respostas:


135

Como você não está transmitindo dados POST, assumirei que o que você está tentando fazer é definir um valor inicial que será exibido no formulário. A maneira de fazer isso é com a initialpalavra - chave.

form = CustomForm(initial={'Email': GetEmailString()})

Veja a documentação do formulário Django para mais explicações.

Se estiver tentando alterar um valor após o envio do formulário, você pode usar algo como:

if form.is_valid():
    form.cleaned_data['Email'] = GetEmailString()

Verifique os documentos mencionados acima para obter mais informações sobre como usar cleaned_data


2
Isso confirma o que eu sabia, mas ModelChoiceFieldainda estou fornecendo invalid_choice quando initial
atribuo a

Sim, esse é o meu problema também. E alterar form.data ['Email'] não é possível.
GergelyPolonkai

2
mudei o meu para form.data['Email'] = GetEmailString()e funciona
psychok7

1
Preciso defini-lo entre CustomForm (request.POST) e .is_valid (), então não posso usar o initial no construtor, nem o cleaning_data. Tentei usar form.data, mas é imutável (Django 1.11).
Teekin

A solução correta para esta questão, deveria ser: form.fields['Email'].initial = GetEmailString() O form.fields['keyword'].initialdá acesso para inicializar seus valores mesmo depois de ter instanciado seu formulário
vctrd

95

Se você já inicializou o formulário, pode usar a propriedade inicial do campo. Por exemplo,

form = CustomForm()
form.fields["Email"].initial = GetEmailString()

Também funciona muito bem em um loop for com um formset, basta usar a lógica "for form in formset" e você pode definir escolhas e dados iniciais como visto acima.
radtek

5
Existe uma maneira diferente de fazer isso é Django 1.7 / Python 3.4? Isso não está funcionando para mim
Jeremy

1
@JeremyCraigMartinez: Não ... O formulário que você está tentando usar é um formulário vinculado (com dados GET / POST passados)? Os documentos dizem que é por isso que os valores iniciais são exibidos apenas para formulários não acoplados. Para formulários vinculados, a saída HTML usará os dados vinculados. , veja aqui
Markus

9
a maneira correta é form.initial ["Email"] = GetEmailString ()
Elio Scordo

12

Se quiser fazer isso dentro do __init__método do formulário por algum motivo, você pode manipular o initialdict:

class MyForm(forms.Form):
    my_field = forms.CharField(max_length=255)

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        self.initial['my_field'] = 'Initial value'

Finalmente encontrei a solução. Obrigado. Funcionou para mim.
Almas Dusal

8

Algo como o de Nigel Cohen funcionaria se você estivesse adicionando dados a uma cópia do conjunto coletado de dados do formulário:

form = FormType(request.POST)
if request.method == "POST":
    formcopy = form(request.POST.copy())
    formcopy.data['Email'] = GetEmailString()

1
Não sou um grande fã de substituir os dados brutos. Se você realmente tiver que fazer isso, provavelmente deverá data[form.add_prefix('Email')]considerar os casos em que um prefixo é definido.
Josh

2
Existe uma maneira diferente de fazer isso é Django 1.7 / Python 3.4? Isso não está funcionando para mim
Jeremy

A terceira linha pode ser um pouco mais curta se não houver necessidade de manter a forma original:form.data = form.data.copy()
ZZY

@Josh, aqui está um cenário de necessidade: usar um formulário para validar a entrada -> processamento com a entrada -> processamento concluído -> apagar / modificar vários campos do formulário e renderizar em HTML como resposta. Por exemplo, existem campos 'nome', 'e-mail', 'conteúdo' em um formulário, desejo manter 'nome' e 'e-mail', mas apagar 'conteúdo'. Para que os usuários não precisem inserir nome / e-mail novamente, se quiserem enviar outro POST. Claro, inicializar um novo formulário com o mesmo nome / e-mail que o valor inicial é uma maneira, mas acho que apagar no formulário antigo é mais simples em alguns casos
ZZY

Não tenho certeza se entendi totalmente. No entanto, se eu fizer isso, parece-me que você deveria, em vez disso, usar modelform_factory. Desta forma, você pode gerar uma classe Form que não possui os campos que você não deseja. É muito perigoso ter uma classe Form que tem campos que não são renderizados, pois o objeto de formulário ainda aceitará dados para os campos não renderizados. Um invasor pode usar isso a seu favor.
Josh

5

Se você inicializou o formulário assim

form = CustomForm()

então, a maneira correta a partir de janeiro de 2019 é usar .initialpara substituir os dados. Isso substituirá os dados no intialdicionário que acompanha o formulário. Também funciona se você inicializou usando alguma instância, como form = CustomForm(instance=instance)

Para substituir os dados no formulário, você precisa

form.initial['Email'] = GetEmailString()

Generalizando isso seria,

form.initial['field_name'] = new_value

3

Basta alterar o campo Form.data:

class ChooseProjectForm(forms.Form):
    project = forms.ModelChoiceField(queryset=project_qs)
    my_projects = forms.BooleanField()

    def __init__(self, *args, **kwargs):
        super(ChooseProjectForm, self).__init__(*args, **kwargs)
        self.data = self.data.copy()  # IMPORTANT, self.data is immutable
        # any condition:
        if self.data.get('my_projects'):
            my_projects = self.fields['project'].queryset.filter(my=True)
            self.fields['project'].queryset = my_projects
            self.fields['project'].initial = my_projects.first().pk
            self.fields['project'].empty_label = None  # disable "-----"
            self.data.update(project=my_projects.first().pk)  # Update Form data
            self.fields['project'].widget = forms.HiddenInput()  # Hide if you want

0

Para lançar mais um caminho na mistura: isso também funciona, com uma notação um pouco mais moderna. Ele apenas contorna o fato de que a QueryDicté imutável.

>>> the_form.data = {**f.data.dict(), 'some_field': 47}
>>> the_form['some_field'].as_widget()
'<input type="hidden" name="some_field" value="47"
        class="field-some_field" id="id_some_field">'

0

no widget, use 'valor' attr. Exemplo:

username = forms.CharField(
    required=False,
    widget=forms.TextInput(attrs={'readonly': True, 'value': 'CONSTANT_VALUE'}),
)

-12

Outra maneira de fazer isso, se você já inicializou um formulário (com ou sem dados) e precisa adicionar mais dados antes de exibi-lo:

form = Form(request.POST.form)
form.data['Email'] = GetEmailString()

8
Isso falha para mim. Eu tenho uma linha como a acima no método init do meu formulário , e ela gera "AttributeError: Esta instância QueryDict é imutável"
Jonathan Hartley

Este código só funciona quando o formulário foi inicializado sem quaisquer dados de formulário. Como resultado, um objeto imutável como request.GET ou request.POST não será vinculado, então você obterá um dicionário vazio (form.data) que pode ser alterado sem erros. Para sua informação, estou usando Django 1.6.3
potar

Isso funcionará se o cabeçalho "Content-Type" estiver definido como "multipart / form-data". Ele falha quando você usa um tipo de conteúdo de "application / x-www-form-urlencoded". Eu não sei por que, mas era um bicho para depurar.
teewuane
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.