summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMalcolm Tredinnick <malcolm.tredinnick@gmail.com>2007-04-09 11:09:17 +0000
committerMalcolm Tredinnick <malcolm.tredinnick@gmail.com>2007-04-09 11:09:17 +0000
commit349bf5a355ff7ebffb3403a68437e2c524d8b7c7 (patch)
tree82e19ce8c2dbf74becf21604cb90662db6fcbe8a
parente5adc5a42797a7afe078320d3050a300b11f8405 (diff)
unicode: Merged with trunk up to [4970].
git-svn-id: http://code.djangoproject.com/svn/django/branches/unicode@4973 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--AUTHORS1
-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.py17
-rw-r--r--django/contrib/localflavor/au/forms.py43
-rw-r--r--django/contrib/localflavor/br/br_states.py8
-rw-r--r--django/contrib/localflavor/fi/forms.py14
-rw-r--r--django/contrib/localflavor/us/__init__.py0
-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__.py2
-rw-r--r--django/newforms/widgets.py6
-rw-r--r--django/views/debug.py3
-rw-r--r--docs/django-admin.txt68
-rw-r--r--docs/documentation.txt34
-rw-r--r--docs/legacy_databases.txt6
-rw-r--r--docs/modpython.txt9
-rw-r--r--docs/request_response.txt4
-rw-r--r--docs/url_dispatch.txt56
-rw-r--r--tests/modeltests/model_forms/models.py10
-rw-r--r--tests/regressiontests/forms/localflavor.py140
-rw-r--r--tests/regressiontests/forms/tests.py26
21 files changed, 326 insertions, 121 deletions
diff --git a/AUTHORS b/AUTHORS
index cca3247981..119f6378eb 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -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/br/br_states.py b/django/contrib/localflavor/br/br_states.py
index c6ce0a1bb7..98e54bca2c 100644
--- a/django/contrib/localflavor/br/br_states.py
+++ b/django/contrib/localflavor/br/br_states.py
@@ -1,11 +1,9 @@
# -*- coding: utf-8 -*-
"""
-A brazilian mapping of state misspellings/abbreviations to normalized
-abbreviations, and an alphabetical list of states for use as `choices
-in a formfield.
+An alphabetical list of Brazilian 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.
+This exists in this standalone file so that it's only imported into memory
+when explicitly needed.
"""
STATE_CHOICES = (
diff --git a/django/contrib/localflavor/fi/forms.py b/django/contrib/localflavor/fi/forms.py
index a2b2eed5c2..da5cb5f2a8 100644
--- a/django/contrib/localflavor/fi/forms.py
+++ b/django/contrib/localflavor/fi/forms.py
@@ -26,8 +26,8 @@ class FISocialSecurityNumber(Field):
def clean(self, value):
super(FISocialSecurityNumber, self).clean(value)
if value in EMPTY_VALUES:
- return u''
-
+ return u''
+
checkmarks = "0123456789ABCDEFHJKLMNPRSTUVWXY"
result = re.match(r"""^
(?P<date>([0-2]\d|3[01])
@@ -35,13 +35,11 @@ class FISocialSecurityNumber(Field):
(\d{2}))
[A+-]
(?P<serial>(\d{3}))
- (?P<chechsum>[%s])$""" % checkmarks, value, re.VERBOSE | re.IGNORECASE)
+ (?P<checksum>[%s])$""" % checkmarks, value, re.VERBOSE | re.IGNORECASE)
if not result:
raise ValidationError(gettext(u'Enter a valid Finnish social security number.'))
- checksum = int(result.groupdict()['date'] + result.groupdict()['serial'])
-
- if checkmarks[checksum % len(checkmarks)] == result.groupdict()['chechsum'].upper():
+ gd = result.groupdict()
+ checksum = int(gd['date'] + gd['serial'])
+ if checkmarks[checksum % len(checkmarks)] == gd['checksum'].upper():
return u'%s' % value.upper()
-
raise ValidationError(gettext(u'Enter a valid Finnish social security number.'))
-
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 3972de7d4a..466897ad86 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -761,7 +761,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/django-admin.txt b/docs/django-admin.txt
index 388eaf98ac..cc23bfb559 100644
--- a/docs/django-admin.txt
+++ b/docs/django-admin.txt
@@ -29,6 +29,9 @@ Generally, when working on a single Django project, it's easier to use
``--settings`` command line option, if you need to switch between multiple
Django settings files.
+The command-line examples throughout this document use ``django-admin.py`` to
+be consistent, but any example can use ``manage.py`` just as well.
+
Usage
=====
@@ -100,23 +103,23 @@ if you're ever curious to see the full list of defaults.
dumpdata [appname appname ...]
------------------------------
-Output to standard output all data in the database associated with the named
+Output to standard output all data in the database associated with the named
application(s).
By default, the database will be dumped in JSON format. If you want the output
-to be in another format, use the ``--format`` option (e.g., ``format=xml``).
-You may specify any Django serialization backend (including any user specified
+to be in another format, use the ``--format`` option (e.g., ``format=xml``).
+You may specify any Django serialization backend (including any user specified
serialization backends named in the ``SERIALIZATION_MODULES`` setting).
If no application name is provided, all installed applications will be dumped.
-The output of ``dumpdata`` can be used as input for ``loaddata``.
+The output of ``dumpdata`` can be used as input for ``loaddata``.
flush
-----
-Return the database to the state it was in immediately after syncdb was
-executed. This means that all data will be removed from the database, any
+Return the database to the state it was in immediately after syncdb was
+executed. This means that all data will be removed from the database, any
post-synchronization handlers will be re-executed, and the ``initial_data``
fixture will be re-installed.
@@ -178,37 +181,37 @@ Django will search in three locations for fixtures:
3. In the literal path named by the fixture
Django will load any and all fixtures it finds in these locations that match
-the provided fixture names.
+the provided fixture names.
-If the named fixture has a file extension, only fixtures of that type
+If the named fixture has a file extension, only fixtures of that type
will be loaded. For example::
django-admin.py loaddata mydata.json
-
-would only load JSON fixtures called ``mydata``. The fixture extension
-must correspond to the registered name of a serializer (e.g., ``json`` or
+
+would only load JSON fixtures called ``mydata``. The fixture extension
+must correspond to the registered name of a serializer (e.g., ``json`` or
``xml``).
-If you omit the extension, Django will search all available fixture types
+If you omit the extension, Django will search all available fixture types
for a matching fixture. For example::
django-admin.py loaddata mydata
-
+
would look for any fixture of any fixture type called ``mydata``. If a fixture
directory contained ``mydata.json``, that fixture would be loaded
-as a JSON fixture. However, if two fixtures with the same name but different
-fixture type are discovered (for example, if ``mydata.json`` and
-``mydata.xml`` were found in the same fixture directory), fixture
-installation will be aborted, and any data installed in the call to
+as a JSON fixture. However, if two fixtures with the same name but different
+fixture type are discovered (for example, if ``mydata.json`` and
+``mydata.xml`` were found in the same fixture directory), fixture
+installation will be aborted, and any data installed in the call to
``loaddata`` will be removed from the database.
-The fixtures that are named can include directory components. These
+The fixtures that are named can include directory components. These
directories will be included in the search path. For example::
django-admin.py loaddata foo/bar/mydata.json
-
-would search ``<appname>/fixtures/foo/bar/mydata.json`` for each installed
-application, ``<dirname>/foo/bar/mydata.json`` for each directory in
+
+would search ``<appname>/fixtures/foo/bar/mydata.json`` for each installed
+application, ``<dirname>/foo/bar/mydata.json`` for each directory in
``FIXTURE_DIRS``, and the literal path ``foo/bar/mydata.json``.
Note that the order in which fixture files are processed is undefined. However,
@@ -219,14 +222,14 @@ end of the transaction.
.. admonition:: MySQL and Fixtures
- Unfortunately, MySQL isn't capable of completely supporting all the
+ Unfortunately, MySQL isn't capable of completely supporting all the
features of Django fixtures. If you use MyISAM tables, MySQL doesn't
- support transactions or constraints, so you won't get a rollback if
- multiple transaction files are found, or validation of fixture data.
- If you use InnoDB tables, you won't be able to have any forward
- references in your data files - MySQL doesn't provide a mechanism to
- defer checking of row constraints until a transaction is committed.
-
+ support transactions or constraints, so you won't get a rollback if
+ multiple transaction files are found, or validation of fixture data.
+ If you use InnoDB tables, you won't be able to have any forward
+ references in your data files - MySQL doesn't provide a mechanism to
+ defer checking of row constraints until a transaction is committed.
+
reset [appname appname ...]
---------------------------
Executes the equivalent of ``sqlreset`` for the given appnames.
@@ -397,8 +400,8 @@ this command to install the default apps.
If you're installing the ``django.contrib.auth`` application, ``syncdb`` will
give you the option of creating a superuser immediately.
-``syncdb`` will also search for and install any fixture named ``initial_data``.
-See the documentation for ``loaddata`` for details on the specification of
+``syncdb`` will also search for and install any fixture named ``initial_data``.
+See the documentation for ``loaddata`` for details on the specification of
fixture data files.
test
@@ -471,7 +474,7 @@ Example usage::
django-admin.py dumpdata --indent=4
-Specifies the number of spaces that will be used for indentation when
+Specifies the number of spaces that will be used for indentation when
pretty-printing output. By default, output will *not* be pretty-printed.
Pretty-printing will only be enabled if the indent option is provided.
@@ -512,7 +515,8 @@ and `2` is verbose output.
------------
Example usage::
- django-admin.py manage.py --adminmedia=/tmp/new-admin-style/
+
+ django-admin.py --adminmedia=/tmp/new-admin-style/
Tells Django where to find the various CSS and JavaScript files for the admin
interface when running the development server. Normally these files are served
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/legacy_databases.txt b/docs/legacy_databases.txt
index 8230c11f61..3e2753baca 100644
--- a/docs/legacy_databases.txt
+++ b/docs/legacy_databases.txt
@@ -39,11 +39,11 @@ Auto-generate the models
Django comes with a utility that can create models by introspecting an existing
database. You can view the output by running this command::
- django-admin.py inspectdb --settings=path.to.settings
+ python manage.py inspectdb
Save this as a file by using standard Unix output redirection::
- django-admin.py inspectdb --settings=path.to.settings > models.py
+ python manage.py inspectdb > models.py
This feature is meant as a shortcut, not as definitive model generation. See
the `django-admin.py documentation`_ for more information.
@@ -60,7 +60,7 @@ Install the core Django tables
Next, run the ``manage.py syncdb`` command to install any extra needed database
records such as admin permissions and content types::
- django-admin.py init --settings=path.to.settings
+ python manage.py syncdb
See whether it worked
=====================
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/docs/url_dispatch.txt b/docs/url_dispatch.txt
index e6e1cb6cbf..39eed0625b 100644
--- a/docs/url_dispatch.txt
+++ b/docs/url_dispatch.txt
@@ -192,10 +192,11 @@ The remaining arguments should be tuples in this format::
url
---
-**New in development version**
-The ``url()`` function can be used instead of a tuple as an argument to
-``patterns()``. This is convenient if you wish to specify a name without the
+**New in Django development version**
+
+You can use the ``url()`` function, instead of a tuple, as an argument to
+``patterns()``. This is convenient if you want to specify a name without the
optional extra arguments dictionary. For example::
urlpatterns = patterns('',
@@ -498,26 +499,40 @@ the view prefix (as explained in "The view prefix" above) will have no effect.
Naming URL patterns
===================
-**New in development version**
+**New in Django development version**
+
+It's fairly common to use the same view function in multiple URL patterns in
+your URLconf. For example, these two URL patterns both point to the ``archive``
+view::
+
+ urlpatterns = patterns('',
+ (r'/archive/(\d{4})/$', archive),
+ (r'/archive-summary/(\d{4})/$', archive, {'summary': True}),
+ )
+
+This is completely valid, but it leads to problems when you try to do reverse
+URL matching (through the ``permalink()`` decorator or the ``{% url %}``
+template tag). Continuing this example, if you wanted to retrieve the URL for
+the ``archive`` view, Django's reverse URL matcher would get confused, because
+*two* URLpatterns point at that view.
-It is fairly common to use the same view function in multiple URL patterns in
-your URLConf. This leads to problems when you come to do reverse URL matching,
-because the ``permalink()`` decorator and ``{% url %}`` template tag use the
-name of the view function to find a match.
+To solve this problem, Django supports **named URL patterns**. That is, you can
+give a name to a URL pattern in order to distinguish it from other patterns
+using the same view and parameters. Then, you can use this name in reverse URL
+matching.
-To solve this problem, you can give a name to each of your URL patterns in
-order to distinguish them from other patterns using the same views and
-parameters. You can then use this name wherever you would otherwise use the
-name of the view function. For example, if you URLConf contains::
+Here's the above example, rewritten to used named URL patterns::
urlpatterns = patterns('',
url(r'/archive/(\d{4})/$', archive, name="full-archive"),
url(r'/archive-summary/(\d{4})/$', archive, {'summary': True}, "arch-summary"),
)
-...you could refer to either the summary archive view in a template as::
+With these names in place (``full-archive`` and ``arch-summary``), you can
+target each pattern individually by using its name::
{% url arch-summary 1945 %}
+ {% url full-archive 2007 %}
Even though both URL patterns refer to the ``archive`` view here, using the
``name`` parameter to ``url()`` allows you to tell them apart in templates.
@@ -527,11 +542,12 @@ not restricted to valid Python names.
.. note::
- Make sure that when you name your URLs, you use names that are unlikely to
- clash with any other application's choice of names. If you call your URL
- pattern *comment* and another application does the same thing, there is no
- guarantee which URL will be inserted into your template when you use this
- name. Putting a prefix on your URL names, perhaps derived from
- the application name, will decrease the chances of collision. Something
- like *myapp-comment* is recommended over simply *comment*.
+ When you name your URL patterns, make sure you use names that are unlikely
+ to clash with any other application's choice of names. If you call your URL
+ pattern ``comment``, and another application does the same thing, there's
+ no guarantee which URL will be inserted into your template when you use
+ this name.
+ Putting a prefix on your URL names, perhaps derived from the application
+ name, will decrease the chances of collision. We recommend something like
+ ``myapp-comment`` instead of ``comment``.
diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py
index 535a7036f4..14ec96940f 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&#39;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&#39;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&#39;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&#39;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&#39;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 e78a4d0ec3..4521d17d7f 100644
--- a/tests/regressiontests/forms/tests.py
+++ b/tests/regressiontests/forms/tests.py
@@ -193,30 +193,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 &quot;quoted&quot; &amp; 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 &quot;quoted&quot; &amp; 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 ########################################################
@@ -1966,12 +1966,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()
@@ -1991,7 +1991,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()