Code

Ticket #8882: formset-unique.diff

File formset-unique.diff, 2.6 KB (added by Alex, 6 years ago)
Line 
1diff --git a/django/forms/models.py b/django/forms/models.py
2index 0c98f52..7cbf3ab 100644
3--- a/django/forms/models.py
4+++ b/django/forms/models.py
5@@ -377,6 +377,41 @@ class BaseModelFormSet(BaseFormSet):
6                     form.save_m2m()
7             self.save_m2m = save_m2m
8         return self.save_existing_objects(commit) + self.save_new_objects(commit)
9+   
10+    def clean(self):
11+        self.validate_unique()
12+   
13+    def validate_unique(self):
14+        from django.db.models.fields import FieldDoesNotExist
15+        unique_checks = []
16+        for name, field in self.forms[0].fields.iteritems():
17+            try:
18+                f = self.forms[0].instance._meta.get_field_by_name(name)[0]
19+            except FieldDoesNotExist:
20+                continue
21+            if f.unique:
22+                unique_checks.append((name,))
23+       
24+        bad_fields = set()
25+        for unique_check in unique_checks:
26+            if len(unique_check) == 1:
27+                field = unique_check[0]
28+                data = set()
29+                for i in xrange(self._total_form_count):
30+                    form = self.forms[i]
31+                    if hasattr(form, 'cleaned_data') and field in form.cleaned_data and form.cleaned_data[field] is not None:
32+                        if form.cleaned_data[field] in data:
33+                            bad_fields.add(unique_check)
34+                        else:
35+                            data.add(form.cleaned_data[field])
36+       
37+        if bad_fields:
38+            errors = []
39+            for field in bad_fields:
40+                errors.append(_(u"You have entered duplicate data for %(field)s, all %(field)ss should be unique" % {
41+                        'field': get_text_list(field, _(u'and'))
42+                    }))
43+            raise ValidationError(errors)
44 
45     def save_existing_objects(self, commit=True):
46         self.changed_objects = []
47diff --git a/tests/modeltests/model_formsets/models.py b/tests/modeltests/model_formsets/models.py
48index 215f35b..94d4d27 100644
49--- a/tests/modeltests/model_formsets/models.py
50+++ b/tests/modeltests/model_formsets/models.py
51@@ -727,4 +727,17 @@ True
52 >>> formset.get_queryset()
53 [<Player: Bobby>]
54 
55+# Prevent duplicates from within the same formset
56+>>> FormSet = modelformset_factory(Product, extra=2)
57+>>> data = {
58+...     'form-TOTAL_FORMS': 2,
59+...     'form-INITIAL_FORMS': 0,
60+...     'form-0-slug': 'red_car',
61+...     'form-1-slug': 'red_car',
62+... }
63+>>> formset = FormSet(data)
64+>>> formset.is_valid()
65+False
66+>>> formset._non_form_errors
67+[u'You have entered duplicate data for slug, all slugs should be unique']
68 """}