respuesta de Daniel es excelente y que trabajó para mí en un proyecto, pero luego me di cuenta debido a la forma de Django forma de trabajo, si está utilizando can_delete y marca la casilla de borrado mientras que el ahorro, es posible validar w/o cualquier orden (en este caso).
Pasé un tiempo tratando de encontrar la manera de evitar que eso ocurra. La primera situación fue fácil: no incluya los formularios que se eliminarán en el recuento. La segunda situación fue más complicada ... si todos se marcan los cuadros de eliminación, entonces no se llamó a clean
.
El código no es exactamente sencillo, desafortunadamente. El método clean
se llama desde full_clean
al que se llama cuando se accede a la propiedad error
. No se tiene acceso a esta propiedad cuando se elimina un subformulario, por lo que nunca se llama al full_clean
. No soy un experto en Django, así que esta podría ser una manera terrible de hacerlo, pero parece funcionar.
Aquí está la clase de modificación:
class InvoiceOrderInlineFormset(forms.models.BaseInlineFormSet):
def is_valid(self):
return super(InvoiceOrderInlineFormset, self).is_valid() and \
not any([bool(e) for e in self.errors])
def clean(self):
# get forms that actually have valid data
count = 0
for form in self.forms:
try:
if form.cleaned_data and not form.cleaned_data.get('DELETE', False):
count += 1
except AttributeError:
# annoyingly, if a subform is invalid Django explicity raises
# an AttributeError for cleaned_data
pass
if count < 1:
raise forms.ValidationError('You must have at least one order')
La solución perfecta, gracias – user108791
He descubierto que si la caja de borrado está marcada, es posible validar con 0 órdenes. Vea mi respuesta para una clase revisada que resuelve ese problema. –
Muchas gracias por este parche (y Dan por la mejora). Como una posible pista para otros, he hecho una 'clase MandatoryInlineFormSet (BaseInlineFormSet)' y luego de esto obtuve InvoiceAdminFormSet. En mi InvoiceAdminFormSet tengo un método clean() que realiza la validación personalizada, pero las primeras devuelven llamadas a MandatoryInlineFromSet.clean(). – Kurt