Login

unique validation for ModelForm

Author:
whiskybar
Posted:
March 19, 2008
Language:
Python
Version:
.96
Score:
2 (after 2 ratings)

Inherit your forms from model from this ModelForm and it will check all the database fields with unique=True in is_valid().

This is a hack around #5736. It is actually a part of a grand problem mentioned in #4895. You can use this hack until the issue is fully resolved.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
from django import newforms as forms

class CleanUniqueField:
    """Wrap the clean_XXX method."""

    def __init__(self, form, name):
        try:
            self.clean = getattr(form, 'clean_' + name)
        except AttributeError:
            self.clean = None

        self.form = form
        self.name = name

    def __call__(self):
        if self.clean:
            result = self.clean()
        else:
            result = self.form.cleaned_data[self.name]

        queryset = self.form._meta.model.objects
        if self.form.instance.pk:
            queryset = queryset.exclude(pk=self.form.instance.pk)

        try:
            queryset.get(**{self.name: result})
        except self.form._meta.model.DoesNotExist:
            return result
        else:
            raise forms.ValidationError(
                u'The %s is already in use.' % self.name)

class ModelForm(forms.ModelForm):
    """A hack around the Django ticket #4895."""

    def __init__(self, *args, **kwargs):
        super(ModelForm, self).__init__(*args, **kwargs)

        for field in self._meta.model._meta.fields:
            if field.unique and field.name in self.base_fields:
                setattr(self,
                    'clean_' + field.name,
                    CleanUniqueField(self, field.name))

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 9 months, 3 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 4 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 5 months ago
  5. Help text hyperlinks by sa2812 1 year, 6 months ago

Comments

visik7 (on May 30, 2008):

line 30 self.name doesn't handle i18n dunno why

#

visik7 (on June 3, 2008):

from django import newforms as forms

class CleanUniqueField: """Wrap the clean_XXX method."""

def __init__(self, form, name, verbose_name):
    try:
        self.clean = getattr(form, 'clean_' + name)
    except AttributeError:
        self.clean = None

    self.form = form
    self.name = name
    self.verbose_name = verbose_name

def __call__(self):
    if self.clean:
        result = self.clean()
    else:
        result = self.form.cleaned_data[self.name]

    queryset = self.form._meta.model.objects
    if self.form.instance.pk:
        queryset = queryset.exclude(pk=self.form.instance.pk)

    try:
        queryset.get(**{self.name: result})
    except self.form._meta.model.DoesNotExist:
        return result
    else:
        raise forms.ValidationError(
            u'The %s is already in use.' % self.verbose_name)
        #FIXME: the string is not not i18n compliant but the field name it is.

class ModelForm(forms.ModelForm): """A hack around the Django ticket #4895."""

def __init__(self, *args, **kwargs):
    super(ModelForm, self).__init__(*args, **kwargs)

    for field in self._meta.model._meta.fields:
        if field.unique and field.name in self.base_fields:
            setattr(self,
                'clean_' + field.name,
                CleanUniqueField(self, field.name, field.verbose_name))

#

visik7 (on June 3, 2008):

I've not commented what the code above is the verbose_name is introduced because self.name isn't the real name to display in the error message

#

whiskybar (on June 4, 2008):

Thanks visik7, this is a valid point indeed. Is verbose_name unicode safe? I am confused a little because you put a #FIXME there.

How about

...
u'The %s is already in use.' % smart_unicode(self.verbose_name))
...

Will it solve the issue? Visik7 do you have a way of testing it?

#

Please login first before commenting.