简体   繁体   中英

Django model validation in admin

Similar to clean() method in model and field validation and Django: Validation error in Admin (although this one is old enough that it was answered before model validation existed)

I'm trying to use model validation in order to keep my code DRY, but I keep running into an odd error. My model looks like so:

from django.db import models
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext as _

class Period(models.Model):
    class Meta:
        app_label = 'nps'

    name = models.CharField(max_length=40)
    start = models.DateField()
    end = models.DateField()

    def clean(self):
        if self.start > self.end:
            raise ValidationError(
                _("Start date must be before end date"),
                code='invalid',
            )
        super(Period, self).clean()

    def validate_unique(self, exclude=None):
        conflicts = Period.objects.filter(
            start__lte=self.end,
            end__gte=self.start,
        )
        if any(conflicts):
            raise ValidationError(
                _("Periods may not overlap."),
                code='invalid',
            )
        super(Period, self).validate_unique(exclude)

    def __unicode__(self):
        return "%s (%s - %s)" % (self.name, self.start.strftime('%m/%d/%Y') or None, self.end.strftime('%m/%d/%Y') or None)

When I try to save a model that's invalid (ie has a start date after the end date), instead of seeing a validation error on the admin page, I get the following exception:

AttributeError at /admin/nps/period/add/
'ValidationError' object has no attribute 'error_dict'
Request Method: POST
Request URL:    http://localhost:8000/admin/nps/period/add/
Django Version: 1.6.2
Exception Type: AttributeError
Exception Value:    
'ValidationError' object has no attribute 'error_dict'
Exception Location: /opt/django_venv/local/lib/python2.7/site-packages/django/forms/models.py in _update_errors, line 327
Python Executable:  /opt/django_venv/bin/python
Python Version: 2.7.3
Python Path:    
['/opt/webapp',
 '/home/vagrant/.pycharm_helpers/pydev',
 '/opt/webapp',
 '/vagrant',
 '/opt/webapp/C',
 '/Program Files (x86)/JetBrains/PyCharm 3.1.1/plugins/sass/lib/stubs/sass_functions.scss',
 '/Python27',
 '/opt/django_venv/lib/python2.7',
 '/opt/django_venv/lib/python2.7/plat-linux2',
 '/opt/django_venv/lib/python2.7/lib-tk',
 '/opt/django_venv/lib/python2.7/lib-old',
 '/opt/django_venv/lib/python2.7/lib-dynload',
 '/usr/lib/python2.7',
 '/usr/lib/python2.7/plat-linux2',
 '/usr/lib/python2.7/lib-tk',
 '/opt/django_venv/local/lib/python2.7/site-packages',
 '/opt/webapp/webapp']
Server time:    Tue, 8 Apr 2014 16:29:24 -0400

It seems like the admin template is expecting something other than a ValidationError to be raised. Am I doing something wrong or is this a bug in Django? The full stacktrace can be found here: https://gist.github.com/DBell-Feins/10170544

Thanks!

I had this same issue, and found a solution after some trial and error. I added the following in the full_clean method, but it should work elsewhere.

from django.core.exceptions import ValidationError
from django.core.exceptions import NON_FIELD_ERRORS

class User(models.Model):
    # ...
    def full_clean(self, *args, **kwargs):
        self.update_username_slug()

        if User.objects.filter(username_slug=self.username_slug).exclude(id=self.id).exists():
            raise ValidationError({
                'username': [
                    ValidationError(
                        message='Username already exists',
                        code='unique',
                        params={},
                    )
                ]
            })
        super(User, self).full_clean(*args, **kwargs)

So in your case, you might want to have something like this.

class Period(models.Model):
    # ...
    def clean(self):
        if self.start > self.end:
            raise ValidationError({
                'start': [
                    ValidationError(
                        message=_("Start date must be before end date"),
                        code='invalid',
                        params={},
                    )
                ]
            })
        super(Period, self).clean()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM