Ticket #12521: 12521.diff
File 12521.diff, 18.9 KB (added by , 15 years ago) |
---|
-
django/contrib/auth/forms.py
diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py index dbc55ca..e9a7fb2 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): 43 37 self.instance.set_password(password1) 44 38 return password2 45 39 40 def save(self, *args, **kwargs): 41 self.instance.set_password(self.cleaned_data["password1"]) 42 return super(UserCreationForm, self).save(*args, **kwargs) 43 46 44 class UserChangeForm(forms.ModelForm): 47 45 username = forms.RegexField(label=_("Username"), max_length=30, regex=r'^\w+$', 48 46 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..29da67c 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): 63 63 if hasattr(self, 'message_dict'): 64 64 return repr(self.message_dict) 65 65 return repr(self.messages) 66 67 class ValidationError(BaseValidationError):68 pass69 70 class UnresolvableValidationError(BaseValidationError):71 """Validation error that cannot be resolved by the user."""72 pass73 -
django/db/models/base.py
diff --git a/django/db/models/base.py b/django/db/models/base.py index 06db7cc..cfe7fec 100644
a b class Model(object): 649 649 not be associated with a particular field; it will have a special-case 650 650 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 if exclude is None: 656 exclude = [] 657 unique_checks, date_checks = self._get_unique_checks(exclude) 656 658 657 659 errors = self._perform_unique_checks(unique_checks) 658 660 date_errors = self._perform_date_checks(date_checks) … … class Model(object): 663 665 if errors: 664 666 raise ValidationError(errors) 665 667 666 def _get_unique_checks(self): 667 from django.db.models.fields import FieldDoesNotExist, Field as ModelField 668 def _get_unique_checks(self, exclude=None): 669 if exclude is None: 670 exclude = [] 671 unique_checks = [] 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. It also does not make sense to check data that didn't 676 # validate, and since NULL does not equal NULL in SQL we should not do 677 # any unique checking for NULL values. 678 for check in self._meta.unique_together: 679 for name in check: 680 # If this is an excluded field, short circuit and don't a unique_check. 681 if name in exclude: 682 break 683 # Also, Skip fields that don't have a value, we can't check for 684 # their uniqueness. 685 if getattr(self, name, None) is None: 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 694 # the list of checks. Again, skip empty fields and any that did not validate. 675 695 for f in self._meta.fields: 676 696 name = f.name 697 # Don't add excluded fields to unique for date checks. 698 if name in exclude: 699 continue 677 700 if f.unique: 678 701 unique_checks.append((name,)) 679 702 if f.unique_for_date: … … class Model(object): 684 707 date_checks.append(('month', name, f.unique_for_month)) 685 708 return unique_checks, date_checks 686 709 687 688 710 def _perform_unique_checks(self, unique_checks): 689 711 errors = {} 690 712 … … class Model(object): 781 803 'field_label': unicode(field_labels) 782 804 } 783 805 784 def full_validate(self, exclude= []):806 def full_validate(self, exclude=None): 785 807 """ 786 808 Cleans all fields and raises ValidationError containing message_dict 787 809 of all validation errors if any occur. 788 810 """ 811 if exclude is None: 812 exclude = [] 789 813 errors = {} 790 814 for f in self._meta.fields: 791 815 if f.name in exclude: … … class Model(object): 795 819 except ValidationError, e: 796 820 errors[f.name] = e.messages 797 821 798 # Form.clean() is run even if other validation fails, so do the799 # same with Model.validate() for consistency.800 822 try: 801 self.validate ()823 self.validate_unique(exclude=exclude.extend(errors.keys())) 802 824 except ValidationError, e: 803 825 if hasattr(e, 'message_dict'): 804 826 if errors: 805 827 for k, v in e.message_dict.items(): 806 errors.set _default(k, []).extend(v)828 errors.setdefault(k, []).extend(v) 807 829 else: 808 830 errors = e.message_dict 809 831 else: 810 832 errors[NON_FIELD_ERRORS] = e.messages 811 833 834 # Form.clean() is run even if other validation fails, so do the 835 # same with Model.validate() for consistency. 836 # However, do not run Model.validate() on incomplete forms when 837 # creating new instance. 838 if not (exclude and getattr(self, '_adding', True)): 839 try: 840 self.validate() 841 except ValidationError, e: 842 if hasattr(e, 'message_dict'): 843 if errors: 844 for k, v in e.message_dict.items(): 845 errors.setdefault(k, []).extend(v) 846 else: 847 errors = e.message_dict 848 else: 849 errors[NON_FIELD_ERRORS] = e.messages 850 812 851 if errors: 813 852 raise ValidationError(errors) 814 853 -
django/forms/models.py
diff --git a/django/forms/models.py b/django/forms/models.py index ff20c93..5435f2a 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, 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 BaseModelForm(BaseForm): 249 249 opts = self._meta 250 250 self.instance = construct_instance(self, self.instance, opts.fields, opts.exclude) 251 251 try: 252 self.instance.full_validate(exclude=self._errors.keys()) 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 exclude = [] 256 for f in self.instance._meta.fields: 257 field = f.name 258 # Exclude fields that aren't on the form. The developer may be 259 # adding these values to the model after form validation. 260 if field not in self.fields: 261 exclude.append(field) 262 # Exclude fields that failed form validation. 263 elif field in self._errors.keys(): 264 exclude.append(field) 265 # Exclude empty fields that are not required by the form. Model 266 # validation might complain that they are null, but the 267 # developer is reponsible for setting their value after calling 268 # form validation.. 269 elif ((not self.fields[field].required) and 270 self.cleaned_data.get(field, None) in EMPTY_VALUES): 271 exclude.append(field) 272 self.instance.full_validate(exclude=exclude) 253 273 except ValidationError, e: 254 274 for k, v in e.message_dict.items(): 255 275 if k != NON_FIELD_ERRORS: 256 276 self._errors.setdefault(k, ErrorList()).extend(v) 257 258 277 # Remove the data from the cleaned_data dict since it was invalid 259 278 if k in self.cleaned_data: 260 279 del self.cleaned_data[k] 261 262 280 if NON_FIELD_ERRORS in e.message_dict: 263 281 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 282 return self.cleaned_data 274 283 275 284 def save(self, commit=True): -
tests/modeltests/model_forms/models.py
diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py index ba59f9a..cb2aa14 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_validate() 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..f41908b 100644
a b False 1031 1031 >>> formset._non_form_errors 1032 1032 [u'Please correct the duplicate data for price and quantity, which must be unique.'] 1033 1033 1034 # Only the price field is specified, this should skip any unique checks since 1035 # the unique_together is not fulfilled. This will fail with a KeyError if broken. 1036 >>> FormSet = modelformset_factory(Price, fields=("price",), extra=2) 1037 >>> data = { 1038 ... 'form-TOTAL_FORMS': '2', 1039 ... 'form-INITIAL_FORMS': '0', 1040 ... 'form-0-price': '24', 1041 ... 'form-1-price': '24', 1042 ... } 1043 >>> formset = FormSet(data) 1044 >>> formset.is_valid() 1045 True 1046 1034 1047 >>> FormSet = inlineformset_factory(Author, Book, extra=0) 1035 1048 >>> author = Author.objects.order_by('id')[0] 1036 1049 >>> book_ids = author.book_set.values_list('id', flat=True) -
tests/modeltests/validation/test_unique.py
diff --git a/tests/modeltests/validation/test_unique.py b/tests/modeltests/validation/test_unique.py index cbb56aa..3aea99d 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): 56 71 mtv = ModelToValidate(number=10, name='Some Name') 57 72 mtv.full_validate() 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..7bf3994 100644
a b class BaseModelValidationTests(ValidationTestCase): 19 19 mtv = ModelToValidate(number=10, name='Some Name') 20 20 self.assertEqual(None, mtv.full_validate()) 21 21 22 def test_custom_validate_method _is_called(self):22 def test_custom_validate_method(self): 23 23 mtv = ModelToValidate(number=11) 24 self.assertFailsValidation(mtv.full_validate, [NON_FIELD_ERRORS, 'name']) 24 # model.validate() will not be called on unsaved models that otherwise 25 # fail validation. 26 self.assertFailsValidation(mtv.full_validate, ['name']) 27 mtv.name = 'test' 28 # model.validate() *should* be called if the model otherwise *does* validate 29 self.assertFailsValidation(mtv.full_validate, [NON_FIELD_ERRORS]) 25 30 26 31 def test_wrong_FK_value_raises_error(self): 27 32 mtv=ModelToValidate(number=10, name='Some Name', parent_id=3) -
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."])