Django

Code

Ticket #9493: formset-unique.4.diff

File formset-unique.4.diff, 4.5 kB (added by Alex, 1 year ago)
  • a/django/forms/models.py

    old new  
    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 = [] 
  • a/docs/topics/forms/modelforms.txt

    old new  
    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 
  • a/tests/modeltests/model_formsets/models.py

    old new  
    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"""}