Ticket #10134: unique_for_stuff.diff
File unique_for_stuff.diff, 5.7 KB (added by , 16 years ago) |
---|
-
django/forms/models.py
diff --git a/django/forms/models.py b/django/forms/models.py index 7ca1ab5..7a33ab8 100644
a b class BaseModelForm(BaseForm): 315 315 for field_name in unique_check: 316 316 bad_fields.add(field_name) 317 317 318 # we do a second round of checks to see if we need to do validation for 319 # any unique_for_<date/year/moth> 320 unique_checks = [] 321 for name, field in self.fields.items(): 322 try: 323 f = self.instance._meta.get_field_by_name(name)[0] 324 except FieldDoesNotExist: 325 # This is an extra field that's not on the ModelForm, ignore it 326 continue 327 if not isinstance(f, ModelField): 328 # This is an extra field that happens to have a name that matches, 329 # for example, a related object accessor for this model. So 330 # get_field_by_name found it, but it is not a Field so do not proceed 331 # to use it as if it were. 332 continue 333 if self.cleaned_data.get(name) is None: 334 continue 335 if f.unique_for_date and self.cleaned_data.get(f.unique_for_date) is not None: 336 unique_checks.append(('date', name, f.unique_for_date)) 337 if f.unique_for_year and self.cleaned_data.get(f.unique_for_year) is not None: 338 unique_checks.append(('year', name, f.unique_for_year)) 339 if f.unique_for_month and self.cleaned_data.get(f.unique_for_month) is not None: 340 unique_checks.append(('month', name, f.unique_for_month)) 341 342 for lookup_type, field, unique_for in unique_checks: 343 lookup_kwargs = {} 344 # there's a ticket to add a date lookup, we can remove this special 345 # case if that makes it's way in 346 if lookup_type == 'date': 347 date = self.cleaned_data[unique_for] 348 lookup_kwargs['%s__day' % unique_for] = date.day 349 lookup_kwargs['%s__month' % unique_for] = date.month 350 lookup_kwargs['%s__year' % unique_for] = date.year 351 else: 352 lookup_kwargs['%s__%s' % (unique_for, lookup_type)] = getattr(self.cleaned_data[unique_for], lookup_type) 353 lookup_kwargs[field] = self.cleaned_data[field] 354 355 qs = self.instance.__class__._default_manager.filter(**lookup_kwargs) 356 # Exclude the current object from the query if we are editing an 357 # instance (as opposed to creating a new one) 358 if self.instance.pk is not None: 359 qs = qs.exclude(pk=self.instance.pk) 360 361 # This cute trick with extra/values is the most efficient way to 362 # tell if a particular query returns any results. 363 if qs.extra(select={'a': 1}).values('a').order_by(): 364 self._errors[field] = ErrorList([ 365 _(u"%(field_name)s must be unique for %(date_field)s %(lookup)s.") % { 366 'field_name': unicode(self.fields[field].label), 367 'date_field': unicode(self.fields[unique_for].label), 368 'lookup': lookup_type, 369 } 370 ]) 371 bad_fields.add(field) 372 318 373 for field_name in bad_fields: 319 374 del self.cleaned_data[field_name] 320 375 if form_errors: -
tests/modeltests/model_forms/models.py
diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py index 992bb90..d5353ae 100644
a b class ExplicitPK(models.Model): 189 189 def __unicode__(self): 190 190 return self.key 191 191 192 class Post(models.Model): 193 title = models.CharField(max_length=50, unique_for_date='posted', blank=True) 194 slug = models.CharField(max_length=50, unique_for_year='posted', blank=True) 195 subtitle = models.CharField(max_length=50, unique_for_month='posted', blank=True) 196 posted = models.DateField() 197 198 def __unicode__(self): 199 return self.name 200 192 201 __test__ = {'API_TESTS': """ 193 202 >>> from django import forms 194 203 >>> from django.forms.models import ModelForm, model_to_dict … … ValidationError: [u'Select a valid choice. z is not one of the available choices 1472 1481 <tr><th><label for="id_description">Description:</label></th><td><input type="text" name="description" id="id_description" /></td></tr> 1473 1482 <tr><th><label for="id_url">The URL:</label></th><td><input id="id_url" type="text" name="url" maxlength="40" /></td></tr> 1474 1483 1484 ### validation on unique_for_date 1485 1486 >>> p = Post.objects.create(title="Django 1.0 is released", slug="Django 1.0", subtitle="Finally", posted=datetime.date(2008, 9, 3)) 1487 >>> class PostForm(ModelForm): 1488 ... class Meta: 1489 ... model = Post 1490 1491 >>> f = PostForm({'title': "Django 1.0 is released", 'posted': '2008-09-03'}) 1492 >>> f.is_valid() 1493 False 1494 >>> f.errors 1495 {'title': [u'Title must be unique for Posted date.']} 1496 >>> f = PostForm({'title': "Work on Django 1.1 begins", 'posted': '2008-09-03'}) 1497 >>> f.is_valid() 1498 True 1499 >>> f = PostForm({'title': "Django 1.0 is released", 'posted': '2008-09-04'}) 1500 >>> f.is_valid() 1501 True 1502 >>> f = PostForm({'slug': "Django 1.0", 'posted': '2008-01-01'}) 1503 >>> f.is_valid() 1504 False 1505 >>> f.errors 1506 {'slug': [u'Slug must be unique for Posted year.']} 1507 >>> f = PostForm({'subtitle': "Finally", 'posted': '2008-09-30'}) 1508 >>> f.is_valid() 1509 False 1510 >>> f.errors 1511 {'subtitle': [u'Subtitle must be unique for Posted month.']} 1512 >>> f = PostForm({'subtitle': "Finally", "title": "Django 1.0 is released", "slug": "Django 1.0", 'posted': '2008-09-03'}, instance=p) 1513 >>> f.is_valid() 1514 True 1515 1475 1516 # Clean up 1476 1517 >>> import shutil 1477 1518 >>> shutil.rmtree(temp_storage_dir)