views:

199

answers:

2

I have a booking model that needs to check if the item being booked out is available. I would like to have the logic behind figuring out if the item is available centralised so that no matter where I save the instance this code validates that it can be saved.

At the moment I have this code in a custom save function of my model class:

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

This works fine - the error is raised if the item is unavailable, and my item is not saved. I can capture the exception from my front end form code, but what about the Django admin site? How can I get my exception to be displayed like any other validation error in the admin site?

+4  A: 

Here you go: http://docs.djangoproject.com/en/dev/ref/contrib/admin/#adding-custom-validation-to-the-admin This however, might be orthogonal to the way, you have taken. This shouldn't be validation error, that you rise, because these are raised by forms. Anyway, take a look and choose the way you like.

gruszczy
I guess I wanted to write, in one place, something that ensured that an instance could not be saved that broke my validation rules - since the save function is called no matter where you do your saving (admin or front end) it made sense to put it there.
Guy Bowden
Yes, but ValidationError are used to inform the end user, that the information he is putting into a form is wrong. If you must assure, that some rules are kept, maybe you should use an assert? Or, if save can simply fail, than maybe you should simple have a return code, whether it was saved properly. I don't know, what exactly you need.
gruszczy
+1  A: 

I've also tried to solve this and there is my solution- in my case i needed to deny any changes in related_objects if the main_object is locked for editing.

1) custom Exception

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

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

2) metaclass with custom save method- all my related_data models will be based on this:

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 - all my related_data admin forms will be based on this (it will ensure that admin interface will inform user without admin interface error):

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

To my mind it is not so much overhead and still pretty straightforward and maintainable.

jki