Ticket #12521: 12521.4.diff
File 12521.4.diff, 42.1 KB (added by , 15 years ago) |
---|
-
django/contrib/admin/options.py
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 6dc707e..8f68eb1 100644
a b class ModelAdmin(BaseModelAdmin): 579 579 """ 580 580 messages.info(request, message) 581 581 582 def save_form(self, request, form, change , commit=False):582 def save_form(self, request, form, change): 583 583 """ 584 584 Given a ModelForm return an unsaved instance. ``change`` is True if 585 585 the object is being changed, and False if it's being added. 586 586 """ 587 return form.save(commit= commit)587 return form.save(commit=False) 588 588 589 589 def save_model(self, request, obj, form, change): 590 590 """ … … class ModelAdmin(BaseModelAdmin): 758 758 if request.method == 'POST': 759 759 form = ModelForm(request.POST, request.FILES) 760 760 if form.is_valid(): 761 # Save the object, even if inline formsets haven't been 762 # validated yet. We need to pass the valid model to the 763 # formsets for validation. If the formsets do not validate, we 764 # will delete the object. 765 new_object = self.save_form(request, form, change=False, commit=True) 761 new_object = self.save_form(request, form, change=False) 766 762 form_validated = True 767 763 else: 768 764 form_validated = False … … class ModelAdmin(BaseModelAdmin): 779 775 prefix=prefix, queryset=inline.queryset(request)) 780 776 formsets.append(formset) 781 777 if all_valid(formsets) and form_validated: 778 self.save_model(request, new_object, form, change=False) 779 form.save_m2m() 782 780 for formset in formsets: 783 781 self.save_formset(request, form, formset, change=False) 784 782 785 783 self.log_addition(request, new_object) 786 784 return self.response_add(request, new_object) 787 elif form_validated:788 # The form was valid, but formsets were not, so delete the789 # object we saved above.790 new_object.delete()791 785 else: 792 786 # Prepare the dict of initial data from the request. 793 787 # We have to special-case M2Ms as a list of comma-separated PKs. -
django/contrib/auth/forms.py
diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py index dbc55ca..55e770e 100644
a b 1 from django.contrib.auth.models import User , UNUSABLE_PASSWORD1 from django.contrib.auth.models import User 2 2 from django.contrib.auth import authenticate 3 3 from django.contrib.auth.tokens import default_token_generator 4 4 from django.contrib.sites.models import Site … … class UserCreationForm(forms.ModelForm): 21 21 model = User 22 22 fields = ("username",) 23 23 24 def clean(self):25 # Fill the password field so model validation won't complain about it26 # being blank. We'll set it with the real value below.27 self.instance.password = UNUSABLE_PASSWORD28 super(UserCreationForm, self).clean()29 30 24 def clean_username(self): 31 25 username = self.cleaned_data["username"] 32 26 try: … … class UserCreationForm(forms.ModelForm): 40 34 password2 = self.cleaned_data["password2"] 41 35 if password1 != password2: 42 36 raise forms.ValidationError(_("The two password fields didn't match.")) 43 self.instance.set_password(password1)44 37 return password2 45 38 39 def save(self, commit=True): 40 user = super(UserCreationForm, self).save(commit=False) 41 user.set_password(self.cleaned_data["password1"]) 42 if commit: 43 user.save() 44 return user 45 46 46 class UserChangeForm(forms.ModelForm): 47 47 username = forms.RegexField(label=_("Username"), max_length=30, regex=r'^\w+$', 48 48 help_text = _("Required. 30 characters or fewer. Alphanumeric characters only (letters, digits and underscores)."), -
django/core/exceptions.py
diff --git a/django/core/exceptions.py b/django/core/exceptions.py index fee7db4..bc599df 100644
a b class FieldError(Exception): 33 33 pass 34 34 35 35 NON_FIELD_ERRORS = '__all__' 36 class BaseValidationError(Exception):36 class ValidationError(Exception): 37 37 """An error while validating data.""" 38 38 def __init__(self, message, code=None, params=None): 39 39 import operator … … class BaseValidationError(Exception): 64 64 return repr(self.message_dict) 65 65 return repr(self.messages) 66 66 67 class ValidationError(BaseValidationError): 68 pass 69 70 class UnresolvableValidationError(BaseValidationError): 71 """Validation error that cannot be resolved by the user.""" 72 pass 67 def update_errors(errors, e): 68 if hasattr(e, 'message_dict'): 69 if errors: 70 for k, v in e.message_dict.items(): 71 errors.setdefault(k, []).extend(v) 72 else: 73 errors = e.message_dict 74 else: 75 errors[NON_FIELD_ERRORS] = e.messages 76 return errors 73 77 -
django/db/models/base.py
diff --git a/django/db/models/base.py b/django/db/models/base.py index 06db7cc..bce3979 100644
a b import sys 3 3 import os 4 4 from itertools import izip 5 5 import django.db.models.manager # Imported to register signal handler. 6 from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, FieldError, ValidationError, NON_FIELD_ERRORS 6 from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, FieldError, ValidationError, NON_FIELD_ERRORS, update_errors 7 7 from django.core import validators 8 8 from django.db.models.fields import AutoField, FieldDoesNotExist 9 9 from django.db.models.fields.related import OneToOneRel, ManyToOneRel, OneToOneField … … class Model(object): 642 642 def prepare_database_save(self, unused): 643 643 return self.pk 644 644 645 def validate(self):645 def clean(self): 646 646 """ 647 647 Hook for doing any extra model-wide validation after clean() has been 648 called on every field . Any ValidationError raised by this method will649 not be associated with a particular field; it will have a special-case650 association with the field defined by NON_FIELD_ERRORS.648 called on every field by self.clean_fields. Any ValidationError raised 649 by this method will not be associated with a particular field; it will 650 have a special-case association with the field defined by NON_FIELD_ERRORS. 651 651 """ 652 self.validate_unique()652 pass 653 653 654 def validate_unique(self): 655 unique_checks, date_checks = self._get_unique_checks() 654 def validate_unique(self, exclude=None): 655 """ 656 Checks unique constraints on the model and raises ``ValidationError`` 657 if any failed. 658 """ 659 unique_checks, date_checks = self._get_unique_checks(exclude=exclude) 656 660 657 661 errors = self._perform_unique_checks(unique_checks) 658 662 date_errors = self._perform_date_checks(date_checks) … … class Model(object): 663 667 if errors: 664 668 raise ValidationError(errors) 665 669 666 def _get_unique_checks(self): 667 from django.db.models.fields import FieldDoesNotExist, Field as ModelField 670 def _get_unique_checks(self, exclude=None): 671 """ 672 Gather a list of checks to perform. Since validate_unique could be 673 called from a ModelForm, some fields may have been excluded; we can't 674 perform a unique check on a model that is missing fields involved 675 in that check. 676 Fields that did not validate should also be exluded, but they need 677 to be passed in via the exclude argument. 678 """ 679 if exclude is None: 680 exclude = [] 681 unique_checks = [] 682 for check in self._meta.unique_together: 683 for name in check: 684 # If this is an excluded field, don't add this check. 685 if name in exclude: 686 break 687 else: 688 unique_checks.append(check) 668 689 669 unique_checks = list(self._meta.unique_together) 670 # these are checks for the unique_for_<date/year/month> 690 # These are checks for the unique_for_<date/year/month>. 671 691 date_checks = [] 672 692 673 693 # Gather a list of checks for fields declared as unique and add them to 674 # the list of checks. Again, skip empty fields and any that did not validate.694 # the list of checks. 675 695 for f in self._meta.fields: 676 696 name = f.name 697 if name in exclude: 698 continue 677 699 if f.unique: 678 700 unique_checks.append((name,)) 679 701 if f.unique_for_date: … … class Model(object): 684 706 date_checks.append(('month', name, f.unique_for_month)) 685 707 return unique_checks, date_checks 686 708 687 688 709 def _perform_unique_checks(self, unique_checks): 689 710 errors = {} 690 711 … … class Model(object): 781 802 'field_label': unicode(field_labels) 782 803 } 783 804 784 def full_validate(self, exclude=[]): 805 def full_clean(self, exclude=None): 806 """ 807 Calls clean_fields, clean, and validate_unique, on the model, 808 and raises a ``ValidationError`` for any errors that occured. 809 """ 810 errors = {} 811 if exclude is None: 812 exclude = [] 813 814 try: 815 self.clean_fields(exclude=exclude) 816 except ValidationError, e: 817 errors = update_errors(errors, e) 818 819 # Form.clean() is run even if other validation fails, so do the 820 # same with Model.clean() for consistency. 821 try: 822 self.clean() 823 except ValidationError, e: 824 errors = update_errors(errors, e) 825 826 # Run unique checks, but only for fields that passed validation. 827 for name in errors.keys(): 828 if name != NON_FIELD_ERRORS and name not in exclude: 829 exclude.append(name) 830 try: 831 self.validate_unique(exclude=exclude) 832 except ValidationError, e: 833 errors = update_errors(errors, e) 834 835 if errors: 836 raise ValidationError(errors) 837 838 def clean_fields(self, exclude=None): 785 839 """ 786 Cleans all fields and raises ValidationError containing message_dict840 Cleans all fields and raises a ValidationError containing message_dict 787 841 of all validation errors if any occur. 788 842 """ 843 if exclude is None: 844 exclude = [] 789 845 errors = {} 790 846 for f in self._meta.fields: 791 847 if f.name in exclude: 792 848 continue 849 # Skip validation for empty fields with blank=True. The developer 850 # is responsible for making sure they have a valid value. 851 raw_value = getattr(self, f.attname) 852 if f.blank and raw_value in validators.EMPTY_VALUES: 853 continue 793 854 try: 794 setattr(self, f.attname, f.clean( getattr(self, f.attname), self))855 setattr(self, f.attname, f.clean(raw_value, self)) 795 856 except ValidationError, e: 796 857 errors[f.name] = e.messages 797 798 # Form.clean() is run even if other validation fails, so do the799 # same with Model.validate() for consistency.800 try:801 self.validate()802 except ValidationError, e:803 if hasattr(e, 'message_dict'):804 if errors:805 for k, v in e.message_dict.items():806 errors.set_default(k, []).extend(v)807 else:808 errors = e.message_dict809 else:810 errors[NON_FIELD_ERRORS] = e.messages811 812 858 if errors: 813 859 raise ValidationError(errors) 814 860 -
django/db/models/fields/related.py
diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index 8fec836..ae6a2f7 100644
a b class ForeignKey(RelatedField, Field): 740 740 def validate(self, value, model_instance): 741 741 if self.rel.parent_link: 742 742 return 743 # Don't validate the field if a value wasn't supplied. This is 744 # generally the case when saving new inlines in the admin. 745 # See #12507. 746 if value is None: 747 return 743 748 super(ForeignKey, self).validate(value, model_instance) 744 749 if not value: 745 750 return -
django/forms/models.py
diff --git a/django/forms/models.py b/django/forms/models.py index ff20c93..0085afd 100644
a b from django.utils.datastructures import SortedDict 9 9 from django.utils.text import get_text_list, capfirst 10 10 from django.utils.translation import ugettext_lazy as _, ugettext 11 11 12 from django.core.exceptions import ValidationError, NON_FIELD_ERRORS, UnresolvableValidationError12 from django.core.exceptions import ValidationError, update_errors, NON_FIELD_ERRORS 13 13 from django.core.validators import EMPTY_VALUES 14 14 from util import ErrorList 15 15 from forms import BaseForm, get_declared_fields … … class ModelFormMetaclass(type): 228 228 class BaseModelForm(BaseForm): 229 229 def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, 230 230 initial=None, error_class=ErrorList, label_suffix=':', 231 empty_permitted=False, instance=None ):231 empty_permitted=False, instance=None, validate_model=False): 232 232 opts = self._meta 233 self.validate_model = validate_model 233 234 if instance is None: 234 235 # if we didn't get an instance, instantiate a new one 235 236 self.instance = opts.model() … … class BaseModelForm(BaseForm): 245 246 super(BaseModelForm, self).__init__(data, files, auto_id, prefix, object_data, 246 247 error_class, label_suffix, empty_permitted) 247 248 249 250 def _get_validation_exclusions(self): 251 """ 252 For backwards-compatibility, several types of fields need to be 253 excluded from model validation. See the following tickets for 254 details: #12507, #12521, #12553 255 However, if self.full_validate=True, run complete model validation. 256 """ 257 exclude = [] 258 if self.validate_model: 259 return exclude 260 261 # Build up a list of fields that should be excluded from model field 262 # validation and unique checks. 263 for f in self.instance._meta.fields: 264 field = f.name 265 # Exclude fields that aren't on the form. The developer may be 266 # adding these values to the model after form validation. 267 if field not in self.fields: 268 exclude.append(f.name) 269 # Exclude fields that failed form validation. There's no need for 270 # the model fields to validate them as well. 271 elif field in self._errors.keys(): 272 exclude.append(f.name) 273 # Exclude empty fields that are not required by the form. The 274 # underlying model field may be required, so this keeps the model 275 # field from raising that error. 276 else: 277 form_field = self.fields[field] 278 field_value = self.cleaned_data.get(field, None) 279 if field_value is None and not form_field.required: 280 exclude.append(f.name) 281 return exclude 282 248 283 def clean(self): 249 284 opts = self._meta 250 285 self.instance = construct_instance(self, self.instance, opts.fields, opts.exclude) 286 exclude = self._get_validation_exclusions() 251 287 try: 252 self.instance.full_ validate(exclude=self._errors.keys())288 self.instance.full_clean(exclude=exclude) 253 289 except ValidationError, e: 254 290 for k, v in e.message_dict.items(): 255 291 if k != NON_FIELD_ERRORS: 256 292 self._errors.setdefault(k, ErrorList()).extend(v) 257 258 293 # Remove the data from the cleaned_data dict since it was invalid 259 294 if k in self.cleaned_data: 260 295 del self.cleaned_data[k] 261 262 296 if NON_FIELD_ERRORS in e.message_dict: 263 297 raise ValidationError(e.message_dict[NON_FIELD_ERRORS]) 264 265 # If model validation threw errors for fields that aren't on the266 # form, the the errors cannot be corrected by the user. Displaying267 # those errors would be pointless, so raise another type of268 # exception that *won't* be caught and displayed by the form.269 if set(e.message_dict.keys()) - set(self.fields.keys() + [NON_FIELD_ERRORS]):270 raise UnresolvableValidationError(e.message_dict)271 272 273 298 return self.cleaned_data 274 299 275 300 def save(self, commit=True): … … class BaseModelFormSet(BaseFormSet): 407 432 self.validate_unique() 408 433 409 434 def validate_unique(self): 410 # Iterate over the forms so that we can find one with potentially valid 411 # data from which to extract the error checks 435 # Collect unique_checks and date_checks to run from all the forms. 436 all_unique_checks = set() 437 all_date_checks = set() 412 438 for form in self.forms: 413 if hasattr(form, 'cleaned_data'): 414 break 415 else: 416 return 417 unique_checks, date_checks = form.instance._get_unique_checks() 439 if not hasattr(form, 'cleaned_data'): 440 continue 441 exclude = form._get_validation_exclusions() 442 unique_checks, date_checks = form.instance._get_unique_checks(exclude=exclude) 443 all_unique_checks = all_unique_checks.union(set(unique_checks)) 444 all_date_checks = all_date_checks.union(set(date_checks)) 445 418 446 errors = [] 419 447 # Do each of the unique checks (unique and unique_together) 420 for unique_check in unique_checks:448 for unique_check in all_unique_checks: 421 449 seen_data = set() 422 450 for form in self.forms: 423 451 # if the form doesn't have cleaned_data then we ignore it, … … class BaseModelFormSet(BaseFormSet): 439 467 # mark the data as seen 440 468 seen_data.add(row_data) 441 469 # iterate over each of the date checks now 442 for date_check in date_checks:470 for date_check in all_date_checks: 443 471 seen_data = set() 444 472 lookup, field, unique_for = date_check 445 473 for form in self.forms: -
docs/ref/models/instances.txt
diff --git a/docs/ref/models/instances.txt b/docs/ref/models/instances.txt index 9b720be..92f5543 100644
a b Validating objects 34 34 35 35 .. versionadded:: 1.2 36 36 37 To validate your model, call its ``full_validate()`` method: 37 To add your own validation logic to a model, override the supplied ``clean()`` 38 method. 38 39 39 .. method:: Model. full_validate([exclude=[]])40 .. method:: Model.clean() 40 41 41 The optional ``exclude`` argument can contain a list of field names to omit 42 when validating. This method raises ``ValidationError`` containing a 42 This method should be used to provide model-wide validation, and to modify 43 attributes on your model if desired. For instance, you could use it to 44 automatically provide a value for a field, or to do validation that requires 45 access to more than a single field:: 46 47 def clean(self): 48 # Don't allow draft entries to have a pub_date. 49 if self.status == 'draft' and self.pub_date is not None: 50 raise ValidationError('Draft entries may not have a publication date.') 51 # Set the pub_date for published items if it hasn't been set already. 52 if self.status == 'published' and self.pub_date is None: 53 self.pub_date = datetime.datetime.now() 54 55 When this method is called by ``full_clean()``, any ``ValidationError`` raised 56 will be included in the ``message_dict`` under ``NON_FIELD_ERRORS``. 57 58 To validate and clean your model, call its ``full_clean()`` method: 59 60 .. method:: Model.full_clean(exclude=None) 61 62 This method calls ``Model.clean_fields()``, ``Model.validate_unique()`` and 63 ``Model.clean()`` in that order and raises a ``ValidationError`` containing a 43 64 message dictionary with errors from all fields. 44 65 45 To add your own validation logic, override the supplied ``validate()`` method: 66 The optional ``exclude`` argument can be used to provide a list of field names 67 that can be excluded from validation and cleaning. 46 68 47 Note that ``full_ validate`` will NOT be called automatically when you call69 Note that ``full_clean()`` will NOT be called automatically when you call 48 70 your model's ``save()`` method. You'll need to call it manually if you want 49 to run your model validators. (This is for backwards compatibility.) However, 50 if you're using a ``ModelForm``, it will call ``full_validate`` for you and 51 will present any errors along with the other form error messages. 71 to run model validation. (This is for backwards compatibility.) 72 73 You will only need to use this method if you need to customize error display 74 instead of just using a :ref:`ModelForm <topics-forms-modelforms>` 75 76 Example:: 77 78 try: 79 article.full_validate() 80 except ValidationError, e: 81 # Do something based on the errors contained in e.error_dict. 82 # Display them to a user, or handle them programatically. 83 84 .. method:: Model.clean_fields(exclude=None) 85 86 This method will validate all fields on your model. The optional ``exclude`` 87 argument lets you provide a list of field names to exclude from validation. It 88 will raise a ``ValidationError`` if any fields fail validation. 89 90 .. method:: Model.validate_unique(exclude=None) 52 91 53 .. method:: Model.validate() 92 This method is similar to ``clean_fields``, but validates all uniqueness 93 constraints on your model instead of individual field values. The optional 94 ``exclude`` argument allows you to provide a list of field names to exclude 95 from validation. It will raise a ``ValidationError`` if any fields fail 96 validation. 54 97 55 The ``validate()`` method on ``Model`` by default checks for uniqueness of 56 fields and group of fields that are declared to be unique, so remember to call 57 ``self.validate_unique()`` or the superclass' ``validate`` method if you want 58 this validation to run. 98 Note that if you provide an ``exclude`` argument to ``validate_unique``, any 99 ``unique_together`` constraint that contains one of the fields you provided 100 will not be checked. 59 101 60 Any ``ValidationError`` raised in this method will be included in the61 ``message_dict`` under ``NON_FIELD_ERRORS``.62 102 63 103 Saving objects 64 104 ============== -
tests/modeltests/model_forms/models.py
diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py index ba59f9a..401f620 100644
a b True 1114 1114 1115 1115 >>> instance.delete() 1116 1116 1117 # Test the non-required FileField 1118 >>> f = TextFileForm(data={'description': u'Assistance'}) 1119 >>> f.fields['file'].required = False 1120 >>> f.is_valid() 1121 True 1122 >>> instance = f.save() 1123 >>> instance.file 1124 <FieldFile: None> 1125 1117 1126 >>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test3.txt', 'hello world')}, instance=instance) 1118 1127 >>> f.is_valid() 1119 1128 True … … True 1152 1161 >>> class BigIntForm(forms.ModelForm): 1153 1162 ... class Meta: 1154 1163 ... model = BigInt 1155 ... 1164 ... 1156 1165 >>> bif = BigIntForm({'biggie': '-9223372036854775808'}) 1157 1166 >>> bif.is_valid() 1158 1167 True … … False 1425 1434 >>> form._errors 1426 1435 {'__all__': [u'Price with this Price and Quantity already exists.']} 1427 1436 1428 # This form is never valid because quantity is blank=False. 1437 This Price instance generated by this form is not valid because the quantity 1438 field is required, but the form is valid because the field is excluded from 1439 the form. This is for backwards compatibility. 1440 1429 1441 >>> class PriceForm(ModelForm): 1430 1442 ... class Meta: 1431 1443 ... model = Price 1432 1444 ... exclude = ('quantity',) 1433 1445 >>> form = PriceForm({'price': '6.00'}) 1434 1446 >>> form.is_valid() 1447 True 1448 >>> price = form.save(commit=False) 1449 >>> price.full_clean() 1435 1450 Traceback (most recent call last): 1436 1451 ... 1437 UnresolvableValidationError: {'quantity': [u'This field cannot be null.']} 1452 ValidationError: {'quantity': [u'This field cannot be null.']} 1453 1454 The form should not validate fields that it doesn't contain even if they are 1455 specified using 'fields', not 'exclude'. 1456 ... class Meta: 1457 ... model = Price 1458 ... fields = ('price',) 1459 >>> form = PriceForm({'price': '6.00'}) 1460 >>> form.is_valid() 1461 True 1462 1463 The form should still have an instance of a model that is not complete and 1464 not saved into a DB yet. 1465 1466 >>> form.instance.price 1467 Decimal('6.00') 1468 >>> form.instance.quantity is None 1469 True 1470 >>> form.instance.pk is None 1471 True 1438 1472 1439 1473 # Unique & unique together with null values 1440 1474 >>> class BookForm(ModelForm): -
tests/modeltests/model_formsets/models.py
diff --git a/tests/modeltests/model_formsets/models.py b/tests/modeltests/model_formsets/models.py index 5eab202..702523e 100644
a b This is used in the admin for save_as functionality. 543 543 ... 'book_set-2-title': '', 544 544 ... } 545 545 546 >>> formset = AuthorBooksFormSet(data, instance=Author(), save_as_new=True) 547 >>> formset.is_valid() 548 True 549 546 550 >>> new_author = Author.objects.create(name='Charles Baudelaire') 547 551 >>> formset = AuthorBooksFormSet(data, instance=new_author, save_as_new=True) 548 552 >>> [book for book in formset.save() if book.author.pk == new_author.pk] … … False 1031 1035 >>> formset._non_form_errors 1032 1036 [u'Please correct the duplicate data for price and quantity, which must be unique.'] 1033 1037 1038 # Only the price field is specified, this should skip any unique checks since 1039 # the unique_together is not fulfilled. This will fail with a KeyError if broken. 1040 >>> FormSet = modelformset_factory(Price, fields=("price",), extra=2) 1041 >>> data = { 1042 ... 'form-TOTAL_FORMS': '2', 1043 ... 'form-INITIAL_FORMS': '0', 1044 ... 'form-0-price': '24', 1045 ... 'form-1-price': '24', 1046 ... } 1047 >>> formset = FormSet(data) 1048 >>> formset.is_valid() 1049 True 1050 1034 1051 >>> FormSet = inlineformset_factory(Author, Book, extra=0) 1035 1052 >>> author = Author.objects.order_by('id')[0] 1036 1053 >>> book_ids = author.book_set.values_list('id', flat=True) -
tests/modeltests/validation/models.py
diff --git a/tests/modeltests/validation/models.py b/tests/modeltests/validation/models.py index f1b0c51..017373c 100644
a b class ModelToValidate(models.Model): 17 17 url = models.URLField(blank=True) 18 18 f_with_custom_validator = models.IntegerField(blank=True, null=True, validators=[validate_answer_to_universe]) 19 19 20 def validate(self):21 super(ModelToValidate, self). validate()20 def clean(self): 21 super(ModelToValidate, self).clean() 22 22 if self.number == 11: 23 23 raise ValidationError('Invalid number supplied!') 24 24 … … class UniqueTogetherModel(models.Model): 36 36 efield = models.EmailField() 37 37 38 38 class Meta: 39 unique_together = (('ifield', 'cfield',), ('ifield', 'efield'),)39 unique_together = (('ifield', 'cfield',), ('ifield', 'efield')) 40 40 41 41 class UniqueForDateModel(models.Model): 42 42 start_date = models.DateField() … … class CustomMessagesModel(models.Model): 51 51 error_messages={'null': 'NULL', 'not42': 'AAARGH', 'not_equal': '%s != me'}, 52 52 validators=[validate_answer_to_universe] 53 53 ) 54 55 class Author(models.Model): 56 name = models.CharField(max_length=100) 57 58 class Article(models.Model): 59 title = models.CharField(max_length=100) 60 author = models.ForeignKey(Author) 61 pub_date = models.DateTimeField(blank=True) 62 63 def clean(self): 64 if self.pub_date is None: 65 self.pub_date = datetime.now() -
tests/modeltests/validation/test_custom_messages.py
diff --git a/tests/modeltests/validation/test_custom_messages.py b/tests/modeltests/validation/test_custom_messages.py index 9a958a0..05bb651 100644
a b from models import CustomMessagesModel 5 5 class CustomMessagesTest(ValidationTestCase): 6 6 def test_custom_simple_validator_message(self): 7 7 cmm = CustomMessagesModel(number=12) 8 self.assertFieldFailsValidationWithMessage(cmm.full_ validate, 'number', ['AAARGH'])8 self.assertFieldFailsValidationWithMessage(cmm.full_clean, 'number', ['AAARGH']) 9 9 10 10 def test_custom_null_message(self): 11 11 cmm = CustomMessagesModel() 12 self.assertFieldFailsValidationWithMessage(cmm.full_ validate, 'number', ['NULL'])12 self.assertFieldFailsValidationWithMessage(cmm.full_clean, 'number', ['NULL']) 13 13 -
tests/modeltests/validation/test_unique.py
diff --git a/tests/modeltests/validation/test_unique.py b/tests/modeltests/validation/test_unique.py index cbb56aa..8b24def 100644
a b 1 1 import unittest 2 import datetime 2 3 from django.conf import settings 3 4 from django.db import connection 4 5 from models import CustomPKModel, UniqueTogetherModel, UniqueFieldsModel, UniqueForDateModel, ModelToValidate … … class GetUniqueCheckTests(unittest.TestCase): 13 14 ) 14 15 15 16 def test_unique_together_gets_picked_up(self): 16 m = UniqueTogetherModel() 17 # Give the fields values, otherwise they won't be picked up in 18 # unique checks. 19 m = UniqueTogetherModel( 20 cfield='test', 21 ifield=1, 22 efield='test@example.com' 23 ) 17 24 self.assertEqual( 18 25 ([('ifield', 'cfield',),('ifield', 'efield'), ('id',), ], []), 19 26 m._get_unique_checks() … … class GetUniqueCheckTests(unittest.TestCase): 24 31 self.assertEqual(([('my_pk_field',)], []), m._get_unique_checks()) 25 32 26 33 def test_unique_for_date_gets_picked_up(self): 27 m = UniqueForDateModel() 34 # Give the fields values, otherwise they won't be picked up in 35 # unique checks. 36 m = UniqueForDateModel( 37 start_date=datetime.date(2010, 1, 9), 38 end_date=datetime.datetime(2010, 1, 9, 9, 0, 0), 39 count=1, 40 order=1, 41 name='test' 42 ) 28 43 self.assertEqual(( 29 30 44 [('id',)], 45 [('date', 'count', 'start_date'), ('year', 'count', 'end_date'), ('month', 'order', 'end_date')] 31 46 ), m._get_unique_checks() 32 47 ) 33 48 … … class PerformUniqueChecksTest(unittest.TestCase): 47 62 l = len(connection.queries) 48 63 mtv = ModelToValidate(number=10, name='Some Name') 49 64 setattr(mtv, '_adding', True) 50 mtv.full_ validate()65 mtv.full_clean() 51 66 self.assertEqual(l+1, len(connection.queries)) 52 67 53 68 def test_primary_key_unique_check_not_performed_when_not_adding(self): 54 69 """Regression test for #12132""" 55 70 l = len(connection.queries) 56 71 mtv = ModelToValidate(number=10, name='Some Name') 57 mtv.full_ validate()72 mtv.full_clean() 58 73 self.assertEqual(l, len(connection.queries)) 74 -
tests/modeltests/validation/tests.py
diff --git a/tests/modeltests/validation/tests.py b/tests/modeltests/validation/tests.py index c00070b..b3af77c 100644
a b 1 from django .core.exceptions import ValidationError, NON_FIELD_ERRORS2 from django. db import models3 1 from django import forms 2 from django.test import TestCase 3 from django.core.exceptions import NON_FIELD_ERRORS 4 4 from modeltests.validation import ValidationTestCase 5 from model s import *5 from modeltests.validation.models import Author, Article, ModelToValidate 6 6 7 from validators import TestModelsWithValidators 8 from test_unique import GetUniqueCheckTests, PerformUniqueChecksTest 9 from test_custom_messages import CustomMessagesTest 7 # Import other tests for this package. 8 from modeltests.validation.validators import TestModelsWithValidators 9 from modeltests.validation.test_unique import GetUniqueCheckTests, PerformUniqueChecksTest 10 from modeltests.validation.test_custom_messages import CustomMessagesTest 10 11 11 12 12 13 class BaseModelValidationTests(ValidationTestCase): 13 14 14 15 def test_missing_required_field_raises_error(self): 15 16 mtv = ModelToValidate(f_with_custom_validator=42) 16 self.assertFailsValidation(mtv.full_ validate, ['name', 'number'])17 self.assertFailsValidation(mtv.full_clean, ['name', 'number']) 17 18 18 19 def test_with_correct_value_model_validates(self): 19 20 mtv = ModelToValidate(number=10, name='Some Name') 20 self.assertEqual(None, mtv.full_ validate())21 self.assertEqual(None, mtv.full_clean()) 21 22 22 def test_custom_validate_method _is_called(self):23 def test_custom_validate_method(self): 23 24 mtv = ModelToValidate(number=11) 24 self.assertFailsValidation(mtv.full_ validate, [NON_FIELD_ERRORS, 'name'])25 self.assertFailsValidation(mtv.full_clean, [NON_FIELD_ERRORS, 'name']) 25 26 26 27 def test_wrong_FK_value_raises_error(self): 27 28 mtv=ModelToValidate(number=10, name='Some Name', parent_id=3) 28 self.assertFailsValidation(mtv.full_ validate, ['parent'])29 self.assertFailsValidation(mtv.full_clean, ['parent']) 29 30 30 31 def test_correct_FK_value_validates(self): 31 32 parent = ModelToValidate.objects.create(number=10, name='Some Name') 32 33 mtv=ModelToValidate(number=10, name='Some Name', parent_id=parent.pk) 33 self.assertEqual(None, mtv.full_ validate())34 self.assertEqual(None, mtv.full_clean()) 34 35 35 36 def test_wrong_email_value_raises_error(self): 36 37 mtv = ModelToValidate(number=10, name='Some Name', email='not-an-email') 37 self.assertFailsValidation(mtv.full_ validate, ['email'])38 self.assertFailsValidation(mtv.full_clean, ['email']) 38 39 39 40 def test_correct_email_value_passes(self): 40 41 mtv = ModelToValidate(number=10, name='Some Name', email='valid@email.com') 41 self.assertEqual(None, mtv.full_ validate())42 self.assertEqual(None, mtv.full_clean()) 42 43 43 44 def test_wrong_url_value_raises_error(self): 44 45 mtv = ModelToValidate(number=10, name='Some Name', url='not a url') 45 self.assertFieldFailsValidationWithMessage(mtv.full_ validate, 'url', [u'Enter a valid value.'])46 self.assertFieldFailsValidationWithMessage(mtv.full_clean, 'url', [u'Enter a valid value.']) 46 47 47 48 def test_correct_url_but_nonexisting_gives_404(self): 48 49 mtv = ModelToValidate(number=10, name='Some Name', url='http://google.com/we-love-microsoft.html') 49 self.assertFieldFailsValidationWithMessage(mtv.full_ validate, 'url', [u'This URL appears to be a broken link.'])50 self.assertFieldFailsValidationWithMessage(mtv.full_clean, 'url', [u'This URL appears to be a broken link.']) 50 51 51 52 def test_correct_url_value_passes(self): 52 53 mtv = ModelToValidate(number=10, name='Some Name', url='http://www.djangoproject.com/') 53 self.assertEqual(None, mtv.full_ validate()) # This will fail if there's no Internet connection54 self.assertEqual(None, mtv.full_clean()) # This will fail if there's no Internet connection 54 55 55 56 def test_text_greater_that_charfields_max_length_eaises_erros(self): 56 57 mtv = ModelToValidate(number=10, name='Some Name'*100) 57 self.assertFailsValidation(mtv.full_validate, ['name',]) 58 58 self.assertFailsValidation(mtv.full_clean, ['name',]) 59 60 class ArticleForm(forms.ModelForm): 61 class Meta: 62 model = Article 63 exclude = ['author'] 64 65 class ModelFormsTests(TestCase): 66 def setUp(self): 67 self.author = Author.objects.create(name='Joseph Kocherhans') 68 69 def test_partial_validation(self): 70 # Make sure the "commit=False and set field values later" idiom still 71 # works with model validation. 72 data = { 73 'title': 'The state of model validation', 74 'pub_date': '2010-1-10 14:49:00' 75 } 76 form = ArticleForm(data) 77 self.assertEqual(form.errors.keys(), []) 78 article = form.save(commit=False) 79 article.author = self.author 80 article.save() 81 82 def test_full_validation(self): 83 data = { 84 'title': 'The state of model validation', 85 'pub_date': '2010-1-10 14:49:00' 86 } 87 article = Article(author_id=self.author.id) 88 form = ArticleForm(data, instance=article, validate_model=True) 89 self.assertEqual(form.errors.keys(), []) 90 article = form.save() 91 92 def test_full_validation_with_empty_blank_field(self): 93 # Since a value for pub_date wasn't provided and the field is 94 # blank=True, model-validation should pass. 95 # Also, Article.clean() should be run since validate_model=True, so 96 # pub_date will be filled after validation, so the form should save 97 # cleanly even though pub_date is not allowed to be null. 98 data = { 99 'title': 'The state of model validation', 100 } 101 article = Article(author_id=self.author.id) 102 form = ArticleForm(data, instance=article, validate_model=True) 103 self.assertEqual(form.errors.keys(), []) 104 self.assertNotEqual(form.instance.pub_date, None) 105 article = form.save() 106 107 def test_full_validation_with_invalid_blank_field(self): 108 # Even though pub_date is set to blank=True, an invalid value was 109 # provided, so it should fail model validation. 110 data = { 111 'title': 'The state of model validation', 112 'pub_date': 'never' 113 } 114 article = Article(author_id=self.author.id) 115 form = ArticleForm(data, instance=article, validate_model=True) 116 self.assertEqual(form.errors.keys(), ['pub_date']) -
tests/modeltests/validation/validators.py
diff --git a/tests/modeltests/validation/validators.py b/tests/modeltests/validation/validators.py index dc4cd4e..3ad2c40 100644
a b from models import * 6 6 class TestModelsWithValidators(ValidationTestCase): 7 7 def test_custom_validator_passes_for_correct_value(self): 8 8 mtv = ModelToValidate(number=10, name='Some Name', f_with_custom_validator=42) 9 self.assertEqual(None, mtv.full_ validate())9 self.assertEqual(None, mtv.full_clean()) 10 10 11 11 def test_custom_validator_raises_error_for_incorrect_value(self): 12 12 mtv = ModelToValidate(number=10, name='Some Name', f_with_custom_validator=12) 13 self.assertFailsValidation(mtv.full_ validate, ['f_with_custom_validator'])13 self.assertFailsValidation(mtv.full_clean, ['f_with_custom_validator']) 14 14 self.assertFieldFailsValidationWithMessage( 15 mtv.full_ validate,15 mtv.full_clean, 16 16 'f_with_custom_validator', 17 17 [u'This is not the answer to life, universe and everything!'] 18 18 ) -
tests/regressiontests/admin_views/tests.py
diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py index 899fff8..351974b 100644
a b import re 4 4 import datetime 5 5 from django.core.files import temp as tempfile 6 6 from django.test import TestCase 7 from django.contrib.auth.models import User, Permission 7 from django.contrib.auth import admin # Register auth models with the admin. 8 from django.contrib.auth.models import User, Permission, UNUSABLE_PASSWORD 8 9 from django.contrib.contenttypes.models import ContentType 9 10 from django.contrib.admin.models import LogEntry, DELETION 10 11 from django.contrib.admin.sites import LOGIN_FORM_KEY … … class ReadonlyTest(TestCase): 1753 1754 self.assertEqual(Post.objects.count(), 2) 1754 1755 p = Post.objects.order_by('-id')[0] 1755 1756 self.assertEqual(p.posted, datetime.date.today()) 1757 1758 class IncompleteFormTest(TestCase): 1759 """ 1760 Tests validation of a ModelForm that doesn't explicitly have all data 1761 corresponding to model fields. Model validation shouldn't fail 1762 such a forms. 1763 """ 1764 fixtures = ['admin-views-users.xml'] 1765 1766 def setUp(self): 1767 self.client.login(username='super', password='secret') 1768 1769 def tearDown(self): 1770 self.client.logout() 1771 1772 def test_user_creation(self): 1773 response = self.client.post('/test_admin/admin/auth/user/add/', { 1774 'username': 'newuser', 1775 'password1': 'newpassword', 1776 'password2': 'newpassword', 1777 }) 1778 new_user = User.objects.order_by('-id')[0] 1779 self.assertRedirects(response, '/test_admin/admin/auth/user/%s/' % new_user.pk) 1780 self.assertNotEquals(new_user.password, UNUSABLE_PASSWORD) 1781 1782 def test_password_mismatch(self): 1783 response = self.client.post('/test_admin/admin/auth/user/add/', { 1784 'username': 'newuser', 1785 'password1': 'newpassword', 1786 'password2': 'mismatch', 1787 }) 1788 self.assertEquals(response.status_code, 200) 1789 self.assert_('password' not in response.context['form'].errors) 1790 self.assertFormError(response, 'form', 'password2', ["The two password fields didn't match."]) -
tests/regressiontests/inline_formsets/tests.py
diff --git a/tests/regressiontests/inline_formsets/tests.py b/tests/regressiontests/inline_formsets/tests.py index be313f3..aef6b3f 100644
a b class DeletionTests(TestCase): 81 81 regression for #10750 82 82 """ 83 83 # exclude some required field from the forms 84 ChildFormSet = inlineformset_factory(School, Child )84 ChildFormSet = inlineformset_factory(School, Child, exclude=['father', 'mother']) 85 85 school = School.objects.create(name=u'test') 86 86 mother = Parent.objects.create(name=u'mother') 87 87 father = Parent.objects.create(name=u'father') … … class DeletionTests(TestCase): 89 89 'child_set-TOTAL_FORMS': u'1', 90 90 'child_set-INITIAL_FORMS': u'0', 91 91 'child_set-0-name': u'child', 92 'child_set-0-mother': unicode(mother.pk),93 'child_set-0-father': unicode(father.pk),94 92 } 95 93 formset = ChildFormSet(data, instance=school) 96 94 self.assertEqual(formset.is_valid(), True) 97 95 objects = formset.save(commit=False) 98 self.assertEqual(school.child_set.count(), 0) 99 objects[0].save() 96 for obj in objects: 97 obj.mother = mother 98 obj.father = father 99 obj.save() 100 100 self.assertEqual(school.child_set.count(), 1) 101 101