Quero adicionar automaticamente novos formulários a um conjunto de formulários do Django usando o Ajax, para que, quando o usuário clicar em um botão "adicionar", execute JavaScript que adicione um novo formulário (que faz parte do conjunto de formulários) à página.
260
Respostas:
É assim que eu faço, usando o jQuery :
Meu modelo:
Em um arquivo javascript:
O que faz:
cloneMore
aceitaselector
como o primeiro argumento e otype
formset como o 2º. O que o queselector
deve fazer é passar o que deve duplicar. Nesse caso, eu o passodiv.table:last
para que o jQuery procure a última tabela com uma classe detable
. A:last
parte disso é importante porqueselector
também é usada para determinar o que o novo formulário será inserido depois. É provável que você queira isso no final dos demais formulários. Otype
argumento é para que possamos atualizar omanagement_form
campo, principalmenteTOTAL_FORMS
, bem como os campos reais do formulário. Se você tem um formset cheio de, digamos,Client
modelos, os campos de gestão terá IDs deid_clients-TOTAL_FORMS
eid_clients-INITIAL_FORMS
, enquanto os campos do formulário será em um formato deid_clients-N-fieldname
comN
sendo o número do formulário, começando com0
. Assim, com otype
argumentocloneMore
de função analisa a forma como muitas formas atualmente existem, e passa por cada entrada e etiqueta dentro da nova forma de substituir todos os nomes de campo / ids de algo comoid_clients-(N)-name
aid_clients-(N+1)-name
e assim por diante. Depois de concluído, ele atualiza oTOTAL_FORMS
campo para refletir o novo formulário e o adiciona ao final do conjunto.Essa função é particularmente útil para mim porque, da maneira como está configurada, permite que eu a use em todo o aplicativo quando quero fornecer mais formulários em um conjunto de formulários e não me faz precisar ter um "modelo" oculto para duplicar contanto que eu o transmita, o nome do conjunto de formulários e o formato em que os formulários são dispostos. Espero que ajude.
fonte
prefix
membro do Formset Object. Este deve ter o mesmo valor que otype
argumento para acloneMore
função.Versão simplificada da resposta de Paolo usando
empty_form
como modelo.fonte
CompetitorFormSet = modelformset_factory(ProjectCompetitor, formset=CompetitorFormSets)
ctx['competitor_form_set'] = CompetitorFormSet(request.POST)
recebo apenas um formulário, no método clean. você pode explicar como lidar com isso em visualizações?empty_form
), o que eu aprecio.Eu postou um trecho de um aplicativo eu trabalhava em uma parte traseira tempo. Semelhante ao de Paolo, mas também permite excluir formulários.
fonte
A sugestão de Paolo funciona lindamente com uma ressalva - os botões voltar / avançar do navegador.
Os elementos dinâmicos criados com o script de Paolo não serão renderizados se o usuário retornar ao conjunto de formulários usando o botão voltar / avançar. Um problema que pode ser um rompimento de negócios para alguns.
Exemplo:
1) O usuário adiciona dois novos formulários ao formset usando o botão "add-more"
2) O usuário preenche os formulários e envia o conjunto de formulários
3) O usuário clica no botão Voltar no navegador
4) O Formset agora é reduzido ao formulário original, todos os formulários adicionados dinamicamente não estão lá
Este não é um defeito no script de Paolo; mas um fato da vida com manipulação dom e cache do navegador.
Suponho que alguém possa armazenar os valores do formulário na sessão e ter alguma mágica do ajax quando o formset for carregado para criar os elementos novamente e recarregar os valores da sessão; mas, dependendo de quão anal você deseja ser sobre o mesmo usuário e várias instâncias do formulário, isso pode se tornar muito complicado.
Alguém tem uma boa sugestão para lidar com isso?
Obrigado!
fonte
Confira as seguintes soluções para formulários dinâmicos de django:
http://code.google.com/p/django-dynamic-formset/
https://github.com/javisantana/django-dinamyc-form/tree/master/frm
Ambos usam o jQuery e são específicos do django. O primeiro parece um pouco mais polido e oferece um download que vem com demos excelentes.
fonte
Simule e imite:
<input>
campos.<input>
campos foram alterados.Embora eu saiba que os conjuntos de formulários usam
<input>
campos ocultos especiais e saiba aproximadamente o que o script deve fazer, não me lembro dos detalhes. O que eu descrevi acima é o que eu faria na sua situação.fonte
Existe um plugin jquery para isso , usei-o com o inline_form definido no Django 1.3, e ele funciona perfeitamente, incluindo pré-população, adição de formulários do lado do cliente, remoção e vários inline_formsets.
fonte
Uma opção seria criar um conjunto de formulários com todos os formulários possíveis, mas inicialmente defina os formulários não necessários como ocultos - ou seja
display: none;
,. Quando for necessário exibir um formulário, defina sua exibição em css comoblock
ou o que for apropriado.Sem saber mais detalhes do que seu "Ajax" está fazendo, é difícil dar uma resposta mais detalhada.
fonte
Outra versão cloneMore, que permite a higienização seletiva de campos. Use-o quando precisar impedir que vários campos sejam apagados.
fonte
Há um pequeno problema com a função cloneMore. Como também está limpando o valor dos campos ocultos gerados automaticamente pelo django, faz com que o django se queixe se você tentar salvar um conjunto de formulários com mais de um formulário vazio.
Aqui está uma correção:
fonte
Eu acho que essa é uma solução muito melhor.
Como você criaria um formset dinâmico no Django?
O clone das coisas não:
fonte
Para os codificadores que estão procurando recursos para entender um pouco melhor as soluções acima:
Django Dynamic Formsets
Depois de ler o link acima, a documentação do Django e as soluções anteriores devem fazer muito mais sentido.
Documentação do Django Formset
Como um resumo rápido do que eu estava ficando confuso: O Formulário de Gerenciamento contém uma visão geral dos formulários contidos nele. Você deve manter essas informações precisas para que o Django esteja ciente dos formulários adicionados. (Comunidade, por favor, me dê sugestões se algumas das minhas palavras estiverem desativadas aqui. Sou novo no Django.)
fonte
@Paolo Bergantino
clonar todos os manipuladores anexados apenas modifique a linha
para
para evitar esse problema.
fonte
Sim, eu também recomendo apenas renderizá-los no html se você tiver um número finito de entradas. (Caso contrário, você precisará usar outro método).
Você pode ocultá-los assim:
Então o js é realmente simples:
fonte
Como todas as respostas acima usam jQuery e tornam algumas coisas um pouco complexas, escrevi o seguinte script:
Primeiro, você deve definir auto_id como false e, assim, desativar a duplicação de id e nome. Como os nomes de entrada precisam ser únicos, toda a identificação é feita com eles e não com os IDs. Você também tem que substituir o
form
,type
e o recipiente do formset. (No exemplo acimachoices
)fonte