Ticket #9493: formset-unique.4.diff

File formset-unique.4.diff, 4.5 KB (added by Alex Gaynor, 15 years ago)
  • django/forms/models.py

    diff --git a/django/forms/models.py b/django/forms/models.py
    index 99f7ef5..fedbab7 100644
    a b class BaseModelFormSet(BaseFormSet):  
    377377                    form.save_m2m()
    378378            self.save_m2m = save_m2m
    379379        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        unique_together = self.forms[0].instance._meta.unique_together
     395        unique_together = [check for check in unique_together if [True for field in check if field in self.forms[0].fields]]
     396        unique_checks.extend(unique_together)
     397       
     398        errors = []
     399        for unique_check in unique_checks:
     400            data = set()
     401            for i in xrange(self._total_form_count):
     402                form = self.forms[i]
     403                if not hasattr(form, 'cleaned_data'):
     404                    continue
     405                if [True for field in unique_check if field in form.cleaned_data and form.cleaned_data[field] is not None]:
     406                    instance = tuple([form.cleaned_data[field] for field in unique_check])
     407                    if instance in data:
     408                        if len(unique_check) == 1:
     409                            errors.append(_("You have entered duplicate data for %(field)s, all %(field)ss should be unique.") % {
     410                                    'field': unique_check[0],
     411                                })
     412                        else:
     413                            errors.append(_("You have entered duplicate data for %(field)s, %(field)s should be unique together.") % {
     414                                    'field': get_text_list(unique_check, _("and")),
     415                                })
     416                        break
     417                    else:
     418                        data.add(instance)
     419       
     420        if errors:
     421            raise ValidationError(errors)
    380422
    381423    def save_existing_objects(self, commit=True):
    382424        self.changed_objects = []
  • docs/topics/forms/modelforms.txt

    diff --git a/docs/topics/forms/modelforms.txt b/docs/topics/forms/modelforms.txt
    index ad3fe02..f2875ff 100644
    a b in a view. The only difference is that we call ``formset.save()`` to save the  
    538538data into the database. This is described above in
    539539:ref:`saving-objects-in-the-formset`.
    540540
     541Overiding ``clean()`` on a ``model_formset``
     542--------------------------------------------
     543
     544Just like with ``ModelForms``, by default the ``clean()`` method of a
     545``model_formset`` will validate that none of the items in the formset validate
     546the unique constraints on your model(either unique or unique_together).  If you
     547want to overide the ``clean()`` method on a ``model_formset`` and maintain this
     548validation, you must call the parent classes ``clean`` method.
     549
     550
    541551Using ``inlineformset_factory``
    542552-------------------------------
    543553
  • tests/modeltests/model_formsets/models.py

    diff --git a/tests/modeltests/model_formsets/models.py b/tests/modeltests/model_formsets/models.py
    index 8e28e6f..57ecf7d 100644
    a b True  
    792792>>> formset.get_queryset()
    793793[<Player: Bobby>]
    794794
     795# Prevent duplicates from within the same formset
     796>>> FormSet = modelformset_factory(Product, extra=2)
     797>>> data = {
     798...     'form-TOTAL_FORMS': 2,
     799...     'form-INITIAL_FORMS': 0,
     800...     'form-0-slug': 'red_car',
     801...     'form-1-slug': 'red_car',
     802... }
     803>>> formset = FormSet(data)
     804>>> formset.is_valid()
     805False
     806>>> formset._non_form_errors
     807[u'You have entered duplicate data for slug, all slugs should be unique.']
     808
     809>>> FormSet = modelformset_factory(Price, extra=2)
     810>>> data = {
     811...     'form-TOTAL_FORMS': 2,
     812...     'form-INITIAL_FORMS': 0,
     813...     'form-0-price': '25',
     814...     'form-0-quantity': '7',
     815...     'form-1-price': '25',
     816...     'form-1-quantity': '7',
     817... }
     818>>> formset = FormSet(data)
     819>>> formset.is_valid()
     820False
     821>>> formset._non_form_errors
     822[u'You have entered duplicate data for price and quantity, price and quantity should be unique together.']
    795823"""}
Back to Top