diff options
| author | Kevin Kubasik <kevin@kubasik.net> | 2009-07-22 12:43:04 +0000 |
|---|---|---|
| committer | Kevin Kubasik <kevin@kubasik.net> | 2009-07-22 12:43:04 +0000 |
| commit | 7e26c1047b4e4f471d4f7020a6571e6e8bced0de (patch) | |
| tree | 491f7d3f9e14979d4ebbf4d04a23b15042895744 /docs | |
| parent | b162138e4c2cfe6a4362c0fbf46953ef94ced103 (diff) | |
| parent | 0c9d0bf7d653336c5ee7d15f23adeb098a9f5dba (diff) | |
[gsoc2009-testing] Upstream merge
git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/test-improvements@11292 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/howto/deployment/modwsgi.txt | 187 | ||||
| -rw-r--r-- | docs/intro/tutorial03.txt | 2 | ||||
| -rw-r--r-- | docs/ref/contrib/admin/_images/article_actions.png | bin | 35643 -> 13367 bytes | |||
| -rw-r--r-- | docs/ref/contrib/admin/index.txt | 108 | ||||
| -rw-r--r-- | docs/ref/forms/fields.txt | 41 | ||||
| -rw-r--r-- | docs/ref/models/querysets.txt | 2 | ||||
| -rw-r--r-- | docs/ref/templates/api.txt | 17 | ||||
| -rw-r--r-- | docs/ref/templates/builtins.txt | 10 | ||||
| -rw-r--r-- | docs/topics/forms/formsets.txt | 49 | ||||
| -rw-r--r-- | docs/topics/http/urls.txt | 169 | ||||
| -rw-r--r-- | docs/topics/i18n.txt | 8 | ||||
| -rw-r--r-- | docs/topics/testing.txt | 8 |
12 files changed, 439 insertions, 162 deletions
diff --git a/docs/howto/deployment/modwsgi.txt b/docs/howto/deployment/modwsgi.txt index 902e312551..8bfbfa74f4 100644 --- a/docs/howto/deployment/modwsgi.txt +++ b/docs/howto/deployment/modwsgi.txt @@ -1,69 +1,118 @@ -.. _howto-deployment-modwsgi:
-
-==========================================
-How to use Django with Apache and mod_wsgi
-==========================================
-
-Deploying Django with Apache_ and `mod_wsgi`_ is the recommended way to get
-Django into production.
-
-.. _Apache: http://httpd.apache.org/
-.. _mod_wsgi: http://code.google.com/p/modwsgi/
-
-mod_wsgi is an Apache module which can be used to host any Python application
-which supports the `Python WSGI interface`_, including Django. Django will work
-with any version of Apache which supports mod_wsgi.
-
-.. _python wsgi interface: http://www.python.org/dev/peps/pep-0333/
-
-The `official mod_wsgi documentation`_ is fantastic; it's your source for all
-the details about how to use mod_wsgi. You'll probably want to start with the
-`installation and configuration documentation`_.
-
-.. _official mod_wsgi documentation: http://code.google.com/p/modwsgi/
-.. _installation and configuration documentation: http://code.google.com/p/modwsgi/wiki/InstallationInstructions
-
-Basic Configuration
-===================
-
-Once you've got mod_wsgi installed and activated, edit your ``httpd.conf`` file
-and add::
-
- WSGIScriptAlias / /path/to/mysite/apache/django.wsgi
-
-The first bit above is the url you want to be serving your application at (``/``
-indicates the root url), and the second is the location of a "WSGI file" -- see
-below -- on your system, usually inside of your project. This tells Apache
-to serve any request below the given URL using the WSGI application defined by that file.
-
-Next we'll need to actually create this WSGI application, so create the file
-mentioned in the second part of ``WSGIScriptAlias`` and add::
-
- import os
- import sys
-
- os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
-
- import django.core.handlers.wsgi
- application = django.core.handlers.wsgi.WSGIHandler()
-
-If your project is not on your ``PYTHONPATH`` by default you can add::
-
- sys.path.append('/usr/local/django')
-
-just above the final ``import`` line to place your project on the path. Remember to
-replace 'mysite.settings' with your correct settings file, and '/usr/local/django'
-with your own project's location.
-
-See the :ref:`Apache/mod_python documentation<howto-deployment-modpython>` for
-directions on serving static media, and the `mod_wsgi documentation`_ for an
-explanation of other directives and configuration options you can use.
-
-Details
-=======
-
-For more details, see the `mod_wsgi documentation`_, which explains the above in
-more detail, and walks through all the various options you've got when deploying
-under mod_wsgi.
-
-.. _mod_wsgi documentation: http://code.google.com/p/modwsgi/wiki/IntegrationWithDjango
+.. _howto-deployment-modwsgi: + +========================================== +How to use Django with Apache and mod_wsgi +========================================== + +Deploying Django with Apache_ and `mod_wsgi`_ is the recommended way to get +Django into production. + +.. _Apache: http://httpd.apache.org/ +.. _mod_wsgi: http://code.google.com/p/modwsgi/ + +mod_wsgi is an Apache module which can be used to host any Python application +which supports the `Python WSGI interface`_, including Django. Django will work +with any version of Apache which supports mod_wsgi. + +.. _python wsgi interface: http://www.python.org/dev/peps/pep-0333/ + +The `official mod_wsgi documentation`_ is fantastic; it's your source for all +the details about how to use mod_wsgi. You'll probably want to start with the +`installation and configuration documentation`_. + +.. _official mod_wsgi documentation: http://code.google.com/p/modwsgi/ +.. _installation and configuration documentation: http://code.google.com/p/modwsgi/wiki/InstallationInstructions + +Basic Configuration +=================== + +Once you've got mod_wsgi installed and activated, edit your ``httpd.conf`` file +and add:: + + WSGIScriptAlias / /path/to/mysite/apache/django.wsgi + +The first bit above is the url you want to be serving your application at (``/`` +indicates the root url), and the second is the location of a "WSGI file" -- see +below -- on your system, usually inside of your project. This tells Apache +to serve any request below the given URL using the WSGI application defined by that file. + +Next we'll need to actually create this WSGI application, so create the file +mentioned in the second part of ``WSGIScriptAlias`` and add:: + + import os + import sys + + os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings' + + import django.core.handlers.wsgi + application = django.core.handlers.wsgi.WSGIHandler() + +If your project is not on your ``PYTHONPATH`` by default you can add:: + + sys.path.append('/usr/local/django') + +just above the final ``import`` line to place your project on the path. Remember to +replace 'mysite.settings' with your correct settings file, and '/usr/local/django' +with your own project's location. + +Serving media files +=================== + +Django doesn't serve media files itself; it leaves that job to whichever Web +server you choose. + +We recommend using a separate Web server -- i.e., one that's not also running +Django -- for serving media. Here are some good choices: + + * lighttpd_ + * Nginx_ + * TUX_ + * A stripped-down version of Apache_ + * Cherokee_ + +If, however, you have no option but to serve media files on the same Apache +``VirtualHost`` as Django, you can set up Apache to serve some URLs as +static media, and others using the mod_wsgi interface to Django. + +This example sets up Django at the site root, but explicitly serves ``robots.txt``, +``favicon.ico``, any CSS file, and anything in the ``/media/`` URL space as a static +file. All other URLs will be served using mod_wsgi:: + + Alias /robots.txt /usr/local/wsgi/static/robots.txt + Alias /favicon.ico /usr/local/wsgi/static/favicon.ico + + AliasMatch /([^/]*\.css) /usr/local/wsgi/static/styles/$1 + + Alias /media/ /usr/local/wsgi/static/media/ + + <Directory /usr/local/wsgi/static> + Order deny,allow + Allow from all + </Directory> + + WSGIScriptAlias / /usr/local/wsgi/scripts/django.wsgi + + <Directory /usr/local/wsgi/scripts> + Order allow,deny + Allow from all + </Directory> + +.. _lighttpd: http://www.lighttpd.net/ +.. _Nginx: http://wiki.codemongers.com/Main +.. _TUX: http://en.wikipedia.org/wiki/TUX_web_server +.. _Apache: http://httpd.apache.org/ +.. _Cherokee: http://www.cherokee-project.com/ + +More details on configuring a mod_wsgi site to serve static files can be found +in the mod_wsgi documentation on `hosting static files`_. + +.. _hosting static files: http://code.google.com/p/modwsgi/wiki/ConfigurationGuidelines#Hosting_Of_Static_Files + +Details +======= + +For more details, see the `mod_wsgi documentation on Django integration`_, +which explains the above in more detail, and walks through all the various +options you've got when deploying under mod_wsgi. + +.. _mod_wsgi documentation on Django integration: http://code.google.com/p/modwsgi/wiki/IntegrationWithDjango diff --git a/docs/intro/tutorial03.txt b/docs/intro/tutorial03.txt index f4ef5f76fe..687407a284 100644 --- a/docs/intro/tutorial03.txt +++ b/docs/intro/tutorial03.txt @@ -365,7 +365,7 @@ That takes care of setting ``handler404`` in the current module. As you can see in ``django/conf/urls/defaults.py``, ``handler404`` is set to :func:`django.views.defaults.page_not_found` by default. -Three more things to note about 404 views: +Four more things to note about 404 views: * If :setting:`DEBUG` is set to ``True`` (in your settings module) then your 404 view will never be used (and thus the ``404.html`` template will never diff --git a/docs/ref/contrib/admin/_images/article_actions.png b/docs/ref/contrib/admin/_images/article_actions.png Binary files differindex 254a8ad557..df4ab8f1ec 100644 --- a/docs/ref/contrib/admin/_images/article_actions.png +++ b/docs/ref/contrib/admin/_images/article_actions.png diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt index 394ebd1f24..584672e4f0 100644 --- a/docs/ref/contrib/admin/index.txt +++ b/docs/ref/contrib/admin/index.txt @@ -762,12 +762,19 @@ documented in :ref:`topics-http-urls`:: anything, so you'll usually want to prepend your custom URLs to the built-in ones. -Note, however, that the ``self.my_view`` function registered above will *not* -have any permission check done; it'll be accessible to the general public. Since -this is usually not what you want, Django provides a convience wrapper to check -permissions. This wrapper is :meth:`AdminSite.admin_view` (i.e. -``self.admin_site.admin_view`` inside a ``ModelAdmin`` instance); use it like -so:: +However, the ``self.my_view`` function registered above suffers from two +problems: + + * It will *not* perform and permission checks, so it will be accessible to + the general public. + * It will *not* provide any header details to prevent caching. This means if + the page retrieves data from the database, and caching middleware is + active, the page could show outdated information. + +Since this is usually not what you want, Django provides a convenience wrapper +to check permissions and mark the view as non-cacheable. This wrapper is +:meth:`AdminSite.admin_view` (i.e. ``self.admin_site.admin_view`` inside a +``ModelAdmin`` instance); use it like so:: class MyModelAdmin(admin.ModelAdmin): def get_urls(self): @@ -781,7 +788,14 @@ Notice the wrapped view in the fifth line above:: (r'^my_view/$', self.admin_site.admin_view(self.my_view)) -This wrapping will protect ``self.my_view`` from unauthorized access. +This wrapping will protect ``self.my_view`` from unauthorized access and will +apply the ``django.views.decorators.cache.never_cache`` decorator to make sure +it is not cached if the cache middleware is active. + +If the page is cacheable, but you still want the permission check to be performed, +you can pass a ``cacheable=True`` argument to :meth:`AdminSite.admin_view`:: + + (r'^my_view/$', self.admin_site.admin_view(self.my_view, cacheable=True)) .. method:: ModelAdmin.formfield_for_foreignkey(self, db_field, request, **kwargs) @@ -1228,7 +1242,7 @@ or :attr:`AdminSite.login_template` properties. ``AdminSite`` objects ===================== -.. class:: AdminSite +.. class:: AdminSite(name=None) A Django administrative site is represented by an instance of ``django.contrib.admin.sites.AdminSite``; by default, an instance of @@ -1242,6 +1256,14 @@ or add anything you like. Then, simply create an instance of your Python class), and register your models and ``ModelAdmin`` subclasses with it instead of using the default. +.. versionadded:: 1.1 + +When constructing an instance of an ``AdminSite``, you are able to provide +a unique instance name using the ``name`` argument to the constructor. This +instance name is used to identify the instance, especially when +:ref:`reversing admin URLs <admin-reverse-urls>`. If no instance name is +provided, a default instance name of ``admin`` will be used. + ``AdminSite`` attributes ------------------------ @@ -1339,10 +1361,10 @@ a pattern for your new view. .. note:: Any view you render that uses the admin templates, or extends the base - admin template, should include in it's context a variable named - ``admin_site`` that contains the name of the :class:`AdminSite` instance. For - :class:`AdminSite` instances, this means ``self.name``; for :class:`ModelAdmin` - instances, this means ``self.admin_site.name``. + admin template, should provide the ``current_app`` argument to + ``RequestContext`` or ``Context`` when rendering the template. It should + be set to either ``self.name`` if your view is on an ``AdminSite`` or + ``self.admin_site.name`` if your view is on a ``ModelAdmin``. .. _admin-reverse-urls: @@ -1356,37 +1378,31 @@ accessible using Django's :ref:`URL reversing system <naming-url-patterns>`. The :class:`AdminSite` provides the following named URL patterns: - ====================== =============================== ============= - Page URL name Parameters - ====================== =============================== ============= - Index ``admin_index`` - Logout ``admin_logout`` - Password change ``admin_password_change`` - Password change done ``admin_password_change_done`` - i18n javascript ``admin_jsi18n`` - Application index page ``admin_app_list`` ``app_label`` - ====================== =============================== ============= - -These names will be prefixed with the name of the :class:`AdminSite` instance, -plus an underscore. For example, if your :class:`AdminSite` was named -``custom``, then the Logout view would be served using a URL with the name -``custom_admin_logout``. The default :class:`AdminSite` doesn't use a prefix -in it's URL names. + ====================== ======================== ============= + Page URL name Parameters + ====================== ======================== ============= + Index ``index`` + Logout ``logout`` + Password change ``password_change`` + Password change done ``password_change_done`` + i18n javascript ``jsi18n`` + Application index page ``app_list`` ``app_label`` + ====================== ======================== ============= Each :class:`ModelAdmin` instance provides an additional set of named URLs: - ====================== ===================================================== ============= - Page URL name Parameters - ====================== ===================================================== ============= - Changelist ``admin_{{ app_label }}_{{ model_name }}_changelist`` - Add ``admin_{{ app_label }}_{{ model_name }}_add`` - History ``admin_{{ app_label }}_{{ model_name }}_history`` ``object_id`` - Delete ``admin_{{ app_label }}_{{ model_name }}_delete`` ``object_id`` - Change ``admin_{{ app_label }}_{{ model_name }}_change`` ``object_id`` - ====================== ===================================================== ============= + ====================== =============================================== ============= + Page URL name Parameters + ====================== =============================================== ============= + Changelist ``{{ app_label }}_{{ model_name }}_changelist`` + Add ``{{ app_label }}_{{ model_name }}_add`` + History ``{{ app_label }}_{{ model_name }}_history`` ``object_id`` + Delete ``{{ app_label }}_{{ model_name }}_delete`` ``object_id`` + Change ``{{ app_label }}_{{ model_name }}_change`` ``object_id`` + ====================== =============================================== ============= -Again, these names will be prefixed by the name of the :class:`AdminSite` in -which they are deployed. +These named URLs are registered with the application namespace ``admin``, and +with an instance namespace corresponding to the name of the Site instance. So - if you wanted to get a reference to the Change view for a particular ``Choice`` object (from the polls application) in the default admin, you would @@ -1394,8 +1410,16 @@ call:: >>> from django.core import urlresolvers >>> c = Choice.objects.get(...) - >>> change_url = urlresolvers.reverse('admin_polls_choice_change', args=(c.id,)) + >>> change_url = urlresolvers.reverse('admin:polls_choice_change', args=(c.id,)) + +This will find the first registered instance of the admin application (whatever the instance +name), and resolve to the view for changing ``poll.Choice`` instances in that instance. + +If you want to find a URL in a specific admin instance, provide the name of that instance +as a ``current_app`` hint to the reverse call. For example, if you specifically wanted +the admin view from the admin instance named ``custom``, you would need to call:: -However, if the admin instance was named ``custom``, you would need to call:: + >>> change_url = urlresolvers.reverse('custom:polls_choice_change', args=(c.id,)) - >>> change_url = urlresolvers.reverse('custom_admin_polls_choice_change', args=(c.id,)) +For more details, see the documentation on :ref:`reversing namespaced URLs +<topics-http-reversing-url-namespaces>`. diff --git a/docs/ref/forms/fields.txt b/docs/ref/forms/fields.txt index e532971179..4bb6a7c444 100644 --- a/docs/ref/forms/fields.txt +++ b/docs/ref/forms/fields.txt @@ -275,7 +275,7 @@ For each field, we describe the default widget used if you don't specify * Default widget: ``CheckboxInput`` * Empty value: ``False`` * Normalizes to: A Python ``True`` or ``False`` value. - * Validates that the check box is checked (i.e. the value is ``True``) if + * Validates that the value is ``True`` (e.g. the check box is checked) if the field has ``required=True``. * Error message keys: ``required`` @@ -287,9 +287,10 @@ For each field, we describe the default widget used if you don't specify .. note:: Since all ``Field`` subclasses have ``required=True`` by default, the - validation condition here is important. If you want to include a checkbox - in your form that can be either checked or unchecked, you must remember to - pass in ``required=False`` when creating the ``BooleanField``. + validation condition here is important. If you want to include a boolean + in your form that can be either ``True`` or ``False`` (e.g. a checked or + unchecked checkbox), you must remember to pass in ``required=False`` when + creating the ``BooleanField``. ``CharField`` ~~~~~~~~~~~~~ @@ -328,7 +329,7 @@ Takes one extra required argument: An iterable (e.g., a list or tuple) of 2-tuples to use as choices for this field. - + ``TypedChoiceField`` ~~~~~~~~~~~~~~~~~~~~ @@ -437,7 +438,7 @@ If no ``input_formats`` argument is provided, the default input formats are:: ``min_value``, ``max_digits``, ``max_decimal_places``, ``max_whole_digits`` -Takes four optional arguments: +Takes four optional arguments: .. attribute:: DecimalField.max_value .. attribute:: DecimalField.min_value @@ -449,7 +450,7 @@ Takes four optional arguments: The maximum number of digits (those before the decimal point plus those after the decimal point, with leading zeros stripped) permitted in the value. - + .. attribute:: DecimalField.decimal_places The maximum number of decimal places permitted. @@ -522,18 +523,18 @@ extra arguments; only ``path`` is required: A regular expression pattern; only files with names matching this expression will be allowed as choices. -``FloatField`` -~~~~~~~~~~~~~~ +``FloatField`` +~~~~~~~~~~~~~~ + + * Default widget: ``TextInput`` + * Empty value: ``None`` + * Normalizes to: A Python float. + * Validates that the given value is an float. Leading and trailing + whitespace is allowed, as in Python's ``float()`` function. + * Error message keys: ``required``, ``invalid``, ``max_value``, + ``min_value`` - * Default widget: ``TextInput`` - * Empty value: ``None`` - * Normalizes to: A Python float. - * Validates that the given value is an float. Leading and trailing - whitespace is allowed, as in Python's ``float()`` function. - * Error message keys: ``required``, ``invalid``, ``max_value``, - ``min_value`` - -Takes two optional arguments for validation, ``max_value`` and ``min_value``. +Takes two optional arguments for validation, ``max_value`` and ``min_value``. These control the range of values permitted in the field. ``ImageField`` @@ -779,10 +780,10 @@ example:: (which is ``"---------"`` by default) with the ``empty_label`` attribute, or you can disable the empty label entirely by setting ``empty_label`` to ``None``:: - + # A custom empty label field1 = forms.ModelChoiceField(queryset=..., empty_label="(Nothing)") - + # No empty label field2 = forms.ModelChoiceField(queryset=..., empty_label=None) diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt index 348486b341..f78ebc506a 100644 --- a/docs/ref/models/querysets.txt +++ b/docs/ref/models/querysets.txt @@ -668,7 +668,7 @@ of the arguments is required, but you should use at least one of them. The resulting SQL of the above example would be:: - SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id) + SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id) AS entry_count FROM blog_blog; Note that the parenthesis required by most database engines around diff --git a/docs/ref/templates/api.txt b/docs/ref/templates/api.txt index 05097b7e59..e3260a96f8 100644 --- a/docs/ref/templates/api.txt +++ b/docs/ref/templates/api.txt @@ -86,9 +86,16 @@ Rendering a context Once you have a compiled ``Template`` object, you can render a context -- or multiple contexts -- with it. The ``Context`` class lives at -``django.template.Context``, and the constructor takes one (optional) -argument: a dictionary mapping variable names to variable values. Call the -``Template`` object's ``render()`` method with the context to "fill" the +``django.template.Context``, and the constructor takes two (optional) +arguments: + + * A dictionary mapping variable names to variable values. + + * The name of the current application. This application name is used + to help :ref:`resolve namespaced URLs<topics-http-reversing-url-namespaces>`. + If you're not using namespaced URLs, you can ignore this argument. + +Call the ``Template`` object's ``render()`` method with the context to "fill" the template:: >>> from django.template import Context, Template @@ -549,13 +556,13 @@ Here are the template loaders that come with Django: Note that the loader performs an optimization when it is first imported: It caches a list of which :setting:`INSTALLED_APPS` packages have a ``templates`` subdirectory. - + This loader is enabled by default. ``django.template.loaders.eggs.load_template_source`` Just like ``app_directories`` above, but it loads templates from Python eggs rather than from the filesystem. - + This loader is disabled by default. Django uses the template loaders in order according to the diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt index aedad6562f..a2f8b9f8b3 100644 --- a/docs/ref/templates/builtins.txt +++ b/docs/ref/templates/builtins.txt @@ -795,6 +795,16 @@ missing. In practice you'll use this to link to views that are optional:: <a href="{{ the_url }}">Link to optional stuff</a> {% endif %} +.. versionadded:: 1.1 + +If you'd like to retrieve a namespaced URL, specify the fully qualified name:: + + {% url myapp:view-name %} + +This will follow the normal :ref:`namespaced URL resolution strategy +<topics-http-reversing-url-namespaces>`, including using any hints provided +by the context as to the current application. + .. templatetag:: widthratio widthratio 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 17978d4328..b2e99dce7f 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. @@ -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,12 +273,14 @@ value should suffice. include ------- +.. 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 -:meth:``include`` also accepts as an argument an iterable that returns URL +:func:`include` also accepts as an argument an iterable that returns URL patterns. See `Including other URLconfs`_ below. @@ -400,7 +412,7 @@ further processing. .. versionadded:: 1.1 -Another posibility is to include additional URL patterns not by specifying the +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:: @@ -417,6 +429,13 @@ directly the pattern list as returned by `patterns`_ instead. For example:: (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 @@ -439,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 _`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 ======================================= @@ -613,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`` 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 2, 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 =============== @@ -623,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 @@ -646,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 @@ -665,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 7bf51c11c5..c5f4ab6481 100644 --- a/docs/topics/i18n.txt +++ b/docs/topics/i18n.txt @@ -959,11 +959,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 78a0796308..d066ca086a 100644 --- a/docs/topics/testing.txt +++ b/docs/topics/testing.txt @@ -691,7 +691,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() |
