diff --git a/django/forms/models.py b/django/forms/models.py
index 0c98f52..7cbf3ab 100644
a
|
b
|
class BaseModelFormSet(BaseFormSet):
|
377 | 377 | form.save_m2m() |
378 | 378 | self.save_m2m = save_m2m |
379 | 379 | return self.save_existing_objects(commit) + self.save_new_objects(commit) |
| 380 | |
| 381 | def clean(self): |
| 382 | self.validate_unique() |
| 383 | |
| 384 | def validate_unique(self): |
| 385 | from django.db.models.fields import FieldDoesNotExist |
| 386 | unique_checks = [] |
| 387 | for name, field in self.forms[0].fields.iteritems(): |
| 388 | try: |
| 389 | f = self.forms[0].instance._meta.get_field_by_name(name)[0] |
| 390 | except FieldDoesNotExist: |
| 391 | continue |
| 392 | if f.unique: |
| 393 | unique_checks.append((name,)) |
| 394 | |
| 395 | bad_fields = set() |
| 396 | for unique_check in unique_checks: |
| 397 | if len(unique_check) == 1: |
| 398 | field = unique_check[0] |
| 399 | data = set() |
| 400 | for i in xrange(self._total_form_count): |
| 401 | form = self.forms[i] |
| 402 | if hasattr(form, 'cleaned_data') and field in form.cleaned_data and form.cleaned_data[field] is not None: |
| 403 | if form.cleaned_data[field] in data: |
| 404 | bad_fields.add(unique_check) |
| 405 | else: |
| 406 | data.add(form.cleaned_data[field]) |
| 407 | |
| 408 | if bad_fields: |
| 409 | errors = [] |
| 410 | for field in bad_fields: |
| 411 | errors.append(_(u"You have entered duplicate data for %(field)s, all %(field)ss should be unique" % { |
| 412 | 'field': get_text_list(field, _(u'and')) |
| 413 | })) |
| 414 | raise ValidationError(errors) |
380 | 415 | |
381 | 416 | def save_existing_objects(self, commit=True): |
382 | 417 | self.changed_objects = [] |
diff --git a/tests/modeltests/model_formsets/models.py b/tests/modeltests/model_formsets/models.py
index 215f35b..94d4d27 100644
a
|
b
|
True
|
727 | 727 | >>> formset.get_queryset() |
728 | 728 | [<Player: Bobby>] |
729 | 729 | |
| 730 | # Prevent duplicates from within the same formset |
| 731 | >>> FormSet = modelformset_factory(Product, extra=2) |
| 732 | >>> data = { |
| 733 | ... 'form-TOTAL_FORMS': 2, |
| 734 | ... 'form-INITIAL_FORMS': 0, |
| 735 | ... 'form-0-slug': 'red_car', |
| 736 | ... 'form-1-slug': 'red_car', |
| 737 | ... } |
| 738 | >>> formset = FormSet(data) |
| 739 | >>> formset.is_valid() |
| 740 | False |
| 741 | >>> formset._non_form_errors |
| 742 | [u'You have entered duplicate data for slug, all slugs should be unique'] |
730 | 743 | """} |