diff options
| author | Adrian Holovaty <adrian@holovaty.com> | 2007-04-09 01:33:23 +0000 |
|---|---|---|
| committer | Adrian Holovaty <adrian@holovaty.com> | 2007-04-09 01:33:23 +0000 |
| commit | 9963ce79b9560b6109ef917944fb30e6336435c5 (patch) | |
| tree | c975585a317e560aa96705ec76f5a0936b31bf21 | |
| parent | 203f93a7aa9fbe04fa660c262ed2e730de437faf (diff) | |
newforms-admin: Merged to [4961]
git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@4962 bcc190cf-cafb-0310-a4f2-bffc1f526a37
| -rw-r--r-- | AUTHORS | 1 | ||||
| -rw-r--r-- | django/contrib/localflavor/au/__init__.py (renamed from django/contrib/localflavor/usa/__init__.py) | 0 | ||||
| -rw-r--r-- | django/contrib/localflavor/au/au_states.py | 17 | ||||
| -rw-r--r-- | django/contrib/localflavor/au/forms.py | 43 | ||||
| -rw-r--r-- | django/contrib/localflavor/us/__init__.py | 0 | ||||
| -rw-r--r-- | django/contrib/localflavor/us/forms.py (renamed from django/contrib/localflavor/usa/forms.py) | 0 | ||||
| -rw-r--r-- | django/contrib/localflavor/us/us_states.py (renamed from django/contrib/localflavor/usa/us_states.py) | 0 | ||||
| -rw-r--r-- | django/db/models/fields/__init__.py | 2 | ||||
| -rw-r--r-- | django/newforms/widgets.py | 6 | ||||
| -rw-r--r-- | django/views/debug.py | 3 | ||||
| -rw-r--r-- | docs/documentation.txt | 34 | ||||
| -rw-r--r-- | docs/modpython.txt | 9 | ||||
| -rw-r--r-- | docs/request_response.txt | 4 | ||||
| -rw-r--r-- | tests/modeltests/model_forms/models.py | 10 | ||||
| -rw-r--r-- | tests/regressiontests/forms/localflavor.py | 140 | ||||
| -rw-r--r-- | tests/regressiontests/forms/tests.py | 26 |
16 files changed, 242 insertions, 53 deletions
@@ -88,6 +88,7 @@ answer newbie questions, and generally made Django that much better: Dirk Eschler <dirk.eschler@gmx.net> Marc Fargas <telenieko@telenieko.com> favo@exoweb.net + Matthew Flanagan <http://wadofstuff.blogspot.com> Eric Floehr <eric@intellovations.com> Jorge Gajon <gajon@gajon.org> gandalf@owca.info diff --git a/django/contrib/localflavor/usa/__init__.py b/django/contrib/localflavor/au/__init__.py index e69de29bb2..e69de29bb2 100644 --- a/django/contrib/localflavor/usa/__init__.py +++ b/django/contrib/localflavor/au/__init__.py diff --git a/django/contrib/localflavor/au/au_states.py b/django/contrib/localflavor/au/au_states.py new file mode 100644 index 0000000000..578d61bb01 --- /dev/null +++ b/django/contrib/localflavor/au/au_states.py @@ -0,0 +1,17 @@ +""" +An alphabetical list of states for use as `choices` in a formfield. + +This exists in this standalone file so that it's only imported into memory +when explicitly needed. +""" + +STATE_CHOICES = ( + ('ACT', 'Australian Capital Territory'), + ('NSW', 'New South Wales'), + ('NT', 'Northern Territory'), + ('QLD', 'Queensland'), + ('SA', 'South Australia'), + ('TAS', 'Tasmania'), + ('VIC', 'Victoria'), + ('WA', 'Western Australia'), +) diff --git a/django/contrib/localflavor/au/forms.py b/django/contrib/localflavor/au/forms.py new file mode 100644 index 0000000000..b81a903d13 --- /dev/null +++ b/django/contrib/localflavor/au/forms.py @@ -0,0 +1,43 @@ +""" +Australian-specific Form helpers +""" + +from django.newforms import ValidationError +from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES +from django.newforms.util import smart_unicode +from django.utils.translation import gettext +import re + +PHONE_DIGITS_RE = re.compile(r'^(\d{10})$') + +class AUPostCodeField(RegexField): + """Australian post code field.""" + def __init__(self, *args, **kwargs): + super(AUPostCodeField, self).__init__(r'^\d{4}$', + max_length=None, min_length=None, + error_message=gettext(u'Enter a 4 digit post code.'), + *args, **kwargs) + +class AUPhoneNumberField(Field): + """Australian phone number field.""" + def clean(self, value): + """Validate a phone number. Strips parentheses, whitespace and + hyphens. + """ + super(AUPhoneNumberField, self).clean(value) + if value in EMPTY_VALUES: + return u'' + value = re.sub('(\(|\)|\s+|-)', '', smart_unicode(value)) + phone_match = PHONE_DIGITS_RE.search(value) + if phone_match: + return u'%s' % phone_match.group(1) + raise ValidationError(u'Phone numbers must contain 10 digits.') + +class AUStateSelect(Select): + """ + A Select widget that uses a list of Australian states/territories as its + choices. + """ + def __init__(self, attrs=None): + from au_states import STATE_CHOICES # relative import + super(AUStateSelect, self).__init__(attrs, choices=STATE_CHOICES) diff --git a/django/contrib/localflavor/us/__init__.py b/django/contrib/localflavor/us/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/django/contrib/localflavor/us/__init__.py diff --git a/django/contrib/localflavor/usa/forms.py b/django/contrib/localflavor/us/forms.py index feda68291b..feda68291b 100644 --- a/django/contrib/localflavor/usa/forms.py +++ b/django/contrib/localflavor/us/forms.py diff --git a/django/contrib/localflavor/usa/us_states.py b/django/contrib/localflavor/us/us_states.py index 89124a4b69..89124a4b69 100644 --- a/django/contrib/localflavor/usa/us_states.py +++ b/django/contrib/localflavor/us/us_states.py diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index f46722be47..ccbe6d858c 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -763,7 +763,7 @@ class PhoneNumberField(IntegerField): validators.isValidPhone(field_data, all_data) def formfield(self, **kwargs): - from django.contrib.localflavor.usa.forms import USPhoneNumberField + from django.contrib.localflavor.us.forms import USPhoneNumberField defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text} defaults.update(kwargs) return USPhoneNumberField(**defaults) diff --git a/django/newforms/widgets.py b/django/newforms/widgets.py index 8d292673a5..f701faa35d 100644 --- a/django/newforms/widgets.py +++ b/django/newforms/widgets.py @@ -121,6 +121,12 @@ class FileInput(Input): input_type = 'file' class Textarea(Widget): + def __init__(self, attrs=None): + # The 'rows' and 'cols' attributes are required for HTML correctness. + self.attrs = {'cols': '40', 'rows': '10'} + if attrs: + self.attrs.update(attrs) + def render(self, name, value, attrs=None): if value is None: value = '' value = smart_unicode(value) diff --git a/django/views/debug.py b/django/views/debug.py index 77b6c2fac2..b49a98a864 100644 --- a/django/views/debug.py +++ b/django/views/debug.py @@ -144,6 +144,7 @@ def technical_404_response(request, exception): t = Template(TECHNICAL_404_TEMPLATE, name='Technical 404 template') c = Context({ 'root_urlconf': settings.ROOT_URLCONF, + 'request_path': request.path[1:], # Trim leading slash 'urlpatterns': tried, 'reason': str(exception), 'request': request, @@ -591,7 +592,7 @@ TECHNICAL_404_TEMPLATE = """ <li>{{ pattern|escape }}</li> {% endfor %} </ol> - <p>The current URL, <code>{{ request.path|escape }}</code>, didn't match any of these.</p> + <p>The current URL, <code>{{ request_path|escape }}</code>, didn't match any of these.</p> {% else %} <p>{{ reason|escape }}</p> {% endif %} diff --git a/docs/documentation.txt b/docs/documentation.txt index bacfb176b1..e72dd47ba1 100644 --- a/docs/documentation.txt +++ b/docs/documentation.txt @@ -42,25 +42,25 @@ On the Web The most recent version of the Django documentation lives at http://www.djangoproject.com/documentation/ . These HTML pages are generated -automatically from the text files in source control every 15 minutes. That -means they reflect the "latest and greatest" in Django -- they include the very -latest corrections and additions, and they discuss the latest Django features, +automatically from the text files in source control. That means they reflect +the "latest and greatest" in Django -- they include the very latest +corrections and additions, and they discuss the latest Django features, which may only be available to users of the Django development version. (See "Differences between versions" below.) -A key advantage of the Web-based documentation is the comment section at the -bottom of each document. This is an area for anybody to submit changes, -corrections and suggestions about the given document. The Django developers -frequently monitor the comments there and use them to improve the documentation -for everybody. +We encourage you to help improve the docs by submitting changes, corrections +and suggestions in the `ticket system`_. The Django developers actively monitor +the ticket system and use your feedback to improve the documentation for +everybody. -We encourage you to help improve the docs: it's easy! Note, however, that -comments should explicitly relate to the documentation, rather than asking -broad tech-support questions. If you need help with your particular Django -setup, try the `django-users mailing list`_ instead of posting a comment to the -documentation. +Note, however, that tickets should explicitly relate to the documentation, +rather than asking broad tech-support questions. If you need help with your +particular Django setup, try the `django-users mailing list`_ or the +`#django IRC channel`_ instead. +.. _ticket system: http://code.djangoproject.com/simpleticket?component=Documentation .. _django-users mailing list: http://groups.google.com/group/django-users +.. _#django IRC channel: irc://irc.freenode.net/django In plain text ------------- @@ -134,14 +134,6 @@ We follow this policy: frozen document that says "These docs are frozen for Django version XXX" and links to the current version of that document. - * Once a document is frozen for a Django release, we remove comments from - that page, in favor of having comments on the latest version of that - document. This is for the sake of maintainability and usability, so that - users have one, and only one, place to leave comments on a particular - document. We realize that some people may be stuck on a previous version - of Django, but we believe the usability problems with multiple versions - of a document the outweigh the benefits. - * The `main documentation Web page`_ includes links to documentation for all previous versions. diff --git a/docs/modpython.txt b/docs/modpython.txt index 31ec1efe49..37909a09fd 100644 --- a/docs/modpython.txt +++ b/docs/modpython.txt @@ -57,17 +57,16 @@ on it, you'll need to tell mod_python:: .. caution:: - Is you are using Windows, remember that the path will contain backslashes. + If you're using Windows, remember that the path will contain backslashes. This string is passed through Python's string parser twice, so you need to escape each backslash **twice**:: PythonPath "['c:\\\\path\\\\to\\\\project'] + sys.path" - or use raw strings:: + Or, use raw strings:: PythonPath "[r'c:\\path\\to\\project'] + sys.path" - You can also add directives such as ``PythonAutoReload Off`` for performance. See the `mod_python documentation`_ for a full list of options. @@ -161,7 +160,7 @@ If, however, you have no option but to serve media files on the same Apache ``VirtualHost`` as Django, here's how you can turn off mod_python for a particular part of the site:: - <Location "/media/"> + <Location "/media"> SetHandler None </Location> @@ -178,7 +177,7 @@ the ``media`` subdirectory and any URL that ends with ``.jpg``, ``.gif`` or SetEnv DJANGO_SETTINGS_MODULE mysite.settings </Location> - <Location "media"> + <Location "/media"> SetHandler None </Location> diff --git a/docs/request_response.txt b/docs/request_response.txt index 40f06c859f..c0272461ca 100644 --- a/docs/request_response.txt +++ b/docs/request_response.txt @@ -483,8 +483,8 @@ In order to use the ``Http404`` exception to its fullest, you should create a template that is displayed when a 404 error is raised. This template should be called ``404.html`` and located in the top level of your template tree. -Customing error views ---------------------- +Customizing error views +----------------------- The 404 (page not found) view ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py index d91f1d2d45..2757787571 100644 --- a/tests/modeltests/model_forms/models.py +++ b/tests/modeltests/model_forms/models.py @@ -159,7 +159,7 @@ represented by a ChoiceField. <option value="1">Mike Royko</option> <option value="2">Bob Woodward</option> </select></td></tr> -<tr><th>Article:</th><td><textarea name="article"></textarea></td></tr> +<tr><th>Article:</th><td><textarea rows="10" cols="40" name="article"></textarea></td></tr> <tr><th>Categories:</th><td><select multiple="multiple" name="categories"> <option value="1">Entertainment</option> <option value="2">It's a test</option> @@ -199,7 +199,7 @@ current values are inserted as 'initial' data in each Field. <option value="1" selected="selected">Mike Royko</option> <option value="2">Bob Woodward</option> </select></li> -<li>Article: <textarea name="article">Hello.</textarea></li> +<li>Article: <textarea rows="10" cols="40" name="article">Hello.</textarea></li> <li>Categories: <select multiple="multiple" name="categories"> <option value="1">Entertainment</option> <option value="2">It's a test</option> @@ -231,7 +231,7 @@ Add some categories and test the many-to-many form output. <option value="1" selected="selected">Mike Royko</option> <option value="2">Bob Woodward</option> </select></li> -<li>Article: <textarea name="article">Hello.</textarea></li> +<li>Article: <textarea rows="10" cols="40" name="article">Hello.</textarea></li> <li>Categories: <select multiple="multiple" name="categories"> <option value="1" selected="selected">Entertainment</option> <option value="2">It's a test</option> @@ -309,7 +309,7 @@ the data in the database when the form is instantiated. <option value="1">Mike Royko</option> <option value="2">Bob Woodward</option> </select></li> -<li>Article: <textarea name="article"></textarea></li> +<li>Article: <textarea rows="10" cols="40" name="article"></textarea></li> <li>Categories: <select multiple="multiple" name="categories"> <option value="1">Entertainment</option> <option value="2">It's a test</option> @@ -328,7 +328,7 @@ the data in the database when the form is instantiated. <option value="2">Bob Woodward</option> <option value="3">Carl Bernstein</option> </select></li> -<li>Article: <textarea name="article"></textarea></li> +<li>Article: <textarea rows="10" cols="40" name="article"></textarea></li> <li>Categories: <select multiple="multiple" name="categories"> <option value="1">Entertainment</option> <option value="2">It's a test</option> diff --git a/tests/regressiontests/forms/localflavor.py b/tests/regressiontests/forms/localflavor.py index fecb57d81b..b37aa3c6ea 100644 --- a/tests/regressiontests/forms/localflavor.py +++ b/tests/regressiontests/forms/localflavor.py @@ -6,7 +6,7 @@ localflavor_tests = r""" USZipCodeField validates that the data is either a five-digit U.S. zip code or a zip+4. ->>> from django.contrib.localflavor.usa.forms import USZipCodeField +>>> from django.contrib.localflavor.us.forms import USZipCodeField >>> f = USZipCodeField() >>> f.clean('60606') u'60606' @@ -67,7 +67,7 @@ u'' USPhoneNumberField validates that the data is a valid U.S. phone number, including the area code. It's normalized to XXX-XXX-XXXX format. ->>> from django.contrib.localflavor.usa.forms import USPhoneNumberField +>>> from django.contrib.localflavor.us.forms import USPhoneNumberField >>> f = USPhoneNumberField() >>> f.clean('312-555-1212') u'312-555-1212' @@ -136,7 +136,7 @@ u'' USStateField validates that the data is either an abbreviation or name of a U.S. state. ->>> from django.contrib.localflavor.usa.forms import USStateField +>>> from django.contrib.localflavor.us.forms import USStateField >>> f = USStateField() >>> f.clean('il') u'IL' @@ -181,7 +181,7 @@ u'' USStateSelect is a Select widget that uses a list of U.S. states/territories as its choices. ->>> from django.contrib.localflavor.usa.forms import USStateSelect +>>> from django.contrib.localflavor.us.forms import USStateSelect >>> w = USStateSelect() >>> print w.render('state', 'IL') <select name="state"> @@ -247,7 +247,7 @@ as its choices. </select> # USSocialSecurityNumberField ################################################# ->>> from django.contrib.localflavor.usa.forms import USSocialSecurityNumberField +>>> from django.contrib.localflavor.us.forms import USSocialSecurityNumberField >>> f = USSocialSecurityNumberField() >>> f.clean('987-65-4330') u'987-65-4330' @@ -882,4 +882,134 @@ u'9786324830D-6104243-0910271-2' Traceback (most recent call last): ... ValidationError: [u'Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X format.'] + +## AUPostCodeField ########################################################## + +A field that accepts a four digit Australian post code. + +>>> from django.contrib.localflavor.au.forms import AUPostCodeField +>>> f = AUPostCodeField() +>>> f.clean('1234') +u'1234' +>>> f.clean('2000') +u'2000' +>>> f.clean('abcd') +Traceback (most recent call last): +... +ValidationError: [u'Enter a 4 digit post code.'] +>>> f.clean('20001') +Traceback (most recent call last): +... +ValidationError: [u'Enter a 4 digit post code.'] +>>> f.clean(None) +Traceback (most recent call last): +... +ValidationError: [u'This field is required.'] +>>> f.clean('') +Traceback (most recent call last): +... +ValidationError: [u'This field is required.'] + +>>> f = AUPostCodeField(required=False) +>>> f.clean('1234') +u'1234' +>>> f.clean('2000') +u'2000' +>>> f.clean('abcd') +Traceback (most recent call last): +... +ValidationError: [u'Enter a 4 digit post code.'] +>>> f.clean('20001') +Traceback (most recent call last): +... +ValidationError: [u'Enter a 4 digit post code.'] +>>> f.clean(None) +u'' +>>> f.clean('') +u'' + +## AUPhoneNumberField ######################################################## + +A field that accepts a 10 digit Australian phone number. +llows spaces and parentheses around area code. + +>>> from django.contrib.localflavor.au.forms import AUPhoneNumberField +>>> f = AUPhoneNumberField() +>>> f.clean('1234567890') +u'1234567890' +>>> f.clean('0213456789') +u'0213456789' +>>> f.clean('02 13 45 67 89') +u'0213456789' +>>> f.clean('(02) 1345 6789') +u'0213456789' +>>> f.clean('(02) 1345-6789') +u'0213456789' +>>> f.clean('(02)1345-6789') +u'0213456789' +>>> f.clean('0408 123 456') +u'0408123456' +>>> f.clean('123') +Traceback (most recent call last): +... +ValidationError: [u'Phone numbers must contain 10 digits.'] +>>> f.clean('1800DJANGO') +Traceback (most recent call last): +... +ValidationError: [u'Phone numbers must contain 10 digits.'] +>>> f.clean(None) +Traceback (most recent call last): +... +ValidationError: [u'This field is required.'] +>>> f.clean('') +Traceback (most recent call last): +... +ValidationError: [u'This field is required.'] + +>>> f = AUPhoneNumberField(required=False) +>>> f.clean('1234567890') +u'1234567890' +>>> f.clean('0213456789') +u'0213456789' +>>> f.clean('02 13 45 67 89') +u'0213456789' +>>> f.clean('(02) 1345 6789') +u'0213456789' +>>> f.clean('(02) 1345-6789') +u'0213456789' +>>> f.clean('(02)1345-6789') +u'0213456789' +>>> f.clean('0408 123 456') +u'0408123456' +>>> f.clean('123') +Traceback (most recent call last): +... +ValidationError: [u'Phone numbers must contain 10 digits.'] +>>> f.clean('1800DJANGO') +Traceback (most recent call last): +... +ValidationError: [u'Phone numbers must contain 10 digits.'] +>>> f.clean(None) +u'' +>>> f.clean('') +u'' + +## AUStateSelect ############################################################# + +AUStateSelect is a Select widget that uses a list of Australian +states/territories as its choices. + +>>> from django.contrib.localflavor.au.forms import AUStateSelect +>>> f = AUStateSelect() +>>> print f.render('state', 'NSW') +<select name="state"> +<option value="ACT">Australian Capital Territory</option> +<option value="NSW" selected="selected">New South Wales</option> +<option value="NT">Northern Territory</option> +<option value="QLD">Queensland</option> +<option value="SA">South Australia</option> +<option value="TAS">Tasmania</option> +<option value="VIC">Victoria</option> +<option value="WA">Western Australia</option> +</select> """ diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py index afe8b204c6..db420757f0 100644 --- a/tests/regressiontests/forms/tests.py +++ b/tests/regressiontests/forms/tests.py @@ -194,30 +194,30 @@ u'<input type="file" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u01 >>> w = Textarea() >>> w.render('msg', '') -u'<textarea name="msg"></textarea>' +u'<textarea rows="10" cols="40" name="msg"></textarea>' >>> w.render('msg', None) -u'<textarea name="msg"></textarea>' +u'<textarea rows="10" cols="40" name="msg"></textarea>' >>> w.render('msg', 'value') -u'<textarea name="msg">value</textarea>' +u'<textarea rows="10" cols="40" name="msg">value</textarea>' >>> w.render('msg', 'some "quoted" & ampersanded value') -u'<textarea name="msg">some "quoted" & ampersanded value</textarea>' ->>> w.render('msg', 'value', attrs={'class': 'pretty'}) -u'<textarea name="msg" class="pretty">value</textarea>' +u'<textarea rows="10" cols="40" name="msg">some "quoted" & ampersanded value</textarea>' +>>> w.render('msg', 'value', attrs={'class': 'pretty', 'rows': 20}) +u'<textarea class="pretty" rows="20" cols="40" name="msg">value</textarea>' You can also pass 'attrs' to the constructor: >>> w = Textarea(attrs={'class': 'pretty'}) >>> w.render('msg', '') -u'<textarea class="pretty" name="msg"></textarea>' +u'<textarea rows="10" cols="40" name="msg" class="pretty"></textarea>' >>> w.render('msg', 'example') -u'<textarea class="pretty" name="msg">example</textarea>' +u'<textarea rows="10" cols="40" name="msg" class="pretty">example</textarea>' 'attrs' passed to render() get precedence over those passed to the constructor: >>> w = Textarea(attrs={'class': 'pretty'}) >>> w.render('msg', '', attrs={'class': 'special'}) -u'<textarea class="special" name="msg"></textarea>' +u'<textarea rows="10" cols="40" name="msg" class="special"></textarea>' >>> w.render('msg', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}) -u'<textarea class="fun" name="msg">\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111</textarea>' +u'<textarea rows="10" cols="40" name="msg" class="fun">\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111</textarea>' # CheckboxInput Widget ######################################################## @@ -1967,12 +1967,12 @@ Any Field can have a Widget class passed to its constructor: >>> print f['subject'] <input type="text" name="subject" /> >>> print f['message'] -<textarea name="message"></textarea> +<textarea rows="10" cols="40" name="message"></textarea> as_textarea(), as_text() and as_hidden() are shortcuts for changing the output widget type: >>> f['subject'].as_textarea() -u'<textarea name="subject"></textarea>' +u'<textarea rows="10" cols="40" name="subject"></textarea>' >>> f['message'].as_text() u'<input type="text" name="message" />' >>> f['message'].as_hidden() @@ -1992,7 +1992,7 @@ as_hidden(): u'<input type="text" name="message" />' >>> f = ContactForm({'subject': 'Hello', 'message': 'I love you.'}, auto_id=False) >>> f['subject'].as_textarea() -u'<textarea name="subject">Hello</textarea>' +u'<textarea rows="10" cols="40" name="subject">Hello</textarea>' >>> f['message'].as_text() u'<input type="text" name="message" value="I love you." />' >>> f['message'].as_hidden() |
