2010-02-01 3 views
14

J'ai un modèle de réservation qui doit vérifier si l'élément réservé est disponible. Je voudrais avoir la logique derrière déterminer si l'article est disponible centralisé de sorte que peu importe où je sauve l'instance ce code valide qu'il peut être sauvé.Affichage d'exceptions de validation de modèle personnalisé dans le site d'administration Django

Au moment où j'ai ce code dans une mesure de sauvegarde en fonction de ma classe de modèle:

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') 

Cela fonctionne très bien - l'erreur est élevée si l'article est disponible, et mon article ne sont pas enregistrées. Je peux capturer l'exception de mon code de formulaire frontal, mais qu'en est-il du site d'administration Django? Comment puis-je faire en sorte que mon exception s'affiche comme toute autre erreur de validation sur le site d'administration?

Répondre

9

C'est parti: http://docs.djangoproject.com/en/dev/ref/contrib/admin/#adding-custom-validation-to-the-admin Cependant, cela pourrait être orthogonal au chemin que vous avez pris. Cela ne devrait pas être une erreur de validation, que vous soulevez, car ceux-ci sont élevés par des formulaires. Quoi qu'il en soit, jetez un coup d'oeil et choisissez la façon dont vous aimez.

+1

Je suppose que je voulais écrire, en un seul endroit, ce qui a assuré qu'une instance ne pouvait pas être sauvé qui a brisé mes règles de validation - puisque la fonction de sauvegarde est appelée peu importe où vous faites votre sauvegarde (admin ou front end), il est logique de le mettre là. –

+0

Oui, mais ValidationError est utilisé pour informer l'utilisateur final que les informations qu'il met dans un formulaire sont erronées. Si vous devez assurer, que certaines règles sont conservées, peut-être que vous devriez utiliser un assert? Ou, si sauver peut simplement échouer, que peut-être vous devriez simplement avoir un code de retour, si elle a été enregistrée correctement. Je ne sais pas, exactement de quoi tu as besoin. – gruszczy

+0

Ce lien ne lui répond pas du tout. Il veut réutiliser la validation dans son modèle en admin. Ne pas réimplémenter la validation dans l'admin ... – Cerin

2

J'ai également essayé de résoudre ceci et il y a ma solution - dans mon cas j'ai dû nier tout changement dans related_objects si l'objet main_object est verrouillé pour l'édition.

1) sur commande Exception

class Error(Exception): 
    """Base class for errors in this module.""" 
    pass 

class EditNotAllowedError(Error): 
    def __init__(self, msg): 
     Exception.__init__(self, msg) 

2) métaclasse avec enregistrement personnalisé méthodolo- tous mes modèles related_data seront basés sur ce point:

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 - toutes mes formes related_data d'admin être basé sur ceci (il s'assurera que l'interface d'admin informera l'utilisateur sans erreur d'interface d'admin):

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 

Pour moi, ce n'est pas tellement frais et encore assez simple et maintenable.

17

Dans django 1.2, la validation du modèle a été ajoutée.

Vous pouvez désormais ajouter une méthode "propre" à vos modèles qui déclenchera des exceptions ValidationError, et elle sera appelée automatiquement lors de l'utilisation de l'administrateur django.

(Il est pas très clair dans la documentation que la méthode propre est appelé par l'administrateur, mais je l'ai vérifié ici)

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

donc votre méthode propre pourrait être quelque chose comme ceci:

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') 

Je ne l'ai pas fait usage largement, mais il semble que beaucoup moins de code que d'avoir à créer un ModelForm, puis lier cette forme dans le fichier admin.py pour une utilisation dans django admin.

+1

Que faire si 'save()' soulève toujours une exception? – spinkus

+0

C'est ce que je cherchais depuis 3 heures! THX! – kchomski

2

Assez vieux poste, mais je pense que "utiliser un nettoyage personnalisé" est toujours la réponse acceptée. Mais ce n'est pas satisfaisant. Vous pouvez faire autant de pré-vérification que vous le souhaitez, vous pouvez toujours obtenir une exception dans Model.save(), et vous peut souhaitez afficher un message à l'utilisateur d'une manière compatible avec une erreur de validation de formulaire.

La solution que j'ai trouvée consistait à remplacer ModelAdmin.changeform_view().Dans ce cas, je suis attrapant une erreur d'intégrité généré quelque part dans le pilote 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

Pour le faire fonctionner, vous devez importer: 'from django.contrib import messages' et' from django.http import HttpResponseRedirect'. –

Questions connexes