Manera adecuada de manejar múltiples formularios en una página en Django
Tengo una página de plantilla esperando dos formularios. Si solo uso un formulario, todo va bien como en este ejemplo típico:
if request.method == 'POST':
form = AuthorForm(request.POST,)
if form.is_valid():
form.save()
# do something.
else:
form = AuthorForm()
Sin embargo, si quiero trabajar con varios formularios, ¿cómo le hago saber a la vista que estoy enviando solo uno de los formularios y no el otro (es decir, sigue siendo request.POST pero solo quiero procesar el formulario para el cual se envió? sucedió)?
Esta es la solución basada en la respuesta donde la frase esperada y la frase prohibida son los nombres de los botones de envío para los diferentes formularios y la frase esperada y la frase prohibida son los formularios.
if request.method == 'POST':
if 'bannedphrase' in request.POST:
bannedphraseform = BannedPhraseForm(request.POST, prefix='banned')
if bannedphraseform.is_valid():
bannedphraseform.save()
expectedphraseform = ExpectedPhraseForm(prefix='expected')
elif 'expectedphrase' in request.POST:
expectedphraseform = ExpectedPhraseForm(request.POST, prefix='expected')
if expectedphraseform.is_valid():
expectedphraseform.save()
bannedphraseform = BannedPhraseForm(prefix='banned')
else:
bannedphraseform = BannedPhraseForm(prefix='banned')
expectedphraseform = ExpectedPhraseForm(prefix='expected')
Tienes pocas opciones:
Coloque diferentes URL en la acción para los dos formularios. Luego tendrá dos funciones de vista diferentes para manejar los dos formularios diferentes.
Lea los valores del botón de envío de los datos POST. Puede saber en qué botón de envío se hizo clic: ¿Cómo puedo crear un formulario Django con varios botones de envío?
Un método para referencia futura es algo como esto. la forma de frase prohibida es la primera forma y la forma de frase esperada es la segunda. Si se golpea el primero, se omite el segundo (lo cual es una suposición razonable en este caso):
if request.method == 'POST':
bannedphraseform = BannedPhraseForm(request.POST, prefix='banned')
if bannedphraseform.is_valid():
bannedphraseform.save()
else:
bannedphraseform = BannedPhraseForm(prefix='banned')
if request.method == 'POST' and not bannedphraseform.is_valid():
expectedphraseform = ExpectedPhraseForm(request.POST, prefix='expected')
bannedphraseform = BannedPhraseForm(prefix='banned')
if expectedphraseform.is_valid():
expectedphraseform.save()
else:
expectedphraseform = ExpectedPhraseForm(prefix='expected')
Necesitaba varios formularios que se validaran de forma independiente en la misma página. Los conceptos clave que me faltaban eran 1) usar el prefijo de formulario para el nombre del botón de envío y 2) un formulario ilimitado no activa la validación. Si ayuda a alguien más, aquí está mi ejemplo simplificado de dos formularios AForm y BForm usando TemplateView basado en las respuestas de @adam-nelson y @daniel-sokolowski y el comentario de @zeraien ( https://stackoverflow.com/a/17303480 /2680349 ):
# views.py
def _get_form(request, formcls, prefix):
data = request.POST if prefix in request.POST else None
return formcls(data, prefix=prefix)
class MyView(TemplateView):
template_name = 'mytemplate.html'
def get(self, request, *args, **kwargs):
return self.render_to_response({'aform': AForm(prefix='aform_pre'), 'bform': BForm(prefix='bform_pre')})
def post(self, request, *args, **kwargs):
aform = _get_form(request, AForm, 'aform_pre')
bform = _get_form(request, BForm, 'bform_pre')
if aform.is_bound and aform.is_valid():
# Process aform and render response
elif bform.is_bound and bform.is_valid():
# Process bform and render response
return self.render_to_response({'aform': aform, 'bform': bform})
# mytemplate.html
<form action="" method="post">
{% csrf_token %}
{{ aform.as_p }}
<input type="submit" name="{{aform.prefix}}" value="Submit" />
{{ bform.as_p }}
<input type="submit" name="{{bform.prefix}}" value="Submit" />
</form>