Showing custom model validation exceptions in the Django admin site

后端 未结 4 1270
悲&欢浪女
悲&欢浪女 2021-02-07 00:27

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

相关标签:
4条回答
  • 2021-02-07 00:27

    In django 1.2, model validation has been added.

    You can now add a "clean" method to your models which raise ValidationError exceptions, and it will be called automatically when using the django admin.

    The clean() method is called when using the django admin, but NOT called on save().

    If you need to use the clean() method outside of the admin, you will need to explicitly call clean() yourself.

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

    So your clean method could be something like this:

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

    I haven't made use of it extensively, but seems like much less code than having to create a ModelForm, and then link that form in the admin.py file for use in django admin.

    0 讨论(0)
  • 2021-02-07 00:46

    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.

    0 讨论(0)
  • 2021-02-07 00:51

    Pretty old post, but I think "use custom cleaning" is still the accepted answer. But it is not satisfactory. You can do as much pre checking as you want you still may get an exception in Model.save(), and you may want to show a message to the user in a fashion consistent with a form validation error.

    The solution I found was to override ModelAdmin.changeform_view(). In this case I'm catching an integrity error generated somewhere down in the SQL driver:

    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)
    
    0 讨论(0)
  • 2021-02-07 00:54

    The best way is put the validation one field is use the ModelForm... [ forms.py]

    class FormProduct(forms.ModelForm):
    
    class Meta:
        model = Product
    
    def clean_photo(self):
        if self.cleaned_data["photo"] is None:
            raise forms.ValidationError(u"You need set some imagem.")
    

    And set the FORM that you create in respective model admin [ admin.py ]

    class ProductAdmin(admin.ModelAdmin):
         form = FormProduct
    
    0 讨论(0)
提交回复
热议问题