Formatos Django: ¿Hacer primero lo requerido?

Estas formas están exhibiendo exactamente el comportamiento opuesto que yo quiero.

Mi punto de vista está configurado de esta manera:

def post(request): # TODO: handle vehicle formset VehicleFormSetFactory = formset_factory(VehicleForm, extra=1) if request.POST: vehicles_formset = VehicleFormSetFactory(request.POST) else: vehicles_formset = VehicleFormSetFactory() 

Y mi plantilla se ve así:

  
{{ vehicles_formset.management_form }} {% for form in vehicles_formset.forms %}

Vehicle {{forloop.counter}}

{% include "form.html" %}
{% endfor %}

De esa manera inicialmente genera solo 1 formulario, como yo quiero. ¡Pero quiero que esa única forma sea requerida!

Cuando agrego dinámicamente formularios en blanco con JavaScript y vehicles_formset.empty_form se requieren todas esas formas adicionales, que no quiero.

De los documentos:

El formset es lo suficientemente inteligente como para ignorar formularios adicionales que no fueron cambiados.

Este es el comportamiento que muestra la primera forma (no es lo que quiero) pero no el comportamiento que exhiben las formas adicionales (lo que sí quiero).

¿Hay algún atributo que pueda cambiar para al menos hacer una forma requerida?

Encontré una mejor solución:

 class RequiredFormSet(BaseFormSet): def __init__(self, *args, **kwargs): super(RequiredFormSet, self).__init__(*args, **kwargs) for form in self.forms: form.empty_permitted = False 

Luego crea tu formset así:

 MyFormSet = formset_factory(MyForm, formset=RequiredFormSet) 

Realmente no sé por qué esta no era una opción para empezar … pero, lo que sea. Solo tomó unas pocas horas de mi vida entenderlo.

Esto hará que todas las formas requeridas. Podría hacer solo el primero requerido configurando self.forms[0].empty_permitted en False .

Nuevo en Django 1.7: puede especificar este comportamiento con su formset_factory

https://docs.djangoproject.com/en/1.8/topics/forms/formsets/#validate-min

 VehicleFormSetFactory = formset_factory(VehicleForm, min_num=1, validate_min=True, extra=1) 

Bueno … esto hace que la primera forma sea requerida.

 class RequiredFormSet(BaseFormSet): def clean(self): if any(self.errors): return if not self.forms[0].has_changed(): raise forms.ValidationError('Please add at least one vehicle.') 

El único “problema” es que si hay 0 formularios, entonces el método de clean no parece ser llamado en absoluto, por lo que no sé cómo verificar si hay 0. En realidad … esto no debería suceder nunca ( excepto que mi JS tiene un error, lo que le permite eliminar todos los formularios).

Oh, creo que ya veo. Prueba esto:

 from django.forms.formsets import BaseFormSet, formset_factory class OneExtraRequiredFormSet(BaseFormSet): def initial_form_count(self): return max(super(OneExtraRequiredFormSet,self).initial_form_count() - 1,0) VehicleFormSetFactory = formset_factory(VehicleForm, formset=OneExtraRequiredFormSet, extra=1) 

== Respuesta original debajo ==

Cuando dices “al menos debes hacer un formulario requerido”, asumo que te refieres a “hacer solo un formulario adicional requerido, sin importar cuántos se hayan agregado mediante javascript”.

Deberá tener una entrada oculta en su página que contiene el número de formularios que se han agregado a través de javascript y luego usar ese número, menos 1, como el valor para pasar como el atributo extra a su constructor de conjuntos de formularios.