Permalink
Browse files

Merged soc2009/model-validation to trunk. Thanks, Honza!

git-svn-id: http://code.djangoproject.com/svn/django/trunk@12098 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
1 parent 4e89105 commit 471596fc1afcb9c6258d317c619eaf5fd394e797 @jkocherhans jkocherhans committed Jan 5, 2010
Showing with 1,549 additions and 638 deletions.
  1. +1 −0 AUTHORS
  2. +11 −5 django/contrib/admin/options.py
  3. +8 −8 django/contrib/auth/forms.py
  4. +16 −8 django/contrib/contenttypes/generic.py
  5. +2 −1 django/contrib/localflavor/ar/forms.py
  6. +3 −2 django/contrib/localflavor/au/forms.py
  7. +2 −1 django/contrib/localflavor/br/forms.py
  8. +3 −2 django/contrib/localflavor/ca/forms.py
  9. +2 −1 django/contrib/localflavor/ch/forms.py
  10. +2 −1 django/contrib/localflavor/cl/forms.py
  11. +2 −1 django/contrib/localflavor/cz/forms.py
  12. +2 −1 django/contrib/localflavor/de/forms.py
  13. +2 −1 django/contrib/localflavor/es/forms.py
  14. +2 −1 django/contrib/localflavor/fi/forms.py
  15. +2 −1 django/contrib/localflavor/fr/forms.py
  16. +2 −1 django/contrib/localflavor/id/forms.py
  17. +2 −1 django/contrib/localflavor/in_/forms.py
  18. +2 −1 django/contrib/localflavor/is_/forms.py
  19. +2 −1 django/contrib/localflavor/it/forms.py
  20. +3 −1 django/contrib/localflavor/kw/forms.py
  21. +2 −1 django/contrib/localflavor/nl/forms.py
  22. +2 −1 django/contrib/localflavor/no/forms.py
  23. +2 −1 django/contrib/localflavor/pe/forms.py
  24. +2 −1 django/contrib/localflavor/pt/forms.py
  25. +1 −1 django/contrib/localflavor/ro/forms.py
  26. +1 −1 django/contrib/localflavor/se/forms.py
  27. +2 −1 django/contrib/localflavor/us/forms.py
  28. +2 −1 django/contrib/localflavor/uy/forms.py
  29. +2 −1 django/contrib/localflavor/za/forms.py
  30. +37 −1 django/core/exceptions.py
  31. +137 −0 django/core/validators.py
  32. +178 −1 django/db/models/base.py
  33. +174 −69 django/db/models/fields/__init__.py
  34. +27 −6 django/db/models/fields/related.py
  35. +1 −1 django/forms/__init__.py
  36. +169 −205 django/forms/fields.py
  37. +2 −1 django/forms/forms.py
  38. +2 −1 django/forms/formsets.py
  39. +59 −172 django/forms/models.py
  40. +5 −19 django/forms/util.py
  41. +11 −0 docs/ref/forms/fields.txt
  42. +87 −26 docs/ref/forms/validation.txt
  43. +22 −0 docs/ref/models/fields.txt
  44. +25 −0 docs/ref/models/instances.txt
  45. +48 −35 tests/modeltests/model_forms/models.py
  46. +0 −17 tests/modeltests/model_formsets/models.py
  47. +21 −0 tests/modeltests/validation/__init__.py
  48. +53 −0 tests/modeltests/validation/models.py
  49. +13 −0 tests/modeltests/validation/test_custom_messages.py
  50. +58 −0 tests/modeltests/validation/test_unique.py
  51. +58 −0 tests/modeltests/validation/tests.py
  52. +18 −0 tests/modeltests/validation/validators.py
  53. +146 −0 tests/modeltests/validators/tests.py
  54. +12 −12 tests/regressiontests/forms/error_messages.py
  55. +5 −1 tests/regressiontests/forms/fields.py
  56. +4 −4 tests/regressiontests/forms/localflavor/ar.py
  57. +5 −5 tests/regressiontests/forms/localflavor/is_.py
  58. +1 −0 tests/regressiontests/forms/tests.py
  59. +9 −8 tests/regressiontests/forms/util.py
  60. +17 −0 tests/regressiontests/forms/validators.py
  61. +5 −5 tests/regressiontests/inline_formsets/tests.py
  62. +52 −0 tests/regressiontests/model_fields/tests.py
  63. +1 −1 tests/regressiontests/views/views.py
