Ticket #8209: django-r8769-8209.diff

File django-r8769-8209.diff, 5.4 KB (added by Alex, 6 years ago)
  • django/forms/models.py

    diff --git a/django/forms/models.py b/django/forms/models.py
    index 6acd32c..112a2ff 100644
    a b class BaseModelForm(BaseForm): 
    202202            object_data.update(initial)
    203203        super(BaseModelForm, self).__init__(data, files, auto_id, prefix, object_data,
    204204                                            error_class, label_suffix, empty_permitted)
     205    def clean(self):
     206        self.validate_unique()
     207        return self.cleaned_data
     208   
     209    def validate_unique(self):
     210        from django.db.models.fields import FieldDoesNotExist
     211        unique_checks = self.instance._meta.unique_together[:]
     212        form_errors = []
     213        for name, field in self.fields.items():
     214            try:
     215                if name in self.cleaned_data and self.instance._meta.get_field_by_name(name)[0].unique and not self.instance._meta.get_field_by_name(name)[0].primary_key:
     216                    unique_checks.append((name,))
     217            except FieldDoesNotExist:
     218                # This is an extra field that's not on the model, ignore it
     219                pass
     220        for unique_check in [check for check in unique_checks if not any([x in self._errors for x in check])]:
     221            kwargs = dict([(field_name, self.cleaned_data[field_name]) for field_name in unique_check])
     222            qs = self.instance.__class__._default_manager.filter(**kwargs)
     223            if self.instance.pk is not None:
     224                qs = qs.exclude(pk=self.instance.pk)
     225            if qs.count() != 0:
     226                model_name = self.instance._meta.verbose_name.title()
     227                if len(unique_check) == 1:
     228                    field_name = unique_check[0]
     229                    field_label = self.fields[field_name].label
     230                    self._errors[field_name] = ErrorList(["%s with this %s already exists." % (model_name, field_label)])
     231                else:
     232                    field_labels = [self.fields[field_name].label for field_name in unique_check]
     233                    form_errors.append("%s with this %s already exists." % (model_name, ' and '.join(field_labels)))
     234                for field_name in unique_check:
     235                    del self.cleaned_data[field_name]
     236        if form_errors:
     237            raise ValidationError(form_errors)
    205238
    206239    def save(self, commit=True):
    207240        """
  • docs/topics/forms/modelforms.txt

    diff --git a/docs/topics/forms/modelforms.txt b/docs/topics/forms/modelforms.txt
    index d161b3f..163c428 100644
    a b parameter when declaring the form field:: 
    338338   ...     class Meta:
    339339   ...         model = Article
    340340
     341Overriding the clean() method
     342-----------------------------
     343
     344You can overide the ``clean()`` method on a model form to provide additional
     345validation in the same way you can on a normal form.  However, by default the
     346``clean()`` method validates the uniqueness of fields that are marked as unique
     347on the model, and those marked as unque_together, if you would like to overide
     348the ``clean()`` method and maintain the default validation you must call the
     349parent class's ``clean()`` method.
     350
    341351Form inheritance
    342352----------------
    343353
    books of a specific author. Here is how you could accomplish this:: 
    500510    >>> from django.forms.models import inlineformset_factory
    501511    >>> BookFormSet = inlineformset_factory(Author, Book)
    502512    >>> author = Author.objects.get(name=u'Orson Scott Card')
    503     >>> formset = BookFormSet(instance=author)
    504  No newline at end of file
     513    >>> formset = BookFormSet(instance=author)
  • tests/modeltests/model_forms/models.py

    diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py
    index 0ea2075..9cde87f 100644
    a b class CommaSeparatedInteger(models.Model): 
    111111    def __unicode__(self):
    112112        return self.field
    113113
     114class Unique(models.Model):
     115    unique_field = models.CharField(max_length=100, unique=True)
     116
     117class UniqueTogether(models.Model):
     118    unique_field_1 = models.CharField(max_length=100)
     119    unique_field_2 = models.CharField(max_length=100)
     120   
     121    class Meta:
     122        unique_together = (('unique_field_1', 'unique_field_2'),)
     123
    114124__test__ = {'API_TESTS': """
    115125>>> from django import forms
    116126>>> from django.forms.models import ModelForm, model_to_dict
    u'1,,2' 
    11231133>>> f.clean('1')
    11241134u'1'
    11251135
     1136>>> class UniqueForm(ModelForm):
     1137...     class Meta:
     1138...         model = Unique
     1139>>> form1 = UniqueForm({'unique_field': 'unique'})
     1140>>> form1.is_valid()
     1141True
     1142>>> obj = form1.save()
     1143>>> obj
     1144<Unique: Unique object>
     1145>>> form2 = UniqueForm({'unique_field': 'unique'})
     1146>>> form2.is_valid()
     1147False
     1148>>> form2._errors
     1149{'unique_field': [u'Unique with this Unique field already exists.']}
     1150>>> form3 = UniqueForm({'unique_field': 'unique'}, instance=obj)
     1151>>> form3.is_valid()
     1152True
     1153
     1154# ModelForm test of unique_together constraint
     1155
     1156>>> class UniqueTogetherForm(ModelForm):
     1157...     class Meta:
     1158...         model = UniqueTogether
     1159>>> form1 = UniqueTogetherForm({'unique_field_1': 'unique1', 'unique_field_2': 'unique2'})
     1160>>> form1.is_valid()
     1161True
     1162>>> form1.save()
     1163<UniqueTogether: UniqueTogether object>
     1164>>> form2 = UniqueTogetherForm({'unique_field_1': 'unique1', 'unique_field_2': 'unique2'})
     1165>>> form2.is_valid()
     1166False
     1167>>> form2._errors
     1168{'__all__': [u'Unique Together with this Unique field 1 and Unique field 2 already exists.']}
     1169
    11261170"""}
Back to Top