Ticket #8209: django-8209.3.diff

File django-8209.3.diff, 11.9 KB (added by Alex, 7 years ago)

Removed usage of any

  • django/forms/models.py

    diff --git a/django/forms/models.py b/django/forms/models.py
    index 4563ace..c0062f5 100644
    a b Helper functions for creating Form classes from Django models 
    33and database field objects.
    44"""
    55
    6 from django.utils.translation import ugettext_lazy as _
    76from django.utils.encoding import smart_unicode
    87from django.utils.datastructures import SortedDict
     8from django.utils.text import get_text_list
     9from django.utils.translation import ugettext_lazy as _
    910
    1011from util import ValidationError, ErrorList
    1112from forms import BaseForm, get_declared_fields
    __all__ = ( 
    2021    'ModelMultipleChoiceField',
    2122)
    2223
     24
    2325def save_instance(form, instance, fields=None, fail_message='saved',
    2426                  commit=True, exclude=None):
    2527    """
    class BaseModelForm(BaseForm): 
    202204            object_data.update(initial)
    203205        super(BaseModelForm, self).__init__(data, files, auto_id, prefix, object_data,
    204206                                            error_class, label_suffix, empty_permitted)
     207    def clean(self):
     208        self.validate_unique()
     209        return self.cleaned_data
     210   
     211    def validate_unique(self):
     212        from django.db.models.fields import FieldDoesNotExist
     213        unique_checks = list(self.instance._meta.unique_together[:])
     214        form_errors = []
     215        for name, field in self.fields.items():
     216            try:
     217                f = self.instance._meta.get_field_by_name(name)[0]
     218            except FieldDoesNotExist:
     219                # This is an extra field that's not on the model, ignore it
     220                continue
     221            if name in self.cleaned_data and f.unique:
     222                unique_checks.append((name,))
     223        # we ignore fields that already have an error
     224        for unique_check in [check for check in unique_checks if not [x in self._errors for x in check if x in self._errors]]:
     225            # generate are parameters for the query
     226            kwargs = dict([(field_name, self.cleaned_data[field_name]) for field_name in unique_check])
     227            qs = self.instance.__class__._default_manager.filter(**kwargs)
     228            if self.instance.pk is not None:
     229                # exclude the current object from the query if we are editing an
     230                # instance
     231                qs = qs.exclude(pk=self.instance.pk)
     232            if qs.extra(select={'a': 1}).values('a').order_by():
     233                model_name = self.instance._meta.verbose_name.title()
     234                # a unique field
     235                if len(unique_check) == 1:
     236                    field_name = unique_check[0]
     237                    field_label = self.fields[field_name].label
     238                    # insert the error into the error dict, very sneaky
     239                    self._errors[field_name] = ErrorList([
     240                        _("%(model_name)s with this %(field_label)s already exists.") % \
     241                        {'model_name': model_name, 'field_label': field_label}
     242                    ])
     243                # a unique together
     244                else:
     245                    field_labels = [self.fields[field_name].label for field_name in unique_check]
     246                    field_labels = get_text_list(field_labels, _('and'))
     247                    form_errors.append(
     248                        _("%(model_name)s with this %(field_label)s already exists.") % \
     249                        {'model_name': model_name, 'field_label': field_labels}
     250                    )
     251                for field_name in unique_check:
     252                    # remove the data from the cleaned_data dict since it was
     253                    # invalid
     254                    del self.cleaned_data[field_name]
     255        if form_errors:
     256            # raise the unique together errors since they are considered
     257            # form wide.
     258            raise ValidationError(form_errors)
    205259
    206260    def save(self, commit=True):
    207261        """
    class BaseModelFormSet(BaseFormSet): 
    246300                 queryset=None, **kwargs):
    247301        self.queryset = queryset
    248302        defaults = {'data': data, 'files': files, 'auto_id': auto_id, 'prefix': prefix}
    249         if self.max_num > 0:
    250             qs = self.get_queryset()[:self.max_num]
    251         else:
    252             qs = self.get_queryset()
    253         defaults['initial'] = [model_to_dict(obj) for obj in qs]
     303        defaults['initial'] = [model_to_dict(obj) for obj in self.get_queryset()]
    254304        defaults.update(kwargs)
    255305        super(BaseModelFormSet, self).__init__(**defaults)
    256 
     306   
     307    def _construct_form(self, i, **kwargs):
     308        if i < self._initial_form_count:
     309            kwargs['instance'] = self.get_queryset()[i]
     310        return super(BaseModelFormSet, self)._construct_form(i, **kwargs)
     311       
    257312    def get_queryset(self):
    258         if self.queryset is not None:
    259             return self.queryset
    260         return self.model._default_manager.get_query_set()
    261 
     313        if not hasattr(self, '_queryset'):
     314            if self.queryset is not None:
     315                qs = self.queryset
     316            else:
     317                qs = self.model._default_manager.get_query_set()
     318            if self.max_num > 0:
     319                self._queryset = qs[:self.max_num]
     320            else:
     321                self._queryset = qs
     322        return self._queryset
     323   
    262324    def save_new(self, form, commit=True):
    263325        """Saves and returns a new model instance for the given form."""
    264326        return save_instance(form, self.model(), exclude=[self._pk_field.name], commit=commit)
    class BaseInlineFormSet(BaseModelFormSet): 
    358420            self._total_form_count = self._initial_form_count
    359421            self._initial_form_count = 0
    360422        super(BaseInlineFormSet, self)._construct_forms()
     423   
     424    def _construct_form(self, i, **kwargs):
     425        form = super(BaseInlineFormSet, self)._construct_form(i, **kwargs)
     426        if self.save_as_new:
     427            # Remove the primary key from the form's data, we are only
     428            # creating new instances
     429            form.data[form.add_prefix(self._pk_field.name)] = None
     430        return form
    361431
    362432    def get_queryset(self):
    363433        """
  • django/utils/itercompat.py

    diff --git a/django/utils/itercompat.py b/django/utils/itercompat.py
    index c166da3..4a28f81 100644
    a b def sorted(in_value): 
    7272    out_value = in_value[:]
    7373    out_value.sort()
    7474    return out_value
     75
  • 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 5f714fb..9a306aa 100644
    a b class CommaSeparatedInteger(models.Model): 
    117117    def __unicode__(self):
    118118        return self.field
    119119
     120class Product(models.Model):
     121    slug = models.SlugField(unique=True)
     122   
     123    def __unicode__(self):
     124        return self.slug
     125
     126class Price(models.Model):
     127    price = models.DecimalField(max_digits=10, decimal_places=2)
     128    quantity = models.PositiveIntegerField()
     129   
     130    def __unicode__(self):
     131        return u"%s for %s" % (self.quantity, self.price)
     132   
     133    class Meta:
     134        unique_together = (('price', 'quantity'),)
     135
    120136class ArticleStatus(models.Model):
    121137    status = models.CharField(max_length=2, choices=ARTICLE_STATUS_CHAR, blank=True, null=True)
    122138
     139
    123140__test__ = {'API_TESTS': """
    124141>>> from django import forms
    125142>>> from django.forms.models import ModelForm, model_to_dict
    u'1,,2' 
    11321149>>> f.clean('1')
    11331150u'1'
    11341151
    1135 # Choices on CharField and IntegerField
     1152# unique/unique_together validation
    11361153
     1154>>> class ProductForm(ModelForm):
     1155...     class Meta:
     1156...         model = Product
     1157>>> form = ProductForm({'slug': 'teddy-bear-blue'})
     1158>>> form.is_valid()
     1159True
     1160>>> obj = form.save()
     1161>>> obj
     1162<Product: teddy-bear-blue>
     1163>>> form = ProductForm({'slug': 'teddy-bear-blue'})
     1164>>> form.is_valid()
     1165False
     1166>>> form._errors
     1167{'slug': [u'Product with this Slug already exists.']}
     1168>>> form = ProductForm({'slug': 'teddy-bear-blue'}, instance=obj)
     1169>>> form.is_valid()
     1170True
     1171
     1172# ModelForm test of unique_together constraint
     1173>>> class PriceForm(ModelForm):
     1174...     class Meta:
     1175...         model = Price
     1176>>> form = PriceForm({'price': '6.00', 'quantity': '1'})
     1177>>> form.is_valid()
     1178True
     1179>>> form.save()
     1180<Price: 1 for 6.00>
     1181>>> form = PriceForm({'price': '6.00', 'quantity': '1'})
     1182>>> form.is_valid()
     1183False
     1184>>> form._errors
     1185{'__all__': [u'Price with this Price and Quantity already exists.']}
     1186
     1187# Choices on CharField and IntegerField
    11371188>>> class ArticleForm(ModelForm):
    11381189...     class Meta:
    11391190...         model = Article
  • tests/modeltests/model_formsets/models.py

    diff --git a/tests/modeltests/model_formsets/models.py b/tests/modeltests/model_formsets/models.py
    index 332c5a7..1e25baa 100644
    a b class Restaurant(Place): 
    7373    def __unicode__(self):
    7474        return self.name
    7575
     76class Product(models.Model):
     77    slug = models.SlugField(unique=True)
     78
     79    def __unicode__(self):
     80        return self.slug
     81
     82class Price(models.Model):
     83    price = models.DecimalField(max_digits=10, decimal_places=2)
     84    quantity = models.PositiveIntegerField()
     85
     86    def __unicode__(self):
     87        return u"%s for %s" % (self.quantity, self.price)
     88
     89    class Meta:
     90        unique_together = (('price', 'quantity'),)
     91
    7692class MexicanRestaurant(Restaurant):
    7793    serves_tacos = models.BooleanField()
    7894
    True 
    553569>>> type(_get_foreign_key(MexicanRestaurant, Owner))
    554570<class 'django.db.models.fields.related.ForeignKey'>
    555571
     572# unique/unique_together validation ###########################################
     573
     574>>> FormSet = modelformset_factory(Product, extra=1)
     575>>> data = {
     576...     'form-TOTAL_FORMS': '1',
     577...     'form-INITIAL_FORMS': '0',
     578...     'form-0-slug': 'car-red',
     579... }
     580>>> formset = FormSet(data)
     581>>> formset.is_valid()
     582True
     583>>> formset.save()
     584[<Product: car-red>]
     585
     586>>> data = {
     587...     'form-TOTAL_FORMS': '1',
     588...     'form-INITIAL_FORMS': '0',
     589...     'form-0-slug': 'car-red',
     590... }
     591>>> formset = FormSet(data)
     592>>> formset.is_valid()
     593False
     594>>> formset.errors
     595[{'slug': [u'Product with this Slug already exists.']}]
     596
     597# unique_together
     598
     599>>> FormSet = modelformset_factory(Price, extra=1)
     600>>> data = {
     601...     'form-TOTAL_FORMS': '1',
     602...     'form-INITIAL_FORMS': '0',
     603...     'form-0-price': u'12.00',
     604...     'form-0-quantity': '1',
     605... }
     606>>> formset = FormSet(data)
     607>>> formset.is_valid()
     608True
     609>>> formset.save()
     610[<Price: 1 for 12.00>]
     611
     612>>> data = {
     613...     'form-TOTAL_FORMS': '1',
     614...     'form-INITIAL_FORMS': '0',
     615...     'form-0-price': u'12.00',
     616...     'form-0-quantity': '1',
     617... }
     618>>> formset = FormSet(data)
     619>>> formset.is_valid()
     620False
     621>>> formset.errors
     622[{'__all__': [u'Price with this Price and Quantity already exists.']}]
     623
    556624"""}
Back to Top