2010-02-01 19 views
14

Tengo un modelo de reserva que debe verificar si el artículo que se está reservando está disponible. Me gustaría tener la lógica detrás de averiguar si el artículo está disponible centralizado, de modo que no importa dónde guarde la instancia, este código valida que se pueda guardar.Mostrando excepciones de validación de modelo personalizado en el sitio de administración de Django

En el momento en que tienen este código en una costumbre función de ahorro de mi clase del 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 eleva si el artículo no está disponible, y mi artículo no se guarda. Puedo capturar la excepción de mi código de formulario de inicio, pero ¿qué pasa con el sitio de administración de Django? ¿Cómo puedo hacer que mi excepción se muestre como cualquier otro error de validación en el sitio de administración?

Respuesta

9

Aquí tienes: http://docs.djangoproject.com/en/dev/ref/contrib/admin/#adding-custom-validation-to-the-admin Sin embargo, esto podría ser ortogonal al camino que has tomado. Esto no debería ser un error de validación, que se levanta, porque estos se plantean por formas. De todos modos, eche un vistazo y elija la forma que desee.

+1

supongo que quería escribir, en un solo lugar, algo que se aseguró de que una instancia no se pudo guardar que rompió mis reglas de validación - dado que se llama a la función de guardar, no importa dónde haga su guardado (administrador o front-end), tiene sentido ponerlo allí. –

+0

Sí, pero ValidationError se usa para informar al usuario final que la información que está ingresando en un formulario es incorrecta. Si debe asegurarse de que se mantienen algunas reglas, ¿quizás debería usar una afirmación? O bien, si guardar puede simplemente fallar, entonces quizás debería tener un código de retorno, ya sea que se haya guardado correctamente. No sé, qué es exactamente lo que necesitas. – gruszczy

+0

Ese enlace no le responde en absoluto. Él quiere reutilizar la validación en su modelo en administración. No volver a aplicar la validación en el administrador ... – Cerin

2

También traté de resolver esto y existe mi solución; en mi caso, necesitaba denegar cualquier cambio en related_objects si el main_object está bloqueado para su edición.

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 la costumbre de guardar método- todos mis modelos related_data 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) Metaform - todos mis formas de administración se related_data basarse en esto (se asegurará de que la interfaz de administrador informará al usuario sin un 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 sobrecarga y sigue siendo bastante sencillo y fácil de mantener.

17

En django 1.2, se ha agregado la validación del modelo.

Ahora puede agregar un método "limpio" a los modelos que generan excepciones ValidationError, y se llamará automáticamente cuando se use el administrador django.

(No es muy claro en la documentación que el método de limpieza es llamado por el administrador, pero he verificado aquí)

http://docs.djangoproject.com/en/dev/ref/models/instances/?from=olddocs#validating-objects

Así que su método de limpieza 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 he hecho uso de ella ampliamente, pero que parece ser mucho menos código que tener que crear una ModelForm y, a continuación, vincular esa forma en el archivo admin.py para su uso en administración de Django.

+1

¿Qué pasa si 'save()' todavía genera una excepción? – spinkus

+0

¡Esto es lo que estaba buscando durante las últimas 3 horas! ¡Gracias! – kchomski

2

Bonita publicación anterior, pero creo que "usar limpieza personalizada" sigue siendo la respuesta aceptada. Pero no es satisfactorio. Puede hacer tantas comprobaciones previas como desee, pero aún así puede obtener una excepción en Model.save(), y puede desea mostrar un mensaje al usuario de manera coherente con un error de validación de formulario.

La solución que encontré fue anular ModelAdmin.changeform_view().En este caso, yo estoy poniendo un error de integridad generada en algún lugar en el controlador de SQL:

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) 
+0

Para hacerlo funcionar, debe importar: 'from django.contrib import messages' y' from django.http import HttpResponseRedirect'. –

Cuestiones relacionadas