Login

unique validation for ModelForm

Author:
whiskybar
Posted:
March 19, 2008
Language:
Python
Version:
.96
Tags:
newforms
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

Comments

visik7 (on May 30, 2008):
<p>line 30 self.name doesn't handle i18n dunno why</p>

#

visik7 (on June 3, 2008):
<p>from django import newforms as forms</p> <p>class CleanUniqueField: """Wrap the clean_XXX method."""</p> <pre>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. </pre> <p>class ModelForm(forms.ModelForm): """A hack around the Django ticket #4895."""</p> <pre>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)) </pre>

#

visik7 (on June 3, 2008):
<p>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</p>

#

whiskybar (on June 4, 2008):
<p>Thanks visik7, this is a valid point indeed. Is verbose_name unicode safe? I am confused a little because you put a #FIXME there.</p> <p>How about</p> <pre>... u'The %s is already in use.' % smart_unicode(self.verbose_name)) ... </pre> <p>Will it solve the issue? Visik7 do you have a way of testing it?</p>

#

Please login first before commenting.