Ticket #18912: 0001-Made-ModelForm-correctly-handle-unique-checks-for-pa.2.patch

File 0001-Made-ModelForm-correctly-handle-unique-checks-for-pa.2.patch, 6.5 KB (added by Sebastian Noack, 12 years ago)
  • django/forms/models.py

    From 7f79fae7c686cbaf4b0f6d22feb29445af206677 Mon Sep 17 00:00:00 2001
    From: Sebastian Noack <s.noack@placement24.com>
    Date: Thu, 6 Sep 2012 10:47:52 +0200
    Subject: [PATCH] Made ModelForm correctly handle unique checks for parent
     models.
    
    See http://code.djangoproject.com/ticket/18912
    ---
     django/forms/models.py |   39 ++++++++++++++++++++++-----------------
     1 file changed, 22 insertions(+), 17 deletions(-)
    
    diff --git a/django/forms/models.py b/django/forms/models.py
    index cc43612..392e062 100644
    a b class BaseModelForm(BaseForm):  
    227227                                            error_class, label_suffix, empty_permitted)
    228228
    229229    def clean(self):
    230         self.validate_unique()
     230        self.validate_unique(self.instance.__class__)
    231231        return self.cleaned_data
    232232
    233     def validate_unique(self):
    234         unique_checks, date_checks = self._get_unique_checks()
     233    def validate_unique(self, model):
     234        unique_checks, date_checks = self._get_unique_checks(model)
    235235        form_errors = []
    236236        bad_fields = set()
    237237
    238         field_errors, global_errors = self._perform_unique_checks(unique_checks)
     238        field_errors, global_errors = self._perform_unique_checks(model, unique_checks)
    239239        bad_fields.union(field_errors)
    240240        form_errors.extend(global_errors)
    241241
    242         field_errors, global_errors = self._perform_date_checks(date_checks)
     242        field_errors, global_errors = self._perform_date_checks(model, date_checks)
    243243        bad_fields.union(field_errors)
    244244        form_errors.extend(global_errors)
    245245
    class BaseModelForm(BaseForm):  
    250250            # form-wide.
    251251            raise ValidationError(form_errors)
    252252
    253     def _get_unique_checks(self):
     253        for parent_model in model._meta.parents:
     254            self.validate_unique(parent_model)
     255
     256    def _get_unique_checks(self, model):
    254257        from django.db.models.fields import FieldDoesNotExist, Field as ModelField
    255258
    256259        # Gather a list of checks to perform. We only perform unique checks
    class BaseModelForm(BaseForm):  
    262265        unique_checks = []
    263266        # these are checks for the unique_for_<date/year/month>
    264267        date_checks = []
    265         for check in self.instance._meta.unique_together[:]:
     268        for check in model._meta.unique_together[:]:
    266269            fields_on_form = [field for field in check if self.cleaned_data.get(field) is not None]
    267270            if len(fields_on_form) == len(check):
    268271                unique_checks.append(check)
    class BaseModelForm(BaseForm):  
    271274        # the list of checks. Again, skip empty fields and any that did not validate.
    272275        for name in self.fields:
    273276            try:
    274                 f = self.instance._meta.get_field_by_name(name)[0]
     277                f, parent_model, _, _ = model._meta.get_field_by_name(name)
    275278            except FieldDoesNotExist:
    276279                # This is an extra field that's not on the ModelForm, ignore it
    277280                continue
    class BaseModelForm(BaseForm):  
    281284                # get_field_by_name found it, but it is not a Field so do not proceed
    282285                # to use it as if it were.
    283286                continue
     287            if parent_model:
     288                continue
    284289            if self.cleaned_data.get(name) is None:
    285290                continue
    286291            if f.unique:
    class BaseModelForm(BaseForm):  
    294299        return unique_checks, date_checks
    295300
    296301
    297     def _perform_unique_checks(self, unique_checks):
     302    def _perform_unique_checks(self, model, unique_checks):
    298303        bad_fields = set()
    299304        form_errors = []
    300305
    class BaseModelForm(BaseForm):  
    312317                    lookup_value =  lookup_value.pk
    313318                lookup_kwargs[str(field_name)] = lookup_value
    314319
    315             qs = self.instance.__class__._default_manager.filter(**lookup_kwargs)
     320            qs = model._default_manager.filter(**lookup_kwargs)
    316321
    317322            # Exclude the current object from the query if we are editing an
    318323            # instance (as opposed to creating a new one)
    class BaseModelForm(BaseForm):  
    323328            # tell if a particular query returns any results.
    324329            if qs.extra(select={'a': 1}).values('a').order_by():
    325330                if len(unique_check) == 1:
    326                     self._errors[unique_check[0]] = ErrorList([self.unique_error_message(unique_check)])
     331                    self._errors[unique_check[0]] = ErrorList([self.unique_error_message(model, unique_check)])
    327332                else:
    328                     form_errors.append(self.unique_error_message(unique_check))
     333                    form_errors.append(self.unique_error_message(model, unique_check))
    329334
    330335                # Mark these fields as needing to be removed from cleaned data
    331336                # later.
    class BaseModelForm(BaseForm):  
    333338                    bad_fields.add(field_name)
    334339        return bad_fields, form_errors
    335340
    336     def _perform_date_checks(self, date_checks):
     341    def _perform_date_checks(self, model, date_checks):
    337342        bad_fields = set()
    338343        for lookup_type, field, unique_for in date_checks:
    339344            lookup_kwargs = {}
    class BaseModelForm(BaseForm):  
    348353                lookup_kwargs['%s__%s' % (unique_for, lookup_type)] = getattr(self.cleaned_data[unique_for], lookup_type)
    349354            lookup_kwargs[field] = self.cleaned_data[field]
    350355
    351             qs = self.instance.__class__._default_manager.filter(**lookup_kwargs)
     356            qs = model._default_manager.filter(**lookup_kwargs)
    352357            # Exclude the current object from the query if we are editing an
    353358            # instance (as opposed to creating a new one)
    354359            if self.instance.pk is not None:
    class BaseModelForm(BaseForm):  
    370375            'lookup': lookup_type,
    371376        }
    372377
    373     def unique_error_message(self, unique_check):
    374         model_name = capfirst(self.instance._meta.verbose_name)
     378    def unique_error_message(self, model, unique_check):
     379        model_name = capfirst(model._meta.verbose_name)
    375380
    376381        # A unique field
    377382        if len(unique_check) == 1:
    class BaseModelFormSet(BaseFormSet):  
    532537                break
    533538        else:
    534539            return
    535         unique_checks, date_checks = form._get_unique_checks()
     540        unique_checks, date_checks = form._get_unique_checks(self.instance.__class__)
    536541        errors = []
    537542        # Do each of the unique checks (unique and unique_together)
    538543        for unique_check in unique_checks:
Back to Top