summaryrefslogtreecommitdiff
path: root/docs/topics
diff options
context:
space:
mode:
Diffstat (limited to 'docs/topics')
-rw-r--r--docs/topics/forms/formsets.txt49
-rw-r--r--docs/topics/http/urls.txt203
-rw-r--r--docs/topics/i18n.txt89
-rw-r--r--docs/topics/testing.txt37
4 files changed, 338 insertions, 40 deletions
diff --git a/docs/topics/forms/formsets.txt b/docs/topics/forms/formsets.txt
index 8e90b54ced..e6146aeaba 100644
--- a/docs/topics/forms/formsets.txt
+++ b/docs/topics/forms/formsets.txt
@@ -86,9 +86,9 @@ displayed.
Formset validation
------------------
-Validation with a formset is about identical to a regular ``Form``. There is
+Validation with a formset is almost identical to a regular ``Form``. There is
an ``is_valid`` method on the formset to provide a convenient way to validate
-each form in the formset::
+all forms in the formset::
>>> ArticleFormSet = formset_factory(ArticleForm)
>>> formset = ArticleFormSet({})
@@ -97,22 +97,25 @@ each form in the formset::
We passed in no data to the formset which is resulting in a valid form. The
formset is smart enough to ignore extra forms that were not changed. If we
-attempt to provide an article, but fail to do so::
+provide an invalid article::
>>> data = {
- ... 'form-TOTAL_FORMS': u'1',
- ... 'form-INITIAL_FORMS': u'1',
+ ... 'form-TOTAL_FORMS': u'2',
+ ... 'form-INITIAL_FORMS': u'0',
... 'form-0-title': u'Test',
- ... 'form-0-pub_date': u'',
+ ... 'form-0-pub_date': u'16 June 1904',
+ ... 'form-1-title': u'Test',
+ ... 'form-1-pub_date': u'', # <-- this date is missing but required
... }
>>> formset = ArticleFormSet(data)
>>> formset.is_valid()
False
>>> formset.errors
- [{'pub_date': [u'This field is required.']}]
+ [{}, {'pub_date': [u'This field is required.']}]
-As we can see the formset properly performed validation and gave us the
-expected errors.
+As we can see, ``formset.errors`` is a list whose entries correspond to the
+forms in the formset. Validation was performed for each of the two forms, and
+the expected error message appears for the second item.
.. _understanding-the-managementform:
@@ -155,20 +158,40 @@ Custom formset validation
~~~~~~~~~~~~~~~~~~~~~~~~~
A formset has a ``clean`` method similar to the one on a ``Form`` class. This
-is where you define your own validation that deals at the formset level::
+is where you define your own validation that works at the formset level::
>>> from django.forms.formsets import BaseFormSet
>>> class BaseArticleFormSet(BaseFormSet):
... def clean(self):
- ... raise forms.ValidationError, u'An error occured.'
+ ... """Checks that no two articles have the same title."""
+ ... if any(self.errors):
+ ... # Don't bother validating the formset unless each form is valid on its own
+ ... return
+ ... titles = []
+ ... for i in range(0, self.total_form_count()):
+ ... form = self.forms[i]
+ ... title = form.cleaned_data['title']
+ ... if title in titles:
+ ... raise forms.ValidationError, "Articles in a set must have distinct titles."
+ ... titles.append(title)
>>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet)
- >>> formset = ArticleFormSet({})
+ >>> data = {
+ ... 'form-TOTAL_FORMS': u'2',
+ ... 'form-INITIAL_FORMS': u'0',
+ ... 'form-0-title': u'Test',
+ ... 'form-0-pub_date': u'16 June 1904',
+ ... 'form-1-title': u'Test',
+ ... 'form-1-pub_date': u'23 June 1912',
+ ... }
+ >>> formset = ArticleFormSet(data)
>>> formset.is_valid()
False
+ >>> formset.errors
+ [{}, {}]
>>> formset.non_form_errors()
- [u'An error occured.']
+ [u'Articles in a set must have distinct titles.']
The formset ``clean`` method is called after all the ``Form.clean`` methods
have been called. The errors will be found using the ``non_form_errors()``
diff --git a/docs/topics/http/urls.txt b/docs/topics/http/urls.txt
index 4248d4f02e..0b2257cefe 100644
--- a/docs/topics/http/urls.txt
+++ b/docs/topics/http/urls.txt
@@ -4,6 +4,8 @@
URL dispatcher
==============
+.. module:: django.core.urlresolvers
+
A clean, elegant URL scheme is an important detail in a high-quality Web
application. Django lets you design URLs however you want, with no framework
limitations.
@@ -40,14 +42,14 @@ algorithm the system follows to determine which Python code to execute:
this is the value of the ``ROOT_URLCONF`` setting, but if the incoming
``HttpRequest`` object has an attribute called ``urlconf``, its value
will be used in place of the ``ROOT_URLCONF`` setting.
-
+
2. Django loads that Python module and looks for the variable
``urlpatterns``. This should be a Python list, in the format returned by
the function ``django.conf.urls.defaults.patterns()``.
-
+
3. Django runs through each URL pattern, in order, and stops at the first
one that matches the requested URL.
-
+
4. Once one of the regexes matches, Django imports and calls the given
view, which is a simple Python function. The view gets passed an
:class:`~django.http.HttpRequest` as its first argument and any values
@@ -182,11 +184,13 @@ your URLconf. This gives your module access to these objects:
patterns
--------
+.. function:: patterns(prefix, pattern_description, ...)
+
A function that takes a prefix, and an arbitrary number of URL patterns, and
returns a list of URL patterns in the format Django needs.
The first argument to ``patterns()`` is a string ``prefix``. See
-"The view prefix" below.
+`The view prefix`_ below.
The remaining arguments should be tuples in this format::
@@ -222,6 +226,8 @@ url
.. versionadded:: 1.0
+.. function:: url(regex, view, kwargs=None, name=None, prefix='')
+
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::
@@ -244,6 +250,8 @@ The ``prefix`` parameter has the same meaning as the first argument to
handler404
----------
+.. data:: handler404
+
A string representing the full Python import path to the view that should be
called if none of the URL patterns match.
@@ -253,6 +261,8 @@ value should suffice.
handler500
----------
+.. data:: handler500
+
A string representing the full Python import path to the view that should be
called in case of server errors. Server errors happen when you have runtime
errors in view code.
@@ -263,8 +273,17 @@ value should suffice.
include
-------
-A function that takes a full Python import path to another URLconf that should
-be "included" in this place. See `Including other URLconfs`_ below.
+.. function:: include(<module or pattern_list>)
+
+A function that takes a full Python import path to another URLconf module that
+should be "included" in this place.
+
+.. versionadded:: 1.1
+
+:func:`include` also accepts as an argument an iterable that returns URL
+patterns.
+
+See `Including other URLconfs`_ below.
Notes on capturing text in URLs
===============================
@@ -391,6 +410,32 @@ Django encounters ``include()``, it chops off whatever part of the URL matched
up to that point and sends the remaining string to the included URLconf for
further processing.
+.. versionadded:: 1.1
+
+Another possibility is to include additional URL patterns not by specifying the
+URLconf Python module defining them as the `include`_ argument but by using
+directly the pattern list as returned by `patterns`_ instead. For example::
+
+ from django.conf.urls.defaults import *
+
+ extra_patterns = patterns('',
+ url(r'reports/(?P<id>\d+)/$', 'credit.views.report', name='credit-reports'),
+ url(r'charge/$', 'credit.views.charge', name='credit-charge'),
+ )
+
+ urlpatterns = patterns('',
+ url(r'^$', 'apps.main.views.homepage', name='site-homepage'),
+ (r'^help/', include('apps.help.urls')),
+ (r'^credit/', include(extra_patterns)),
+ )
+
+This approach can be seen in use when you deploy an instance of the Django
+Admin application. The Django Admin is deployed as instances of a
+:class:`AdminSite`; each :class:`AdminSite` instance has an attribute
+``urls`` that returns the url patterns available to that instance. It is this
+attribute that you ``include()`` into your projects ``urlpatterns`` when you
+deploy the admin instance.
+
.. _`Django Web site`: http://www.djangoproject.com/
Captured parameters
@@ -413,6 +458,58 @@ the following example is valid::
In the above example, the captured ``"username"`` variable is passed to the
included URLconf, as expected.
+.. _topics-http-defining-url-namespaces:
+
+Defining URL Namespaces
+-----------------------
+
+When you need to deploy multiple instances of a single application, it can be
+helpful to be able to differentiate between instances. This is especially
+important when using :ref:`named URL patterns <naming-url-patterns>`, since
+multiple instances of a single application will share named URLs. Namespaces
+provide a way to tell these named URLs apart.
+
+A URL namespace comes in two parts, both of which are strings:
+
+ * An **application namespace**. This describes the name of the application
+ that is being deployed. Every instance of a single application will have
+ the same application namespace. For example, Django's admin application
+ has the somewhat predictable application namespace of ``admin``.
+
+ * An **instance namespace**. This identifies a specific instance of an
+ application. Instance namespaces should be unique across your entire
+ project. However, an instance namespace can be the same as the
+ application namespace. This is used to specify a default instance of an
+ application. For example, the default Django Admin instance has an
+ instance namespace of ``admin``.
+
+URL Namespaces can be specified in two ways.
+
+Firstly, you can provide the application and instance namespace as arguments
+to ``include()`` when you construct your URL patterns. For example,::
+
+ (r'^help/', include('apps.help.urls', namespace='foo', app_name='bar')),
+
+This will include the URLs defined in ``apps.help.urls`` into the application
+namespace ``bar``, with the instance namespace ``foo``.
+
+Secondly, you can include an object that contains embedded namespace data. If
+you ``include()`` a ``patterns`` object, that object will be added to the
+global namespace. However, you can also ``include()`` an object that contains
+a 3-tuple containing::
+
+ (<patterns object>, <application namespace>, <instance namespace>)
+
+This will include the nominated URL patterns into the given application and
+instance namespace. For example, the ``urls`` attribute of Django's
+:class:`AdminSite` object returns a 3-tuple that contains all the patterns in
+an admin site, plus the name of the admin instance, and the application
+namespace ``admin``.
+
+Once you have defined namespaced URLs, you can reverse them. For details on
+reversing namespaced urls, see the documentation on :ref:`reversing namespaced
+URLs <topics-http-reversing-url-namespaces>`.
+
Passing extra options to view functions
=======================================
@@ -545,7 +642,7 @@ view::
This is completely valid, but it leads to problems when you try to do reverse
URL matching (through the ``permalink()`` decorator or the :ttag:`url` template
-tag. Continuing this example, if you wanted to retrieve the URL for the
+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.
@@ -587,6 +684,86 @@ not restricted to valid Python names.
name, will decrease the chances of collision. We recommend something like
``myapp-comment`` instead of ``comment``.
+.. _topics-http-reversing-url-namespaces:
+
+URL namespaces
+--------------
+
+.. versionadded:: 1.1
+
+Namespaced URLs are specified using the ``:`` operator. For example, the main
+index page of the admin application is referenced using ``admin:index``. This
+indicates a namespace of ``admin``, and a named URL of ``index``.
+
+Namespaces can also be nested. The named URL ``foo:bar:whiz`` would look for
+a pattern named ``whiz`` in the namespace ``bar`` that is itself defined within
+the top-level namespace ``foo``.
+
+When given a namespaced URL (e.g. ``myapp:index``) to resolve, Django splits
+the fully qualified name into parts, and then tries the following lookup:
+
+ 1. First, Django looks for a matching application namespace (in this
+ example, ``myapp``). This will yield a list of instances of that
+ application.
+
+ 2. If there is a *current* application defined, Django finds and returns
+ the URL resolver for that instance. The *current* application can be
+ specified as an attribute on the template context - applications that
+ expect to have multiple deployments should set the ``current_app``
+ attribute on any ``Context`` or ``RequestContext`` that is used to
+ render a template.
+
+ The current application can also be specified manually as an argument
+ to the :func:`reverse()` function.
+
+ 3. If there is no current application. Django looks for a default
+ application instance. The default application instance is the instance
+ that has an instance namespace matching the application namespace (in
+ this example, an instance of the ``myapp`` called ``myapp``).
+
+ 4. If there is no default application instance, Django will pick the first
+ deployed instance of the application, whatever its instance name may be.
+
+ 5. If the provided namespace doesn't match an application namespace in
+ step 1, Django will attempt a direct lookup of the namespace as an
+ instance namespace.
+
+If there are nested namespaces, these steps are repeated for each part of the
+namespace until only the view name is unresolved. The view name will then be
+resolved into a URL in the namespace that has been found.
+
+To show this resolution strategy in action, consider an example of two instances
+of ``myapp``: one called ``foo``, and one called ``bar``. ``myapp`` has a main
+index page with a URL named `index`. Using this setup, the following lookups are
+possible:
+
+ * If one of the instances is current - say, if we were rendering a utility page
+ in the instance ``bar`` - ``myapp:index`` will resolve to the index page of
+ the instance ``bar``.
+
+ * If there is no current instance - say, if we were rendering a page
+ somewhere else on the site - ``myapp:index`` will resolve to the first
+ registered instance of ``myapp``. Since there is no default instance,
+ the first instance of ``myapp`` that is registered will be used. This could
+ be ``foo`` or ``bar``, depending on the order they are introduced into the
+ urlpatterns of the project.
+
+ * ``foo:index`` will always resolve to the index page of the instance ``foo``.
+
+If there was also a default instance - i.e., an instance named `myapp` - the
+following would happen:
+
+ * If one of the instances is current - say, if we were rendering a utility page
+ in the instance ``bar`` - ``myapp:index`` will resolve to the index page of
+ the instance ``bar``.
+
+ * If there is no current instance - say, if we were rendering a page somewhere
+ else on the site - ``myapp:index`` will resolve to the index page of the
+ default instance.
+
+ * ``foo:index`` will again resolve to the index page of the instance ``foo``.
+
+
Utility methods
===============
@@ -597,8 +774,7 @@ If you need to use something similar to the :ttag:`url` template tag in
your code, Django provides the following method (in the
``django.core.urlresolvers`` module):
-.. currentmodule:: django.core.urlresolvers
-.. function:: reverse(viewname, urlconf=None, args=None, kwargs=None)
+.. function:: reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
``viewname`` is either the function name (either a function reference, or the
string version of the name, if you used that form in ``urlpatterns``) or the
@@ -620,6 +796,14 @@ vertical bar (``"|"``) character. You can quite happily use such patterns for
matching against incoming URLs and sending them off to views, but you cannot
reverse such patterns.
+.. versionadded:: 1.1
+
+The ``current_app`` argument allows you to provide a hint to the resolver
+indicating the application to which the currently executing view belongs.
+This ``current_app`` argument is used as a hint to resolve application
+namespaces into URLs on specific application instances, according to the
+:ref:`namespaced URL resolution strategy <topics-http-reversing-url-namespaces>`.
+
.. admonition:: Make sure your views are all correct
As part of working out which URL names map to which patterns, the
@@ -639,7 +823,6 @@ resolve()
The :func:`django.core.urlresolvers.resolve` function can be used for resolving
URL paths to the corresponding view functions. It has the following signature:
-.. currentmodule:: django.core.urlresolvers
.. function:: resolve(path, urlconf=None)
``path`` is the URL path you want to resolve. As with ``reverse()`` above, you
diff --git a/docs/topics/i18n.txt b/docs/topics/i18n.txt
index fe8020f86d..9634b0624c 100644
--- a/docs/topics/i18n.txt
+++ b/docs/topics/i18n.txt
@@ -230,7 +230,19 @@ Pluralization
~~~~~~~~~~~~~
Use the function ``django.utils.translation.ungettext()`` to specify pluralized
-messages. Example::
+messages.
+
+``ungettext`` takes three arguments: the singular translation string, the plural
+translation string and the number of objects.
+
+This function is useful when your need you Django application to be localizable
+to languages where the number and complexity of `plural forms
+<http://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms>`_ is
+greater than the two forms used in English ('object' for the singular and
+'objects' for all the cases where ``count`` is different from zero, irrespective
+of its value.)
+
+For example::
from django.utils.translation import ungettext
def hello_world(request, count):
@@ -239,9 +251,61 @@ messages. Example::
}
return HttpResponse(page)
-``ungettext`` takes three arguments: the singular translation string, the plural
-translation string and the number of objects (which is passed to the
-translation languages as the ``count`` variable).
+In this example the number of objects is passed to the translation languages as
+the ``count`` variable.
+
+Lets see a slightly more complex usage example::
+
+ from django.utils.translation import ungettext
+
+ count = Report.objects.count()
+ if count == 1:
+ name = Report._meta.verbose_name
+ else:
+ name = Report._meta.verbose_name_plural
+
+ text = ungettext(
+ 'There is %(count)d %(name)s available.',
+ 'There are %(count)d %(name)s available.',
+ count
+ ) % {
+ 'count': count,
+ 'name': name
+ }
+
+Here we reuse localizable, hopefully already translated literals (contained in
+the ``verbose_name`` and ``verbose_name_plural`` model ``Meta`` options) for
+other parts of the sentence so all of it is consistently based on the
+cardinality of the elements at play.
+
+.. _pluralization-var-notes:
+
+.. note::
+
+ When using this technique, make sure you use a single name for every
+ extrapolated variable included in the literal. In the example above note how
+ we used the ``name`` Python variable in both translation strings. This
+ example would fail::
+
+ from django.utils.translation import ungettext
+ from myapp.models import Report
+
+ count = Report.objects.count()
+ d = {
+ 'count': count,
+ 'name': Report._meta.verbose_name
+ 'plural_name': Report._meta.verbose_name_plural
+ }
+ text = ungettext(
+ 'There is %(count)d %(name)s available.',
+ 'There are %(count)d %(plural_name)s available.',
+ count
+ ) % d
+
+ You would get a ``a format specification for argument 'name', as in
+ 'msgstr[0]', doesn't exist in 'msgid'`` error when running
+ ``django-admin.py compilemessages`` or a ``KeyError`` Python exception at
+ runtime.
In template code
----------------
@@ -264,6 +328,8 @@ content that will require translation in the future::
<title>{% trans "myvar" noop %}</title>
+Internally, inline translations use an ``ugettext`` call.
+
It's not possible to mix a template variable inside a string within ``{% trans
%}``. If your translations require strings with variables (placeholders), use
``{% blocktrans %}``::
@@ -295,8 +361,11 @@ To pluralize, specify both the singular and plural forms with the
There are {{ counter }} {{ name }} objects.
{% endblocktrans %}
-Internally, all block and inline translations use the appropriate
-``ugettext`` / ``ungettext`` call.
+When you use the pluralization feature and bind additional values to local
+variables apart from the counter value that selects the translated literal to be
+used, have in mind that the ``blocktrans`` construct is internally converted
+to an ``ungettext`` call. This means the same :ref:`notes regarding ungettext
+variables <pluralization-var-notes>` apply.
Each ``RequestContext`` has access to three translation-specific variables:
@@ -897,11 +966,11 @@ Using the JavaScript translation catalog
To use the catalog, just pull in the dynamically generated script like this::
- <script type="text/javascript" src="/path/to/jsi18n/"></script>
+ <script type="text/javascript" src="{% url django.views.i18n.javascript_catalog %}"></script>
-This is how the admin fetches the translation catalog from the server. When the
-catalog is loaded, your JavaScript code can use the standard ``gettext``
-interface to access it::
+This uses reverse URL lookup to find the URL of the JavaScript catalog view.
+When the catalog is loaded, your JavaScript code can use the standard
+``gettext`` interface to access it::
document.write(gettext('this is to be translated'));
diff --git a/docs/topics/testing.txt b/docs/topics/testing.txt
index 1256a61187..cec6002b7b 100644
--- a/docs/topics/testing.txt
+++ b/docs/topics/testing.txt
@@ -479,7 +479,7 @@ arguments at time of construction:
Once you have a ``Client`` instance, you can call any of the following
methods:
- .. method:: Client.get(path, data={}, follow=False)
+ .. method:: Client.get(path, data={}, follow=False, **extra)
Makes a GET request on the provided ``path`` and returns a ``Response``
@@ -495,6 +495,17 @@ arguments at time of construction:
/customers/details/?name=fred&age=7
+ The ``extra`` keyword arguments parameter can be used to specify
+ headers to be sent in the request. For example::
+
+ >>> c = Client()
+ >>> c.get('/customers/details/', {'name': 'fred', 'age': 7},
+ ... HTTP_X_REQUESTED_WITH='XMLHttpRequest')
+
+ ...will send the HTTP header ``HTTP_X_REQUESTED_WITH`` to the
+ details view, which is a good way to test code paths that use the
+ :meth:`django.http.HttpRequest.is_ajax()` method.
+
.. versionadded:: 1.1
If you already have the GET arguments in URL-encoded form, you can
@@ -518,7 +529,7 @@ arguments at time of construction:
>>> response.redirect_chain
[(u'http://testserver/next/', 302), (u'http://testserver/final/', 302)]
- .. method:: Client.post(path, data={}, content_type=MULTIPART_CONTENT, follow=False)
+ .. method:: Client.post(path, data={}, content_type=MULTIPART_CONTENT, follow=False, **extra)
Makes a POST request on the provided ``path`` and returns a
``Response`` object, which is documented below.
@@ -569,6 +580,8 @@ arguments at time of construction:
Note that you should manually close the file after it has been provided
to ``post()``.
+ The ``extra`` argument acts the same as for :meth:`Client.get`.
+
.. versionchanged:: 1.1
If the URL you request with a POST contains encoded parameters, these
@@ -585,7 +598,7 @@ arguments at time of construction:
and a ``redirect_chain`` attribute will be set in the response object
containing tuples of the intermediate urls and status codes.
- .. method:: Client.head(path, data={}, follow=False)
+ .. method:: Client.head(path, data={}, follow=False, **extra)
.. versionadded:: 1.1
@@ -597,7 +610,7 @@ arguments at time of construction:
and a ``redirect_chain`` attribute will be set in the response object
containing tuples of the intermediate urls and status codes.
- .. method:: Client.options(path, data={}, follow=False)
+ .. method:: Client.options(path, data={}, follow=False, **extra)
.. versionadded:: 1.1
@@ -608,7 +621,9 @@ arguments at time of construction:
and a ``redirect_chain`` attribute will be set in the response object
containing tuples of the intermediate urls and status codes.
- .. method:: Client.put(path, data={}, content_type=MULTIPART_CONTENT, follow=False)
+ The ``extra`` argument acts the same as for :meth:`Client.get`.
+
+ .. method:: Client.put(path, data={}, content_type=MULTIPART_CONTENT, follow=False, **extra)
.. versionadded:: 1.1
@@ -620,7 +635,7 @@ arguments at time of construction:
and a ``redirect_chain`` attribute will be set in the response object
containing tuples of the intermediate urls and status codes.
- .. method:: Client.delete(path, follow=False)
+ .. method:: Client.delete(path, follow=False, **extra)
.. versionadded:: 1.1
@@ -631,6 +646,8 @@ arguments at time of construction:
and a ``redirect_chain`` attribute will be set in the response object
containing tuples of the intermediate urls and status codes.
+ The ``extra`` argument acts the same as for :meth:`Client.get`.
+
.. method:: Client.login(**credentials)
.. versionadded:: 1.0
@@ -669,7 +686,13 @@ arguments at time of construction:
user accounts that are valid on your production site will not work
under test conditions. You'll need to create users as part of the test
suite -- either manually (using the Django model API) or with a test
- fixture.
+ fixture. Remember that if you want your test user to have a password,
+ you can't set the user's password by setting the password attribute
+ directly -- you must use the
+ :meth:`~django.contrib.auth.models.User.set_password()` function to
+ store a correctly hashed password. Alternatively, you can use the
+ :meth:`~django.contrib.auth.models.UserManager.create_user` helper
+ method to create a new user with a correctly hashed password.
.. method:: Client.logout()