Como usar valores de formulário de um formulário não vinculado
Pergunta
Tenho um relatório web que utiliza um formulário Django (novos formulários) para campos que controlam a consulta utilizada para gerar o relatório (data de início, data de término,...).O problema que estou tendo é que a página deve funcionar usando os valores iniciais do formulário (não vinculados), mas não consigo acessar o campo clean_data a menos que eu chame is_valid().Mas is_valid() sempre falha em formulários não vinculados.
Parece que os formulários do Django foram projetados com o caso de edição de dados, de modo que um formulário não vinculado não seja realmente útil para outra coisa senão a exibição de HTML.
Por exemplo, se eu tiver:
if request.method == 'GET':
form = MyForm()
else:
form = MyForm(request.method.POST)
if form.is_valid():
do_query(form.cleaned_data['start_date'], form.cleaned_data['end_date'])
is_valid() falhará se for um GET (já que não está vinculado) e se eu fizer isso:
if request.method == 'GET':
form = MyForm()
do_query(form.cleaned_data['start_date'], form.cleaned_data['end_date'])
else:
form = MyForm(request.method.POST)
if form.is_valid():
do_query(form.cleaned_data['start_date'], form.cleaned_data['end_date'])
a primeira chamada para do_query aciona exceções em form.cleaned_data, que não é um campo válido porque is_valid() não foi chamado.Parece que tenho que fazer algo como:
if request.method == 'GET':
form = MyForm()
do_query(form['start_date'].field.initial, form['end_date'].field.initial)
else:
form = MyForm(request.method.POST)
if form.is_valid():
do_query(form.cleaned_data['start_date'], form.cleaned_data['end_date'])
isto é, não existe uma interface comum para recuperar os valores do formulário entre um formulário vinculado e um não vinculado.
Alguém vê uma maneira mais limpa de fazer isso?
Solução
Se você adicionar este método à sua classe de formulário:
def get_cleaned_or_initial(self, fieldname):
if hasattr(self, 'cleaned_data'):
return self.cleaned_data.get(fieldname)
else:
return self[fieldname].field.initial
você poderia então reescrever seu código como:
if request.method == 'GET':
form = MyForm()
else:
form = MyForm(request.method.POST)
form.is_valid()
do_query(form.get_cleaned_or_initial('start_date'), form.get_cleaned_or_initial('end_date'))
Outras dicas
Não consolidado significa que não há dados associados ao formulário (iniciais ou fornecidos posteriormente), portanto a validação pode falhar.Conforme mencionado em outras respostas (e em sua própria conclusão), você deve fornecer valores iniciais e verificar os dados vinculados e os valores iniciais.
O caso de uso para formulários é o processamento de formulários e validação, então você deve ter alguns dados para validar antes de acessar cleaned_data
.
Você pode passar um dicionário de valores iniciais para o seu formulário:
if request.method == "GET":
# calculate my_start_date and my_end_date here...
form = MyForm( { 'start_date': my_start_date, 'end_date': my_end_date} )
...
Veja o documentação oficial da API de formulários, onde eles demonstram isso.
editar:Com base nas respostas de outros usuários, talvez esta seja a solução mais limpa:
if request.method == "GET":
form = MyForm()
form['start_date'] = form['start_date'].field.initial
form['end_date'] = form['end_date'].field.initial
else:
form = MyForm(request.method.POST)
if form.is_valid():
do_query(form.cleaned_data['start_date'], form.cleaned_data['end_date'])
Eu ainda não tentei isso;alguém pode confirmar que isso funciona?Acho que isso é melhor do que criar um novo método, porque essa abordagem não requer outro código (possivelmente não escrito por você) para saber sobre seu novo acessador 'mágico'.