Ticket #9493: formset-unique.6.diff
File formset-unique.6.diff, 5.1 KB (added by , 16 years ago) |
---|
-
django/forms/models.py
diff --git a/django/forms/models.py b/django/forms/models.py index 01bd912..cee9fd7 100644
a b class BaseModelFormSet(BaseFormSet): 395 395 form.save_m2m() 396 396 self.save_m2m = save_m2m 397 397 return self.save_existing_objects(commit) + self.save_new_objects(commit) 398 399 def clean(self): 400 self.validate_unique() 401 402 def validate_unique(self): 403 from django.db.models.fields import FieldDoesNotExist, Field as ModelField 404 unique_checks = [] 405 for name, field in self.forms[0].fields.iteritems(): 406 try: 407 f = self.forms[0].instance._meta.get_field_by_name(name)[0] 408 except FieldDoesNotExist: 409 continue 410 if not isinstance(f, ModelField): 411 continue 412 if f.unique: 413 unique_checks.append((name,)) 414 unique_together = self.forms[0].instance._meta.unique_together 415 unique_together = [check for check in unique_together if [True for field in check if field in self.forms[0].fields]] 416 unique_checks.extend(unique_together) 417 418 errors = [] 419 for unique_check in unique_checks: 420 data = set() 421 for form in self.forms: 422 if not hasattr(form, 'cleaned_data'): 423 continue 424 if [True for field in unique_check if field in form.cleaned_data and form.cleaned_data[field] is not None]: 425 instance = tuple([form.cleaned_data[field] for field in unique_check]) 426 if instance in data: 427 errors.append(self.get_unique_error_message(unique_check)) 428 break 429 else: 430 data.add(instance) 431 432 if errors: 433 raise ValidationError(errors) 434 435 def get_unique_error_message(self, unique_check): 436 if len(unique_check) == 1: 437 return _("You have entered duplicate data for %(field)s, all %(field)ss should be unique.") % { 438 'field': unique_check[0], 439 } 440 else: 441 return _("You have entered duplicate data for %(field)s, %(field)s should be unique together.") % { 442 'field': get_text_list(unique_check, _("and")), 443 } 398 444 399 445 def save_existing_objects(self, commit=True): 400 446 self.changed_objects = [] … … class BaseInlineFormSet(BaseModelFormSet): 505 551 form.fields[self._pk_field.name] = InlineForeignKeyField(self.instance, pk_field=True) 506 552 else: 507 553 form.fields[self.fk.name] = InlineForeignKeyField(self.instance, label=form.fields[self.fk.name].label) 554 555 def get_unique_error_message(self, unique_check): 556 unique_check = [field for field in unique_check if field != self.fk.name] 557 return super(BaseInlineFormSet, self).get_unique_error_message(unique_check) 508 558 509 559 def _get_foreign_key(parent_model, model, fk_name=None): 510 560 """ -
docs/topics/forms/modelforms.txt
diff --git a/docs/topics/forms/modelforms.txt b/docs/topics/forms/modelforms.txt index 50beea2..3767d29 100644
a b than that of a "normal" formset. The only difference is that we call 539 539 ``formset.save()`` to save the data into the database. (This was described 540 540 above, in :ref:`saving-objects-in-the-formset`.) 541 541 542 543 Overiding ``clean()`` on a ``model_formset`` 544 -------------------------------------------- 545 546 Just like with ``ModelForms``, by default the ``clean()`` method of a 547 ``model_formset`` will validate that none of the items in the formset validate 548 the unique constraints on your model(either unique or unique_together). If you 549 want to overide the ``clean()`` method on a ``model_formset`` and maintain this 550 validation, you must call the parent classes ``clean`` method. 551 552 542 553 Using a custom queryset 543 554 ~~~~~~~~~~~~~~~~~~~~~~~ 544 555 -
tests/modeltests/model_formsets/models.py
diff --git a/tests/modeltests/model_formsets/models.py b/tests/modeltests/model_formsets/models.py index f11d453..b355ae8 100644
a b True 828 828 >>> formset.get_queryset() 829 829 [<Player: Bobby>] 830 830 831 # Prevent duplicates from within the same formset 832 >>> FormSet = modelformset_factory(Product, extra=2) 833 >>> data = { 834 ... 'form-TOTAL_FORMS': 2, 835 ... 'form-INITIAL_FORMS': 0, 836 ... 'form-0-slug': 'red_car', 837 ... 'form-1-slug': 'red_car', 838 ... } 839 >>> formset = FormSet(data) 840 >>> formset.is_valid() 841 False 842 >>> formset._non_form_errors 843 [u'You have entered duplicate data for slug, all slugs should be unique.'] 844 845 >>> FormSet = modelformset_factory(Price, extra=2) 846 >>> data = { 847 ... 'form-TOTAL_FORMS': 2, 848 ... 'form-INITIAL_FORMS': 0, 849 ... 'form-0-price': '25', 850 ... 'form-0-quantity': '7', 851 ... 'form-1-price': '25', 852 ... 'form-1-quantity': '7', 853 ... } 854 >>> formset = FormSet(data) 855 >>> formset.is_valid() 856 False 857 >>> formset._non_form_errors 858 [u'You have entered duplicate data for price and quantity, price and quantity should be unique together.'] 831 859 """}