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))
Eldila
fonte

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

Conceder
fonte
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()
Josh
fonte
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'
seddonym
fonte
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()
Milo P
fonte
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
Vineeth Sai
fonte
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
ckarrie
fonte
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">'
dr. Sybren
fonte
0

no widget, use 'valor' attr. Exemplo:

username = forms.CharField(
    required=False,
    widget=forms.TextInput(attrs={'readonly': True, 'value': 'CONSTANT_VALUE'}),
)
Lucas vazquez
fonte
-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()
Nigel Cohen
fonte
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