tutorial - python django documentation
Mostrar excepciones de validaciĆ³n de modelo personalizadas en el sitio de administraciĆ³n de Django (4)
Tengo un modelo de reserva que necesita verificar si el artículo que se está reservando está disponible. Me gustaría tener la lógica detrás de averiguar si el elemento está disponible centralizado para que no importa dónde guarde la instancia, este código valida que se puede guardar.
En este momento tengo este código en una función de guardado personalizada de mi clase de modelo:
def save(self):
if self.is_available(): # my custom check availability function
super(MyObj, self).save()
else:
# this is the bit I''m stuck with..
raise forms.ValidationError(''Item already booked for those dates'')
Esto funciona bien: el error se genera si el elemento no está disponible y mi elemento no se guarda. Puedo capturar la excepción de mi código de formulario de front-end, pero ¿qué pasa con el sitio de administración de Django? ¿Cómo puedo hacer que se muestre mi excepción como cualquier otro error de validación en el sitio de administración?
Aquí tiene: http://docs.djangoproject.com/en/dev/ref/contrib/admin/#adding-custom-validation-to-the-admin Esto, sin embargo, puede ser ortogonal a la forma que ha tomado. Esto no debería ser un error de validación, que se eleva, porque estos son levantados por formularios. De todos modos, échale un vistazo y elige la forma que más te guste.
Bastante viejo post, pero creo que "usar limpieza personalizada" sigue siendo la respuesta aceptada. Pero no es satisfactorio. Puede realizar la comprobación previa que desee, pero aún así puede obtener una excepción en Model.save()
, y es posible que desee mostrar un mensaje al usuario de una manera consistente con un error de validación de formulario.
La solución que encontré fue anular ModelAdmin.changeform_view() . En este caso, estoy detectando un error de integridad generado en algún lugar del controlador SQL:
from django.contrib import messages
from django.http import HttpResponseRedirect
def changeform_view(self, request, object_id=None, form_url='''', extra_context=None):
try:
return super(MyModelAdmin, self).changeform_view(request, object_id, form_url, extra_context)
except IntegrityError as e:
self.message_user(request, e, level=messages.ERROR)
return HttpResponseRedirect(form_url)
En django 1.2, se ha agregado la validación del modelo.
Ahora puede agregar un método "limpio" a sus modelos que generan excepciones de ValidationError, y se llamará automáticamente cuando use el administrador de django.
(No queda muy claro en la documentación que el administrador llame al método de limpieza, pero lo he verificado aquí)
http://docs.djangoproject.com/en/dev/ref/models/instances/?from=olddocs#validating-objects
Entonces tu método limpio podría ser algo como esto:
from django.core.exceptions import ValidationError
class MyModel(models.Model):
def is_available(self):
#do check here
return result
def clean(self):
if not self.is_available():
raise ValidationError(''Item already booked for those dates'')
No lo he usado extensivamente, pero parece mucho menos código que tener que crear un ModelForm, y luego vincular ese formulario en el archivo admin.py para usarlo en django admin.
También he intentado resolver esto y está mi solución, en mi caso, necesitaba rechazar cualquier cambio en los objetos relacionados si el objeto principal está bloqueado para editar.
1) Excepción personalizada
class Error(Exception):
"""Base class for errors in this module."""
pass
class EditNotAllowedError(Error):
def __init__(self, msg):
Exception.__init__(self, msg)
2) metaclase con método de guardado personalizado, todos mis modelos de datos relacionados se basarán en esto:
class RelatedModel(models.Model):
main_object = models.ForeignKey("Main")
class Meta:
abstract = True
def save(self, *args, **kwargs):
if self.main_object.is_editable():
super(RelatedModel, self).save(*args, **kwargs)
else:
raise EditNotAllowedError, "Closed for editing"
3) metaforma: todos mis formularios de administración de datos relacionados se basarán en esto (asegurará que la interfaz de administración informará al usuario sin error de interfaz de administración):
from django.forms import ModelForm, ValidationError
...
class RelatedModelForm(ModelForm):
def clean(self):
cleaned_data = self.cleaned_data
if not cleaned_data.get("main_object")
raise ValidationError("Closed for editing")
super(RelatedModelForm, self).clean() # important- let admin do its work on data!
return cleaned_data
En mi opinión, no es tanto una sobrecarga y sigue siendo bastante sencillo y fácil de mantener.