View
@@ -254,6 +254,7 @@ answer newbie questions, and generally made Django that much better:
Gasper Koren
Martin Kosír <martin@martinkosir.net>
Arthur Koziel <http://arthurkoziel.com>
+ Honza Kral <honza.kral@gmail.com>
Meir Kriheli <http://mksoft.co.il/>
Bruce Kroeze <http://coderseye.com/>
krzysiek.pawlik@silvermedia.pl
@@ -578,12 +578,12 @@ def message_user(self, request, message):
"""
messages.info(request, message)
- def save_form(self, request, form, change):
+ def save_form(self, request, form, change, commit=False):
"""
Given a ModelForm return an unsaved instance. ``change`` is True if
the object is being changed, and False if it's being added.
"""
- return form.save(commit=False)
+ return form.save(commit=commit)
def save_model(self, request, obj, form, change):
"""
@@ -757,8 +757,12 @@ def add_view(self, request, form_url='', extra_context=None):
if request.method == 'POST':
form = ModelForm(request.POST, request.FILES)
if form.is_valid():
+ # Save the object, even if inline formsets haven't been
+ # validated yet. We need to pass the valid model to the
+ # formsets for validation. If the formsets do not validate, we
+ # will delete the object.
+ new_object = self.save_form(request, form, change=False, commit=True)
form_validated = True
- new_object = self.save_form(request, form, change=False)
else:
form_validated = False
new_object = self.model()
@@ -774,13 +778,15 @@ def add_view(self, request, form_url='', extra_context=None):
prefix=prefix, queryset=inline.queryset(request))
formsets.append(formset)
if all_valid(formsets) and form_validated:
- self.save_model(request, new_object, form, change=False)
- form.save_m2m()
for formset in formsets:
self.save_formset(request, form, formset, change=False)
self.log_addition(request, new_object)
return self.response_add(request, new_object)
+ elif form_validated:
+ # The form was valid, but formsets were not, so delete the
+ # object we saved above.
+ new_object.delete()
else:
# Prepare the dict of initial data from the request.
# We have to special-case M2Ms as a list of comma-separated PKs.
@@ -1,4 +1,4 @@
-from django.contrib.auth.models import User
+from django.contrib.auth.models import User, UNUSABLE_PASSWORD
from django.contrib.auth import authenticate
from django.contrib.auth.tokens import default_token_generator
from django.contrib.sites.models import Site
@@ -21,6 +21,12 @@ class Meta:
model = User
fields = ("username",)
+ def clean(self):
+ # Fill the password field so model validation won't complain about it
+ # being blank. We'll set it with the real value below.
+ self.instance.password = UNUSABLE_PASSWORD
+ super(UserCreationForm, self).clean()
+
def clean_username(self):
username = self.cleaned_data["username"]
try:
@@ -34,15 +40,9 @@ def clean_password2(self):
password2 = self.cleaned_data["password2"]
if password1 != password2:
raise forms.ValidationError(_("The two password fields didn't match."))
+ self.instance.set_password(password1)
return password2
- def save(self, commit=True):
- user = super(UserCreationForm, self).save(commit=False)
- user.set_password(self.cleaned_data["password1"])
- if commit:
- user.save()
- return user
-
class UserChangeForm(forms.ModelForm):
username = forms.RegexField(label=_("Username"), max_length=30, regex=r'^\w+$',
help_text = _("Required. 30 characters or fewer. Alphanumeric characters only (letters, digits and underscores)."),
@@ -297,7 +297,11 @@ def __init__(self, data=None, files=None, instance=None, save_as_new=None,
# Avoid a circular import.
from django.contrib.contenttypes.models import ContentType
opts = self.model._meta
- self.instance = instance
+ if instance is None:
+ self.instance = self.model()
+ else:
+ self.instance = instance
+ self.save_as_new = save_as_new
self.rel_name = '-'.join((
opts.app_label, opts.object_name.lower(),
self.ct_field.name, self.ct_fk_field.name,
@@ -324,15 +328,19 @@ def get_default_prefix(cls):
))
get_default_prefix = classmethod(get_default_prefix)
- def save_new(self, form, commit=True):
+ def _construct_form(self, i, **kwargs):
# Avoid a circular import.
from django.contrib.contenttypes.models import ContentType
- kwargs = {
- self.ct_field.get_attname(): ContentType.objects.get_for_model(self.instance).pk,
- self.ct_fk_field.get_attname(): self.instance.pk,
- }
- new_obj = self.model(**kwargs)
- return save_instance(form, new_obj, commit=commit)
+ form = super(BaseGenericInlineFormSet, self)._construct_form(i, **kwargs)
+ if self.save_as_new:
+ # Remove the key from the form's data, we are only creating new instances.
+ form.data[form.add_prefix(self.ct_fk_field.name)] = None
+ form.data[form.add_prefix(self.ct_field.name)] = None
+
+ # Set the GenericForeignKey value here so that the form can do its validation.
+ setattr(form.instance, self.ct_fk_field.attname, self.instance.pk)
+ setattr(form.instance, self.ct_field.attname, ContentType.objects.get_for_model(self.instance).pk)
+ return form
def generic_inlineformset_factory(model, form=ModelForm,
formset=BaseGenericInlineFormSet,
@@ -4,7 +4,8 @@
"""
from django.forms import ValidationError
-from django.forms.fields import RegexField, CharField, Select, EMPTY_VALUES
+from django.core.validators import EMPTY_VALUES
+from django.forms.fields import RegexField, CharField, Select
from django.utils.encoding import smart_unicode
from django.utils.translation import ugettext_lazy as _
@@ -2,9 +2,10 @@
Australian-specific Form helpers
"""
+from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
-from django.forms.fields import Field, RegexField, Select, EMPTY_VALUES
-from django.forms.util import smart_unicode
+from django.forms.fields import Field, RegexField, Select
+from django.utils.encoding import smart_unicode
from django.utils.translation import ugettext_lazy as _
import re
@@ -3,8 +3,9 @@
BR-specific Form helpers
"""
+from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
-from django.forms.fields import Field, RegexField, CharField, Select, EMPTY_VALUES
+from django.forms.fields import Field, RegexField, CharField, Select
from django.utils.encoding import smart_unicode
from django.utils.translation import ugettext_lazy as _
import re
@@ -2,9 +2,10 @@
Canada-specific Form helpers
"""
+from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
-from django.forms.fields import Field, RegexField, Select, EMPTY_VALUES
-from django.forms.util import smart_unicode
+from django.forms.fields import Field, RegexField, Select
+from django.utils.encoding import smart_unicode
from django.utils.translation import ugettext_lazy as _
import re
@@ -2,8 +2,9 @@
Swiss-specific Form helpers
"""
+from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
-from django.forms.fields import Field, RegexField, Select, EMPTY_VALUES
+from django.forms.fields import Field, RegexField, Select
from django.utils.encoding import smart_unicode
from django.utils.translation import ugettext_lazy as _
import re
@@ -2,8 +2,9 @@
Chile specific form helpers.
"""
+from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
-from django.forms.fields import RegexField, Select, EMPTY_VALUES
+from django.forms.fields import RegexField, Select
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_unicode
@@ -2,8 +2,9 @@
Czech-specific form helpers
"""
+from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
-from django.forms.fields import Select, RegexField, Field, EMPTY_VALUES
+from django.forms.fields import Select, RegexField, Field
from django.utils.translation import ugettext_lazy as _
import re
@@ -2,8 +2,9 @@
DE-specific Form helpers
"""
+from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
-from django.forms.fields import Field, RegexField, Select, EMPTY_VALUES
+from django.forms.fields import Field, RegexField, Select
from django.utils.translation import ugettext_lazy as _
import re
@@ -3,8 +3,9 @@
Spanish-specific Form helpers
"""
+from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
-from django.forms.fields import RegexField, Select, EMPTY_VALUES
+from django.forms.fields import RegexField, Select
from django.utils.translation import ugettext_lazy as _
import re
@@ -3,8 +3,9 @@
"""
import re
+from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
-from django.forms.fields import Field, RegexField, Select, EMPTY_VALUES
+from django.forms.fields import Field, RegexField, Select
from django.utils.translation import ugettext_lazy as _
class FIZipCodeField(RegexField):
@@ -2,8 +2,9 @@
FR-specific Form helpers
"""
+from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
-from django.forms.fields import Field, RegexField, Select, EMPTY_VALUES
+from django.forms.fields import Field, RegexField, Select
from django.utils.encoding import smart_unicode
from django.utils.translation import ugettext_lazy as _
import re
@@ -5,8 +5,9 @@
import re
import time
+from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
-from django.forms.fields import Field, Select, EMPTY_VALUES
+from django.forms.fields import Field, Select
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_unicode
@@ -2,8 +2,9 @@
India-specific Form helpers.
"""
+from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
-from django.forms.fields import Field, RegexField, Select, EMPTY_VALUES
+from django.forms.fields import Field, RegexField, Select
from django.utils.encoding import smart_unicode
from django.utils.translation import gettext
import re
@@ -2,8 +2,9 @@
Iceland specific form helpers.
"""
+from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
-from django.forms.fields import RegexField, EMPTY_VALUES
+from django.forms.fields import RegexField
from django.forms.widgets import Select
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_unicode
@@ -2,8 +2,9 @@
IT-specific Form helpers
"""
+from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
-from django.forms.fields import Field, RegexField, Select, EMPTY_VALUES
+from django.forms.fields import Field, RegexField, Select
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_unicode
from django.contrib.localflavor.it.util import ssn_check_digit, vat_number_check_digit
@@ -3,8 +3,10 @@
"""
import re
from datetime import date
+
+from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
-from django.forms.fields import Field, RegexField, EMPTY_VALUES
+from django.forms.fields import Field, RegexField
from django.utils.translation import gettext as _
id_re = re.compile(r'^(?P<initial>\d{1})(?P<yy>\d\d)(?P<mm>\d\d)(?P<dd>\d\d)(?P<mid>\d{4})(?P<checksum>\d{1})')
@@ -4,8 +4,9 @@
import re
+from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
-from django.forms.fields import Field, Select, EMPTY_VALUES
+from django.forms.fields import Field, Select
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_unicode
@@ -3,8 +3,9 @@
"""
import re, datetime
+from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
-from django.forms.fields import Field, RegexField, Select, EMPTY_VALUES
+from django.forms.fields import Field, RegexField, Select
from django.utils.translation import ugettext_lazy as _
class NOZipCodeField(RegexField):
@@ -3,8 +3,9 @@
PE-specific Form helpers.
"""
+from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
-from django.forms.fields import RegexField, CharField, Select, EMPTY_VALUES
+from django.forms.fields import RegexField, CharField, Select
from django.utils.translation import ugettext_lazy as _
class PERegionSelect(Select):
@@ -2,8 +2,9 @@
PT-specific Form helpers
"""
+from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
-from django.forms.fields import Field, RegexField, Select, EMPTY_VALUES
+from django.forms.fields import Field, RegexField, Select
from django.utils.encoding import smart_unicode
from django.utils.translation import ugettext_lazy as _
import re
@@ -5,8 +5,8 @@
import re
+from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError, Field, RegexField, Select
-from django.forms.fields import EMPTY_VALUES
from django.utils.translation import ugettext_lazy as _
class ROCIFField(RegexField):
@@ -5,7 +5,7 @@
import re
from django import forms
from django.utils.translation import ugettext_lazy as _
-from django.forms.fields import EMPTY_VALUES
+from django.core.validators import EMPTY_VALUES
from django.contrib.localflavor.se.utils import (id_number_checksum,
validate_id_birthday, format_personal_id_number, valid_organisation,
format_organisation_number)
@@ -2,8 +2,9 @@
USA-specific Form helpers
"""
+from django.core.validators import EMPTY_VALUES
from django.forms import ValidationError
-from django.forms.fields import Field, RegexField, Select, EMPTY_VALUES, CharField
+from django.forms.fields import Field, RegexField, Select, CharField
from django.utils.encoding import smart_unicode
from django.utils.translation import ugettext_lazy as _
import re
@@ -4,7 +4,8 @@
"""
import re
-from django.forms.fields import Select, RegexField, EMPTY_VALUES
+from django.core.validators import EMPTY_VALUES
+from django.forms.fields import Select, RegexField
from django.forms import ValidationError
from django.utils.translation import ugettext_lazy as _
from django.contrib.localflavor.uy.util import get_validation_digit
Oops, something went wrong. Retry.

0 comments on commit 471596f

Please sign in to comment.