From 986bcffed2c2ab85a1cd3ebe520b7d725d921846 Mon Sep 17 00:00:00 2001 From: Marc Garcia Date: Tue, 4 Aug 2009 14:56:04 +0000 Subject: [soc2009/i18n] merged up to trunk r11385 git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/i18n-improvements@11388 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- docs/_ext/djangodocs.py | 53 ++- docs/_templates/layout.html | 2 +- docs/faq/admin.txt | 19 +- docs/howto/custom-model-fields.txt | 2 +- docs/howto/deployment/modpython.txt | 25 +- docs/howto/deployment/modwsgi.txt | 187 +++++---- docs/howto/error-reporting.txt | 10 +- docs/index.txt | 3 +- docs/internals/committers.txt | 57 ++- docs/internals/deprecation.txt | 21 + docs/internals/index.txt | 3 +- docs/internals/release-process.txt | 31 +- docs/intro/tutorial03.txt | 6 +- docs/ref/contrib/admin/_images/article_actions.png | Bin 35643 -> 13367 bytes docs/ref/contrib/admin/index.txt | 114 +++-- docs/ref/contrib/contenttypes.txt | 4 +- docs/ref/databases.txt | 2 +- docs/ref/forms/fields.txt | 43 +- docs/ref/middleware.txt | 15 +- docs/ref/models/instances.txt | 42 +- docs/ref/models/querysets.txt | 2 +- docs/ref/templates/api.txt | 17 +- docs/ref/templates/builtins.txt | 37 +- docs/releases/1.1-rc-1.txt | 111 +++++ docs/releases/1.1.txt | 459 +++++++++++++++++++++ docs/releases/index.txt | 4 +- docs/topics/forms/formsets.txt | 49 ++- docs/topics/http/urls.txt | 203 ++++++++- docs/topics/i18n.txt | 89 +++- docs/topics/testing.txt | 37 +- 30 files changed, 1374 insertions(+), 273 deletions(-) create mode 100644 docs/internals/deprecation.txt create mode 100644 docs/releases/1.1-rc-1.txt create mode 100644 docs/releases/1.1.txt (limited to 'docs') diff --git a/docs/_ext/djangodocs.py b/docs/_ext/djangodocs.py index 65a823e10b..af07a84f32 100644 --- a/docs/_ext/djangodocs.py +++ b/docs/_ext/djangodocs.py @@ -6,10 +6,16 @@ import docutils.nodes import docutils.transforms import sphinx import sphinx.addnodes -import sphinx.builder +try: + from sphinx import builders +except ImportError: + import sphinx.builder as builders import sphinx.directives import sphinx.environment -import sphinx.htmlwriter +try: + import sphinx.writers.html as sphinx_htmlwriter +except ImportError: + import sphinx.htmlwriter as sphinx_htmlwriter import sphinx.roles from docutils import nodes @@ -44,7 +50,7 @@ def setup(app): directivename = "django-admin-option", rolename = "djadminopt", indextemplate = "pair: %s; django-admin command-line option", - parse_node = lambda env, sig, signode: sphinx.directives.parse_option_desc(signode, sig), + parse_node = parse_django_adminopt_node, ) app.add_config_value('django_next_version', '0.0', True) app.add_directive('versionadded', parse_version_directive, 1, (1, 1, 1)) @@ -102,7 +108,7 @@ class SuppressBlockquotes(docutils.transforms.Transform): if len(node.children) == 1 and isinstance(node.children[0], self.suppress_blockquote_child_nodes): node.replace_self(node.children[0]) -class DjangoHTMLTranslator(sphinx.htmlwriter.SmartyPantsHTMLTranslator): +class DjangoHTMLTranslator(sphinx_htmlwriter.SmartyPantsHTMLTranslator): """ Django-specific reST to HTML tweaks. """ @@ -125,10 +131,10 @@ class DjangoHTMLTranslator(sphinx.htmlwriter.SmartyPantsHTMLTranslator): # def visit_literal_block(self, node): self.no_smarty += 1 - sphinx.htmlwriter.SmartyPantsHTMLTranslator.visit_literal_block(self, node) - + sphinx_htmlwriter.SmartyPantsHTMLTranslator.visit_literal_block(self, node) + def depart_literal_block(self, node): - sphinx.htmlwriter.SmartyPantsHTMLTranslator.depart_literal_block(self, node) + sphinx_htmlwriter.SmartyPantsHTMLTranslator.depart_literal_block(self, node) self.no_smarty -= 1 # @@ -162,7 +168,7 @@ class DjangoHTMLTranslator(sphinx.htmlwriter.SmartyPantsHTMLTranslator): # Give each section a unique ID -- nice for custom CSS hooks # This is different on docutils 0.5 vs. 0.4... - if hasattr(sphinx.htmlwriter.SmartyPantsHTMLTranslator, 'start_tag_with_title') and sphinx.__version__ == '0.4.2': + if hasattr(sphinx_htmlwriter.SmartyPantsHTMLTranslator, 'start_tag_with_title') and sphinx.__version__ == '0.4.2': def start_tag_with_title(self, node, tagname, **atts): node = { 'classes': node.get('classes', []), @@ -176,7 +182,7 @@ class DjangoHTMLTranslator(sphinx.htmlwriter.SmartyPantsHTMLTranslator): node['ids'] = ['s-' + i for i in old_ids] if sphinx.__version__ != '0.4.2': node['ids'].extend(old_ids) - sphinx.htmlwriter.SmartyPantsHTMLTranslator.visit_section(self, node) + sphinx_htmlwriter.SmartyPantsHTMLTranslator.visit_section(self, node) node['ids'] = old_ids def parse_django_admin_node(env, sig, signode): @@ -186,6 +192,25 @@ def parse_django_admin_node(env, sig, signode): signode += sphinx.addnodes.desc_name(title, title) return sig +def parse_django_adminopt_node(env, sig, signode): + """A copy of sphinx.directives.CmdoptionDesc.parse_signature()""" + from sphinx import addnodes + from sphinx.directives.desc import option_desc_re + count = 0 + firstname = '' + for m in option_desc_re.finditer(sig): + optname, args = m.groups() + if count: + signode += addnodes.desc_addname(', ', ', ') + signode += addnodes.desc_name(optname, optname) + signode += addnodes.desc_addname(args, args) + if not count: + firstname = optname + count += 1 + if not firstname: + raise ValueError + return firstname + def monkeypatch_pickle_builder(): import shutil from os import path @@ -214,12 +239,12 @@ def monkeypatch_pickle_builder(): # copy the environment file from the doctree dir to the output dir # as needed by the web app - shutil.copyfile(path.join(self.doctreedir, sphinx.builder.ENV_PICKLE_FILENAME), - path.join(self.outdir, sphinx.builder.ENV_PICKLE_FILENAME)) + shutil.copyfile(path.join(self.doctreedir, builders.ENV_PICKLE_FILENAME), + path.join(self.outdir, builders.ENV_PICKLE_FILENAME)) # touch 'last build' file, used by the web application to determine # when to reload its environment and clear the cache - open(path.join(self.outdir, sphinx.builder.LAST_BUILD_FILENAME), 'w').close() + open(path.join(self.outdir, builders.LAST_BUILD_FILENAME), 'w').close() + + builders.PickleHTMLBuilder.handle_finish = handle_finish - sphinx.builder.PickleHTMLBuilder.handle_finish = handle_finish - diff --git a/docs/_templates/layout.html b/docs/_templates/layout.html index eb42298ab3..5bf1da6a37 100644 --- a/docs/_templates/layout.html +++ b/docs/_templates/layout.html @@ -1,6 +1,6 @@ {% extends "!layout.html" %} -{%- macro secondnav %} +{%- macro secondnav() %} {%- if prev %} « previous {{ reldelim2 }} diff --git a/docs/faq/admin.txt b/docs/faq/admin.txt index c23bdd1fe9..4c7b570f00 100644 --- a/docs/faq/admin.txt +++ b/docs/faq/admin.txt @@ -37,20 +37,19 @@ Set the :setting:`CACHE_MIDDLEWARE_ANONYMOUS_ONLY` setting to ``True``. See the How do I automatically set a field's value to the user who last edited the object in the admin? ----------------------------------------------------------------------------------------------- -At this point, Django doesn't have an official way to do this. But it's an oft-requested -feature, so we're discussing how it can be implemented. The problem is we don't want to couple -the model layer with the admin layer with the request layer (to get the current user). It's a -tricky problem. - -One person hacked up a `solution that doesn't require patching Django`_, but note that it's an -unofficial solution, and there's no guarantee it won't break at some point. - -.. _solution that doesn't require patching Django: http://lukeplant.me.uk/blog.php?id=1107301634 +The :class:`ModelAdmin` class provides customization hooks that allow you to transform +an object as it saved, using details from the request. By extracting the current user +from the request, and customizing the :meth:`ModelAdmin.save_model` hook, you can update +an object to reflect the user that edited it. See :ref:`the documentation on ModelAdmin +methods ` for an example. How do I limit admin access so that objects can only be edited by the users who created them? --------------------------------------------------------------------------------------------- -See the answer to the previous question. +The :class:`ModelAdmin` class also provides customization hooks that allow you to control the +visibility and editability of objects in the admin. Using the same trick of extracting the +user from the request, the :meth:`ModelAdmin.queryset` and :meth:`ModelAdmin.has_change_permission` +can be used to control the visibility and editability of objects in the admin. My admin-site CSS and images showed up fine using the development server, but they're not displaying when using mod_python. --------------------------------------------------------------------------------------------------------------------------- diff --git a/docs/howto/custom-model-fields.txt b/docs/howto/custom-model-fields.txt index 709ea49b87..9f798f14d5 100644 --- a/docs/howto/custom-model-fields.txt +++ b/docs/howto/custom-model-fields.txt @@ -464,7 +464,7 @@ should raise either a ``ValueError`` if the ``value`` is of the wrong sort (a list when you were expecting an object, for example) or a ``TypeError`` if your field does not support that type of lookup. For many fields, you can get by with handling the lookup types that need special handling for your field -and pass the rest of the :meth:`get_db_prep_lookup` method of the parent class. +and pass the rest to the :meth:`get_db_prep_lookup` method of the parent class. If you needed to implement ``get_db_prep_save()``, you will usually need to implement ``get_db_prep_lookup()``. If you don't, ``get_db_prep_value`` will be diff --git a/docs/howto/deployment/modpython.txt b/docs/howto/deployment/modpython.txt index 9ba1c2f9fb..8b9a4d3696 100644 --- a/docs/howto/deployment/modpython.txt +++ b/docs/howto/deployment/modpython.txt @@ -6,8 +6,8 @@ How to use Django with Apache and mod_python .. highlight:: apache -The `mod_python`_ module for Apache_ can be used to deploy Django to a -production server, although it has been mostly superseded by the simpler +The `mod_python`_ module for Apache_ can be used to deploy Django to a +production server, although it has been mostly superseded by the simpler :ref:`mod_wsgi deployment option `. mod_python is similar to (and inspired by) `mod_perl`_ : It embeds Python within @@ -378,3 +378,24 @@ as necessary. .. _Expat Causing Apache Crash: http://www.dscpl.com.au/articles/modpython-006.html .. _mod_python FAQ entry: http://modpython.org/FAQ/faqw.py?req=show&file=faq02.013.htp .. _Getting mod_python Working: http://www.dscpl.com.au/articles/modpython-001.html + +If you get a UnicodeEncodeError +=============================== + +If you're taking advantage of the internationalization features of Django (see +:ref:`topics-i18n`) and you intend to allow users to upload files, you must +ensure that the environment used to start Apache is configured to accept +non-ASCII file names. If your environment is not correctly configured, you +will trigger ``UnicodeEncodeError`` exceptions when calling functions like +``os.path()`` on filenames that contain non-ASCII characters. + +To avoid these problems, the environment used to start Apache should contain +settings analogous to the following:: + + export LANG='en_US.UTF-8' + export LC_ALL='en_US.UTF-8' + +Consult the documentation for your operating system for the appropriate syntax +and location to put these configuration items; ``/etc/apache2/envvars`` is a +common location on Unix platforms. Once you have added these statements +to your environment, restart Apache. 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` 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/ + + + Order deny,allow + Allow from all + + + WSGIScriptAlias / /usr/local/wsgi/scripts/django.wsgi + + + Order allow,deny + Allow from all + + +.. _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/howto/error-reporting.txt b/docs/howto/error-reporting.txt index e0750ce327..246e7445d0 100644 --- a/docs/howto/error-reporting.txt +++ b/docs/howto/error-reporting.txt @@ -23,6 +23,10 @@ administrators immediate notification of any errors. The :setting:`ADMINS` will get a description of the error, a complete Python traceback, and details about the HTTP request that caused the error. +By default, Django will send email from root@localhost. However, some mail +providers reject all email from this address. To use a different sender +address, modify the :setting:`SERVER_EMAIL` setting. + To disable this behavior, just remove all entries from the :setting:`ADMINS` setting. @@ -33,12 +37,12 @@ Django can also be configured to email errors about broken links (404 "page not found" errors). Django sends emails about 404 errors when: * :setting:`DEBUG` is ``False`` - + * :setting:`SEND_BROKEN_LINK_EMAILS` is ``True`` - + * Your :setting:`MIDDLEWARE_CLASSES` setting includes ``CommonMiddleware`` (which it does by default). - + If those conditions are met, Django will e-mail the users listed in the :setting:`MANAGERS` setting whenever your code raises a 404 and the request has a referer. (It doesn't bother to e-mail for 404s that don't have a referer -- diff --git a/docs/index.txt b/docs/index.txt index 89ee463dfa..86105372c4 100644 --- a/docs/index.txt +++ b/docs/index.txt @@ -200,6 +200,7 @@ The Django open-source project * **Django over time:** :ref:`API stability ` | - :ref:`Archive of release notes ` | `Backwards-incompatible changes`_ + :ref:`Archive of release notes ` | `Backwards-incompatible changes`_ | + :ref:`Deprecation Timeline ` .. _Backwards-incompatible changes: http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges diff --git a/docs/internals/committers.txt b/docs/internals/committers.txt index 002c7f5ab8..7326532ec9 100644 --- a/docs/internals/committers.txt +++ b/docs/internals/committers.txt @@ -135,24 +135,49 @@ Joseph Kocherhans .. _michael meeks: http://en.wikipedia.org/wiki/Michael_Meeks_(software) `Brian Rosner`_ - Brian is currently a web developer working on an e-commerce system in - Django. He spends his free time contributing to Django and enjoys to learn - more about programming languages and system architectures. Brian is the - co-host of the weekly podcast, `This Week in Django`_. - + Brian is currently the tech lead at Eldarion_ managing and developing + Django / Pinax_ based websites. He enjoys learning more about programming + languages and system architectures and contributing to open source + projects. Brian is the host of the `Django Dose`_ podcasts. + Brian helped immensely in getting Django's "newforms-admin" branch finished in time for Django 1.0; he's now a full committer, continuing to improve on the admin and forms system. - Brian lives in Denver, USA. + Brian lives in Denver, Colorado, USA. .. _brian rosner: http://oebfare.com/ -.. _this week in django: http://thisweekindjango.com/ +.. _eldarion: http://eldarion.com/ +.. _pinax: http://pinaxproject.com/ +.. _django dose: http://djangodose.com/ + +`Gary Wilson`_ + Gary starting contributing patches to Django in 2006 while developing Web + applications for `The University of Texas`_ (UT). Since, he has made + contributions to the e-mail and forms systems, as well as many other + improvements and code cleanups throughout the code base. + + Gary is currently a developer and software engineering graduate student at + UT, where his dedication to spreading the ways of Python and Django never + ceases. + + Gary lives in Austin, Texas, USA. + +.. _Gary Wilson: http://gdub.wordpress.com/ +.. _The University of Texas: http://www.utexas.edu/ + +Justin Bronn + Justin Bronn is a computer scientist and attorney specializing + in legal topics related to intellectual property and spatial law. + + In 2007, Justin began developing ``django.contrib.gis`` in a branch, + a.k.a. GeoDjango_, which was merged in time for Django 1.0. While + implementing GeoDjango, Justin obtained a deep knowledge of Django's + internals including the ORM, the admin, and Oracle support. -Gary Wilson - In early 2007, Gary started contributing a lot of cleanup fixes and fixing - broken windows. He's continued to do that necessary tidying up work - throughout the code base since then. + Justin lives in Houston, Texas. + +.. _GeoDjango: http://geodjango.org/ Karen Tracey Karen has a background in distributed operating systems (graduate school), @@ -187,16 +212,6 @@ Ian Kelly Matt Boersma Matt is also responsible for Django's Oracle support. -Justin Bronn - Justin Bronn is a computer scientist and third-year law student at the - University of Houston who enjoys studying legal topics related to - intellectual property and spatial law. - - Justin is the primary developer of ``django.contrib.gis``, a.k.a. - GeoDjango_. - -.. _GeoDjango: http://geodjango.org/ - Jeremy Dunck Jeremy the lead developer of Pegasus News, a personalized local site based in Dallas, Texas. An early contributor to Greasemonkey and Django, he sees diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt new file mode 100644 index 0000000000..7e7f4c6338 --- /dev/null +++ b/docs/internals/deprecation.txt @@ -0,0 +1,21 @@ +.. _internals-deprecation: + +=========================== +Django Deprecation Timeline +=========================== + +This document outlines when various pieces of Django will be removed, following +their deprecation, as per the :ref:`Django deprecation policy +` + + * 1.3 + * ``AdminSite.root()``. This release will remove the old method for + hooking up admin URLs. This has been deprecated since the 1.1 + release. + + * 2.0 + * ``django.views.defaults.shortcut()``. This function has been moved + to ``django.contrib.contenttypes.views.shortcut()`` as part of the + goal of removing all ``django.contrib`` references from the core + Django codebase. The old shortcut will be removed in the 2.0 + release. diff --git a/docs/internals/index.txt b/docs/internals/index.txt index 0d54948bf5..1cbbb87f06 100644 --- a/docs/internals/index.txt +++ b/docs/internals/index.txt @@ -17,8 +17,9 @@ the hood". .. toctree:: :maxdepth: 1 - + contributing documentation committers release-process + deprecation diff --git a/docs/internals/release-process.txt b/docs/internals/release-process.txt index 911b67e441..6d4ad9e8c9 100644 --- a/docs/internals/release-process.txt +++ b/docs/internals/release-process.txt @@ -48,14 +48,16 @@ Minor releases -------------- Minor release (1.1, 1.2, etc.) will happen roughly every six months -- see -`release process`_, below for details. +`release process`_, below for details. + +.. _internal-release-deprecation-policy: These releases will contain new features, improvements to existing features, and such. A minor release may deprecate certain features from previous releases. If a feature in version ``A.B`` is deprecated, it will continue to work in version ``A.B+1``. In version ``A.B+2``, use of the feature will raise a ``PendingDeprecationWarning`` but will continue to work. Version ``A.B+3`` will -remove the feature entirely. +remove the feature entirely. So, for example, if we decided to remove a function that existed in Django 1.0: @@ -66,9 +68,9 @@ So, for example, if we decided to remove a function that existed in Django 1.0: * Django 1.2 will contain the backwards-compatible replica, but the warning will be promoted to a full-fledged ``DeprecationWarning``. This warning is *loud* by default, and will likely be quite annoying. - + * Django 1.3 will remove the feature outright. - + Micro releases -------------- @@ -92,21 +94,21 @@ varying levels: * The current development trunk will get new features and bug fixes requiring major refactoring. - + * All bug fixes applied to the trunk will also be applied to the last minor release, to be released as the next micro release. - + * Security fixes will be applied to the current trunk and the previous two minor releases. - + As a concrete example, consider a moment in time halfway between the release of Django 1.3 and 1.4. At this point in time: * Features will be added to development trunk, to be released as Django 1.4. - + * Bug fixes will be applied to a ``1.3.X`` branch, and released as 1.3.1, 1.3.2, etc. - + * Security releases will be applied to trunk, a ``1.3.X`` branch and a ``1.2.X`` branch. Security fixes will trigger the release of ``1.3.1``, ``1.2.1``, etc. @@ -117,7 +119,7 @@ Release process =============== Django uses a time-based release schedule, with minor (i.e. 1.1, 1.2, etc.) -releases every six months, or more, depending on features. +releases every six months, or more, depending on features. After each previous release (and after a suitable cooling-off period of a week or two), the core development team will examine the landscape and announce a @@ -174,12 +176,12 @@ and an rc complete with string freeze two weeks before the end of the schedule. Bug-fix releases ---------------- -After a minor release (i.e 1.1), the previous release will go into bug-fix mode. +After a minor release (i.e 1.1), the previous release will go into bug-fix mode. A branch will be created of the form ``branches/releases/1.0.X`` to track bug-fixes to the previous release. When possible, bugs fixed on trunk must *also* be fixed on the bug-fix branch; this means that commits need to cleanly -separate bug fixes from feature additions. The developer who commits a fix to +separate bug fixes from feature additions. The developer who commits a fix to trunk will be responsible for also applying the fix to the current bug-fix branch. Each bug-fix branch will have a maintainer who will work with the committers to keep them honest on backporting bug fixes. @@ -193,14 +195,13 @@ development will be happening in a bunch of places: * On trunk, development towards 1.2 proceeds with small additions, bugs fixes, etc. being checked in daily. - + * On the branch "branches/releases/1.1.X", bug fixes found in the 1.1 release are checked in as needed. At some point, this branch will be released as "1.1.1", "1.1.2", etc. * On the branch "branches/releases/1.0.X", security fixes are made if needed and released as "1.0.2", "1.0.3", etc. - + * On feature branches, development of major features is done. These branches will be merged into trunk before the end of phase two. - diff --git a/docs/intro/tutorial03.txt b/docs/intro/tutorial03.txt index f4ef5f76fe..238dc63f71 100644 --- a/docs/intro/tutorial03.txt +++ b/docs/intro/tutorial03.txt @@ -326,8 +326,8 @@ shortcut. Here's the ``detail()`` view, rewritten:: return render_to_response('polls/detail.html', {'poll': p}) The :func:`~django.shortcuts.get_object_or_404` function takes a Django model -module as its first argument and an arbitrary number of keyword arguments, which -it passes to the module's :meth:`~django.db.models.QuerySet.get` function. It +as its first argument and an arbitrary number of keyword arguments, which it +passes to the module's :meth:`~django.db.models.QuerySet.get` function. It raises :exc:`~django.http.Http404` if the object doesn't exist. .. admonition:: Philosophy @@ -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 index 254a8ad557..df4ab8f1ec 100644 Binary files a/docs/ref/contrib/admin/_images/article_actions.png and b/docs/ref/contrib/admin/_images/article_actions.png differ diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt index 64d9c52492..584672e4f0 100644 --- a/docs/ref/contrib/admin/index.txt +++ b/docs/ref/contrib/admin/index.txt @@ -704,6 +704,8 @@ objects. Templates can override or extend base admin templates as described in If you don't specify this attribute, a default template shipped with Django that provides the standard appearance is used. +.. _model-admin-methods: + ``ModelAdmin`` methods ---------------------- @@ -760,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): @@ -779,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) @@ -792,7 +808,7 @@ return a subset of objects for this foreign key field based on the user:: class MyModelAdmin(admin.ModelAdmin): def formfield_for_foreignkey(self, db_field, request, **kwargs): if db_field.name == "car": - kwargs["queryset"] = Car.object.filter(owner=request.user) + kwargs["queryset"] = Car.objects.filter(owner=request.user) return db_field.formfield(**kwargs) return super(MyModelAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs) @@ -847,7 +863,7 @@ provided some extra mapping data that would not otherwise be available:: 'osm_data': self.get_osm_info(), } return super(MyModelAdmin, self).change_view(request, object_id, - extra_context=my_context)) + extra_context=my_context) ``ModelAdmin`` media definitions -------------------------------- @@ -1226,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 @@ -1240,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 `. If no instance name is +provided, a default instance name of ``admin`` will be used. + ``AdminSite`` attributes ------------------------ @@ -1337,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: @@ -1354,37 +1378,31 @@ accessible using Django's :ref:`URL reversing system `. 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 @@ -1392,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 +`. diff --git a/docs/ref/contrib/contenttypes.txt b/docs/ref/contrib/contenttypes.txt index 94900b3892..8a926afc97 100644 --- a/docs/ref/contrib/contenttypes.txt +++ b/docs/ref/contrib/contenttypes.txt @@ -177,9 +177,9 @@ The ``ContentTypeManager`` .. method:: models.ContentTypeManager.clear_cache() Clears an internal cache used by - :class:`~django.contrib.contenttypes.models.ContentType>` to keep track + :class:`~django.contrib.contenttypes.models.ContentType` to keep track of which models for which it has created - :class:`django.contrib.contenttypes.models.ContentType>` instances. You + :class:`django.contrib.contenttypes.models.ContentType` instances. You probably won't ever need to call this method yourself; Django will call it automatically when it's needed. diff --git a/docs/ref/databases.txt b/docs/ref/databases.txt index 9a35b6cb8f..007a7079b7 100644 --- a/docs/ref/databases.txt +++ b/docs/ref/databases.txt @@ -220,7 +220,7 @@ bytestrings (which shouldn't be too difficult) is the recommended solution. Should you decide to use ``utf8_bin`` collation for some of your tables with MySQLdb 1.2.1p2, you should still use ``utf8_collation_ci_swedish`` (the default) collation for the :class:`django.contrib.sessions.models.Session` -table (usually called ``django_session`` and the table +table (usually called ``django_session``) and the :class:`django.contrib.admin.models.LogEntry` table (usually called ``django_admin_log``). Those are the two standard tables that use :class:`~django.db.model.TextField` internally. 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`` -~~~~~~~~~~~~~~ - - * 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``. +``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`` + +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/middleware.txt b/docs/ref/middleware.txt index 5125f6e064..ff51df9e8f 100644 --- a/docs/ref/middleware.txt +++ b/docs/ref/middleware.txt @@ -122,17 +122,10 @@ Reverse proxy middleware .. class:: django.middleware.http.SetRemoteAddrFromForwardedFor -Sets ``request.META['REMOTE_ADDR']`` based on -``request.META['HTTP_X_FORWARDED_FOR']``, if the latter is set. This is useful -if you're sitting behind a reverse proxy that causes each request's -``REMOTE_ADDR`` to be set to ``127.0.0.1``. - -**Important note:** This does NOT validate ``HTTP_X_FORWARDED_FOR``. If you're -not behind a reverse proxy that sets ``HTTP_X_FORWARDED_FOR`` automatically, do -not use this middleware. Anybody can spoof the value of -``HTTP_X_FORWARDED_FOR``, and because this sets ``REMOTE_ADDR`` based on -``HTTP_X_FORWARDED_FOR``, that means anybody can "fake" their IP address. Only -use this when you can absolutely trust the value of ``HTTP_X_FORWARDED_FOR``. +.. versionchanged: 1.1 + +This middleware was removed in Django 1.1. See :ref:`the release notes +` for details. Locale middleware ----------------- diff --git a/docs/ref/models/instances.txt b/docs/ref/models/instances.txt index c6509ece3d..7a0606dafe 100644 --- a/docs/ref/models/instances.txt +++ b/docs/ref/models/instances.txt @@ -188,6 +188,46 @@ almost always do the right thing and trying to override that will lead to errors that are difficult to track down. This feature is for advanced use only. +Updating attributes based on existing fields +-------------------------------------------- + +Sometimes you'll need to perform a simple arithmetic task on a field, such +as incrementing or decrementing the current value. The obvious way to +achieve this is to do something like:: + + >>> product = Product.objects.get(name='Venezuelan Beaver Cheese') + >>> product.number_sold += 1 + >>> product.save() + +If the old ``number_sold`` value retrieved from the database was 10, then +the value of 11 will be written back to the database. + +This can be optimized slightly by expressing the update relative to the +original field value, rather than as an explicit assignment of a new value. +Django provides :ref:`F() expressions ` as a way of +performing this kind of relative update. Using ``F()`` expressions, the +previous example would be expressed as:: + + >>> from django.db.models import F + >>> product = Product.objects.get(name='Venezuelan Beaver Cheese') + >>> product.number_sold = F('number_sold') + 1 + >>> product.save() + +This approach doesn't use the initial value from the database. Instead, it +makes the database do the update based on whatever value is current at the +time that the save() is executed. + +Once the object has been saved, you must reload the object in order to access +the actual value that was applied to the updated field:: + + >>> product = Products.objects.get(pk=product.pk) + >>> print product.number_sold + 42 + +For more details, see the documentation on :ref:`F() expressions +` and their :ref:`use in update queries +`. + Deleting objects ================ @@ -196,7 +236,7 @@ Deleting objects Issues a SQL ``DELETE`` for the object. This only deletes the object in the database; the Python instance will still be around, and will still have data in its fields. - + For more details, including how to delete objects in bulk, see :ref:`topics-db-queries-delete`. 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`. + 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 ba45a6f1c4..169688dd17 100644 --- a/docs/ref/templates/builtins.txt +++ b/docs/ref/templates/builtins.txt @@ -101,6 +101,14 @@ You can use any number of values in a ``{% cycle %}`` tag, separated by spaces. Values enclosed in single (``'``) or double quotes (``"``) are treated as string literals, while values without quotes are treated as template variables. +Note that the variables included in the cycle will not be escaped. This is +because template tags do not escape their content. If you want to escape the +variables in the cycle, you must do so explicitly:: + + {% filter force_escape %} + {% cycle var1 var2 var3 %} + {% endfilter %} + For backwards compatibility, the ``{% cycle %}`` tag supports the much inferior old syntax from previous Django versions. You shouldn't use this in any new projects, but for the sake of the people who are still using it, here's what it @@ -160,8 +168,9 @@ Sample usage:: firstof ~~~~~~~ -Outputs the first variable passed that is not False. Outputs nothing if all the -passed variables are False. +Outputs the first variable passed that is not False, without escaping. + +Outputs nothing if all the passed variables are False. Sample usage:: @@ -170,11 +179,11 @@ Sample usage:: This is equivalent to:: {% if var1 %} - {{ var1 }} + {{ var1|safe }} {% else %}{% if var2 %} - {{ var2 }} + {{ var2|safe }} {% else %}{% if var3 %} - {{ var3 }} + {{ var3|safe }} {% endif %}{% endif %}{% endif %} You can also use a literal string as a fallback value in case all @@ -182,6 +191,14 @@ passed variables are False:: {% firstof var1 var2 var3 "fallback value" %} +Note that the variables included in the firstof tag will not be escaped. This +is because template tags do not escape their content. If you want to escape +the variables in the firstof tag, you must do so explicitly:: + + {% filter force_escape %} + {% firstof var1 var2 var3 "fallback value" %} + {% endfilter %} + .. templatetag:: for for @@ -778,6 +795,16 @@ missing. In practice you'll use this to link to views that are optional:: Link to optional stuff {% 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 +`, including using any hints provided +by the context as to the current application. + .. templatetag:: widthratio widthratio diff --git a/docs/releases/1.1-rc-1.txt b/docs/releases/1.1-rc-1.txt new file mode 100644 index 0000000000..bda424800e --- /dev/null +++ b/docs/releases/1.1-rc-1.txt @@ -0,0 +1,111 @@ +.. _releases-1.1-rc-1: + +============================= +Django 1.1 RC 1 release notes +============================= + + +July 21, 2009 + +Welcome to the first Django 1.1 release candidate! + +This is the third -- and likely last -- in a series of +preview/development releases leading up to the eventual release of +Django 1.1, currently scheduled to take place approximately one week +after this release candidate. This release is targeted primarily at +developers who are interested in trying out new features and testing +the Django codebase to help identify and resolve any critical bugs +prior to the final 1.1 release. + +As such, this release is not yet intended for production use, and any +such use is discouraged. + + +What's new in Django 1.1 RC 1 +============================= + +The Django codebase has -- with one exception -- been in feature +freeze since the first 1.1 beta release, and so this release candidate +contains only one new feature (see below); work leading up to this +release candidate has instead been focused on bugfixing, particularly +on the new features introduced prior to the 1.1 beta. + +For an overview of those features, consult :ref:`the Django 1.1 beta +release notes `. + + +URL namespaces +-------------- + +The 1.1 beta release introduced the ability to use reverse URL +resolution with Django's admin application, which exposed a set of +:ref:`named URLs `. Unfortunately, achieving +consistent and correct reverse resolution for admin URLs proved +extremely difficult, and so one additional feature was added to Django +to resolve this issue: URL namespaces. + +In short, this feature allows the same group of URLs, from the same +application, to be included in a Django URLConf multiple times, with +varying (and potentially nested) named prefixes which will be used +when performing reverse resolution. For full details, see :ref:`the +documentation on defining URL namespaces +`. + +Due to the changes needed to support this feature, the URL pattern +names used when reversing admin URLs have changed since the 1.1 beta +release; if you were developing applications which took advantage of +this new feature, you will need to update your code to reflect the new +names (for most purposes, changing ``admin_`` to ``admin:`` in names +to be reversed will suffice). For a full list of URL pattern names +used by the admin and information on how namespaces are applied to +them, consult the documentation on :ref:`reversing admin URLs +`. + + +The Django 1.1 roadmap +====================== + +As of this release candidate, Django 1.1 is in both feature freeze and +"string freeze" -- all strings marked for translation in the Django +codebase will retain their current form in the final Django 1.1 +release. Only critical release-blocking bugs will receive attention +between now and the final 1.1 release. + +If no such bugs are discovered, Django 1.1 will be released +approximately one week after this release candidate, on or about July +28, 2009. + + +What you can do to help +======================= + +In order to provide a high-quality 1.1 release, we need your +help. Although this release candidate is, again, *not* intended for +production use, you can help the Django team by trying out this +release candidate in a safe testing environment and reporting any bugs +or issues you encounter. The Django ticket tracker is the central +place to search for open issues: + + * http://code.djangoproject.com/timeline + +Please open a new ticket only if no existing ticket corresponds to a +problem you're running into. + +Additionally, discussion of Django development, including progress +toward the 1.1 release, takes place daily on the django-developers +mailing list: + + * http://groups.google.com/group/django-developers + +... and in the ``#django-dev`` IRC channel on ``irc.freenode.net``. If you're +interested in helping out with Django's development, feel free to join the +discussions there. + +Django's online documentation also includes pointers on how to contribute to +Django: + + * :ref:`How to contribute to Django ` + +Contributions on any level -- developing code, writing documentation or simply +triaging tickets and helping to test proposed bugfixes -- are always welcome and +appreciated. diff --git a/docs/releases/1.1.txt b/docs/releases/1.1.txt new file mode 100644 index 0000000000..5af2e17449 --- /dev/null +++ b/docs/releases/1.1.txt @@ -0,0 +1,459 @@ +.. _releases-1.1: + +======================== +Django 1.1 release notes +======================== + + +July 29, 2009 + +Welcome to Django 1.1! + +Django 1.1 includes a number of nifty `new features`_, lots of bug +fixes, and an easy upgrade path from Django 1.0. + +.. _new features: `What's new in Django 1.1`_ + +Backwards-incompatible changes +============================== + +Django has a policy of :ref:`API stability `. This means +that, in general, code you develop against Django 1.0 should continue to work +against 1.1 unchanged. However, we do sometimes make backwards-incompatible +changes if they're necessary to resolve bugs, and there are a handful of such +(minor) changes between Django 1.0 and Django 1.1. + +Before upgrading to Django 1.1 you should double-check that the following +changes don't impact you, and upgrade your code if they do. + +Changes to constraint names +--------------------------- + +Django 1.1 modifies the method used to generate database constraint names so +that names are consistent regardless of machine word size. This change is +backwards incompatible for some users. + +If you are using a 32-bit platform, you're off the hook; you'll observe no +differences as a result of this change. + +However, **users on 64-bit platforms may experience some problems** using the +:djadmin:`reset` management command. Prior to this change, 64-bit platforms +would generate a 64-bit, 16 character digest in the constraint name; for +example:: + + ALTER TABLE myapp_sometable ADD CONSTRAINT object_id_refs_id_5e8f10c132091d1e FOREIGN KEY ... + +Following this change, all platforms, regardless of word size, will generate a +32-bit, 8 character digest in the constraint name; for example:: + + ALTER TABLE myapp_sometable ADD CONSTRAINT object_id_refs_id_32091d1e FOREIGN KEY ... + +As a result of this change, you will not be able to use the :djadmin:`reset` +management command on any table made by a 64-bit machine. This is because the +the new generated name will not match the historically generated name; as a +result, the SQL constructed by the reset command will be invalid. + +If you need to reset an application that was created with 64-bit constraints, +you will need to manually drop the old constraint prior to invoking +:djadmin:`reset`. + +Test cases are now run in a transaction +--------------------------------------- + +Django 1.1 runs tests inside a transaction, allowing better test performance +(see `test performance improvements`_ for details). + +This change is slightly backwards incompatible if existing tests need to test +transactional behavior, if they rely on invalid assumptions about the test +environment, or if they require a specific test case ordering. + +For these cases, :class:`~django.test.TransactionTestCase` can be used instead. +This is a just a quick fix to get around test case errors revealed by the new +rollback approach; in the long-term tests should be rewritten to correct the +test case. + +.. _removed-setremoteaddrfromforwardedfor-middleware: + +Removed ``SetRemoteAddrFromForwardedFor`` middleware +---------------------------------------------------- + +For convenience, Django 1.0 included an optional middleware class -- +``django.middleware.http.SetRemoteAddrFromForwardedFor`` -- which updated the +value of ``REMOTE_ADDR`` based on the HTTP ``X-Forwarded-For`` header commonly +set by some proxy configurations. + +It has been demonstrated that this mechanism cannot be made reliable enough for +general-purpose use, and that (despite documentation to the contrary) its +inclusion in Django may lead application developers to assume that the value of +``REMOTE_ADDR`` is "safe" or in some way reliable as a source of authentication. + +While not directly a security issue, we've decided to remove this middleware +with the Django 1.1 release. It has been replaced with a class that does nothing +other than raise a ``DeprecationWarning``. + +If you've been relying on this middleware, the easiest upgrade path is: + + * Examine `the code as it existed before it was removed`__. + + * Verify that it works correctly with your upstream proxy, modifying + it to support your particular proxy (if necessary). + + * Introduce your modified version of ``SetRemoteAddrFromForwardedFor`` as a + piece of middleware in your own project. + +__ http://code.djangoproject.com/browser/django/trunk/django/middleware/http.py?rev=11000#L33 + +Names of uploaded files are available later +------------------------------------------- + +.. currentmodule:: django.db.models + +In Django 1.0, files uploaded and stored in a model's :class:`FileField` were +saved to disk before the model was saved to the database. This meant that the +actual file name assigned to the file was available before saving. For example, +it was available in a model's pre-save signal handler. + +In Django 1.1 the file is saved as part of saving the model in the database, so +the actual file name used on disk cannot be relied on until *after* the model +has been saved saved. + +Changes to how model formsets are saved +--------------------------------------- + +.. currentmodule:: django.forms.models + +In Django 1.1, :class:`BaseModelFormSet` now calls :meth:`ModelForm.save()`. + +This is backwards-incompatible if you were modifying ``self.initial`` in a model +formset's ``__init__``, or if you relied on the internal ``_total_form_count`` +or ``_initial_form_count`` attributes of BaseFormSet. Those attributes are now +public methods. + +Fixed the ``join`` filter's escaping behavior +--------------------------------------------- + +The :ttag:`join` filter no longer escapes the literal value that is +passed in for the connector. + +This is backwards incompatible for the special situation of the literal string +containing one of the five special HTML characters. Thus, if you were writing +``{{ foo|join:"&" }}``, you now have to write ``{{ foo|join:"&" }}``. + +The previous behavior was a bug and contrary to what was documented +and expected. + +Permanent redirects and the ``redirect_to()`` generic view +---------------------------------------------------------- + +Django 1.1 adds a ``permanent`` argument to the +:func:`django.views.generic.simple.redirect_to()` view. This is technically +backwards-incompatible if you were using the ``redirect_to`` view with a +format-string key called 'permanent', which is highly unlikely. + +Features deprecated in 1.1 +========================== + +One feature has been marked as deprecated in Django 1.1: + + * You should no longer use ``AdminSite.root()`` to register that admin + views. That is, if your URLconf contains the line:: + + (r'^admin/(.*)', admin.site.root), + + You should change it to read:: + + (r'^admin/', include(admin.site.urls)), + +You should begin to remove use of this features from your code immediately. + +``AdminSite.root`` will will raise a ``PendingDeprecationWarning`` if used in +Django 1.1. This warning is hidden by default. In Django 1.2, this warning will +be upgraded to a ``DeprecationWarning``, which will be displayed loudly. Django +1.3 will remove ``AdminSite.root()`` entirely. + +For more details on our deprecation policies and strategy, see +:ref:`internals-release-process`. + +What's new in Django 1.1 +======================== + +Quite a bit: since Django 1.0, we've made 1,290 code commits, fixed 1,206 bugs, +and added roughly 10,000 lines of documentation. + +The major new features in Django 1.1 are: + +ORM improvements +---------------- + +.. currentmodule:: django.db.models + +Two major enhancements have been added to Django's object-relational mapper +(ORM): aggregate support, and query expressions. + +Aggregate support +~~~~~~~~~~~~~~~~~ + +It's now possible to run SQL aggregate queries (i.e. ``COUNT()``, ``MAX()``, +``MIN()``, etc.) from within Django's ORM. You can choose to either return the +results of the aggregate directly, or else annotate the objects in a +:class:`QuerySet` with the results of the aggregate query. + +This feature is available as new :meth:`QuerySet.aggregate()`` and +:meth:`QuerySet.annotate()`` methods, and is covered in detail in :ref:`the ORM +aggregation documentation `. + +Query expressions +~~~~~~~~~~~~~~~~~ + +Queries can now refer to a another field on the query and can traverse +relationships to refer to fields on related models. This is implemented in the +new :class:`F` object; for full details, including examples, consult the +:ref:`documentation for F expressions `. + +Model improvements +------------------ + +A number of features have been added to Django's model layer: + +"Unmanaged" models +~~~~~~~~~~~~~~~~~~ + +You can now control whether or not Django manages the life-cycle of the database +tables for a model using the :attr:`~Options.managed` model option. This +defaults to ``True``, meaning that Django will create the appropriate database +tables in :djadmin:`syncdb` and remove them as part of the :djadmin:`reset` +command. That is, Django *manages* the database table's lifecycle. + +If you set this to ``False``, however, no database table creating or deletion +will be automatically performed for this model. This is useful if the model +represents an existing table or a database view that has been created by some +other means. + +For more details, see the documentation for the :attr:`~Options.managed` +option. + +Proxy models +~~~~~~~~~~~~ + +You can now create :ref:`proxy models `: subclasses of existing +models that only add Python-level (rather than database-level) behavior and +aren't represented by a new table. That is, the new model is a *proxy* for some +underlying model, which stores all the real data. + +All the details can be found in the :ref:`proxy models documentation +`. This feature is similar on the surface to unmanaged models, +so the documentation has an explanation of :ref:`how proxy models differ from +unmanaged models `. + +Deferred fields +~~~~~~~~~~~~~~~ + +In some complex situations, your models might contain fields which could +contain a lot of data (for example, large text fields), or require expensive +processing to convert them to Python objects. If you know you don't need those +particular fields, you can now tell Django not to retrieve them from the +database. + +You'll do this with the :ref:`new queryset methods ` +``defer()`` and ``only()``. + +Testing improvements +-------------------- + +A few notable improvements have been made to the :ref:`testing framework +`. + +Test performance improvements +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. currentmodule:: django.test + +Tests written using Django's :ref:`testing framework ` now run +dramatically faster (as much as 10 times faster in many cases). + +This was accomplished through the introduction of transaction-based tests: when +using :class:`django.test.TestCase`, your tests will now be run in a transaction +which is rolled back when finished, instead of by flushing and re-populating the +database. This results in an immense speedup for most types of unit tests. See +the documentation for :class:`TestCase` and :class:`TransactionTestCase` for a +full description, and some important notes on database support. + +Test client improvements +------------------------ + +.. currentmodule:: django.test.client + +A couple of small -- but highly useful -- improvements have been made to the +test client: + + * The test :class:`Client` now can automatically follow redirects with the + ``follow`` argument to :meth:`Client.get` and :meth:`Client.post`. This + makes testing views that issue redirects simpler. + + * It's now easier to get at the template context in the response returned + the test client: you'll simply access the context as + ``request.context[key]``. The old way, which treats ``request.context`` as + a list of contexts, one for each rendered template in the inheritance + chain, is still available if you need it. + +New admin features +------------------ + +Django 1.1 adds a couple of nifty new features to Django's admin interface: + +Editable fields on the change list +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can now make fields editable on the admin list views via the new +:ref:`list_editable ` admin option. These fields will show +up as form widgets on the list pages, and can be edited and saved in bulk. + +Admin "actions" +~~~~~~~~~~~~~~~ + +You can now define :ref:`admin actions ` that can +perform some action to a group of models in bulk. Users will be able to select +objects on the change list page and then apply these bulk actions to all +selected objects. + +Django ships with one pre-defined admin action to delete a group of objects in +one fell swoop. + +Conditional view processing +--------------------------- + +Django now has much better support for :ref:`conditional view processing +` using the standard ``ETag`` and +``Last-Modified`` HTTP headers. This means you can now easily short-circuit +view processing by testing less-expensive conditions. For many views this can +lead to a serious improvement in speed and reduction in bandwidth. + +URL namespaces +-------------- + +Django 1.1 improves :ref:`named URL patterns ` with the +introduction of URL "namespaces." + +In short, this feature allows the same group of URLs, from the same application, +to be included in a Django URLConf multiple times, with varying (and potentially +nested) named prefixes which will be used when performing reverse resolution. In +other words, reusable applications like Django's admin interface may be +registered multiple times without URL conflicts. + +For full details, see :ref:`the documentation on defining URL namespaces +`. + +GeoDjango +--------- + +In Django 1.1, GeoDjango_ (i.e. ``django.contrib.gis``) has several new +features: + + * Support for SpatiaLite_ -- a spatial database for SQLite -- as a spatial + backend. + + * Geographic aggregates (``Collect``, ``Extent``, ``MakeLine``, ``Union``) + and ``F`` expressions. + + * New ``GeoQuerySet`` methods: ``collect``, ``geojson``, and + ``snap_to_grid``. + + * A new list interface methods for ``GEOSGeometry`` objects. + +For more details, see the `GeoDjango documentation`_. + +.. _geodjango: http://geodjango.org/ +.. _spatialite: http://www.gaia-gis.it/spatialite/ +.. _geodjango documentation: http://geodjango.org/docs/ + +Other improvements +------------------ + +Other new features and changes introduced since Django 1.0 include: + +* The :ref:`CSRF protection middleware ` has been split into + two classes -- ``CsrfViewMiddleware`` checks incoming requests, and + ``CsrfResponseMiddleware`` processes outgoing responses. The combined + ``CsrfMiddleware`` class (which does both) remains for + backwards-compatibility, but using the split classes is now recommended in + order to allow fine-grained control of when and where the CSRF processing + takes place. + +* :func:`~django.core.urlresolvers.reverse` and code which uses it (e.g., the + ``{% url %}`` template tag) now works with URLs in Django's administrative + site, provided that the admin URLs are set up via ``include(admin.site.urls)`` + (sending admin requests to the ``admin.site.root`` view still works, but URLs + in the admin will not be "reversible" when configured this way). + +* The ``include()`` function in Django URLconf modules can now accept sequences + of URL patterns (generated by ``patterns()``) in addition to module names. + +* Instances of Django forms (see `the forms overview `_ now + have two additional methods, ``hidden_fields()`` and ``visible_fields()``, + which return the list of hidden -- i.e., ```` -- and + visible fields on the form, respectively. + +* The ``redirect_to`` generic view (see `the generic views documentation + `_) now accepts an additional keyword argument + ``permanent``. If ``permanent`` is ``True``, the view will emit an HTTP + permanent redirect (status code 301). If ``False``, the view will emit an HTTP + temporary redirect (status code 302). + +* A new database lookup type -- ``week_day`` -- has been added for ``DateField`` + and ``DateTimeField``. This type of lookup accepts a number between 1 (Sunday) + and 7 (Saturday), and returns objects where the field value matches that day + of the week. See `the full list of lookup types `_ for details. + +* The ``{% for %}`` tag in Django's template language now accepts an optional + ``{% empty %}`` clause, to be displayed when ``{% for %}`` is asked to loop + over an empty sequence. See :ref:`the list of built-in template tags + ` for examples of this. + +* The :djadmin:`dumpdata` management command now accepts individual + model names as arguments, allowing you to export the data just from + particular models. + +* There's a new :tfilter:`safeseq` template filter which works just like + :tfilter:`safe` for lists, marking each item in the list as safe. + +* :ref:`Cache backends ` now support ``incr()`` and + ``decr()`` commands to increment and decrement the value of a cache key. + On cache backends that support atomic increment/decrement -- most + notably, the memcached backend -- these operations will be atomic, and + quite fast. + +* Django now can :ref:`easily delegate authentication to the web server + ` via a new authentication backend that supports + the standard ``REMOTE_USER`` environment variable used for this purpose. + +* There's a new :func:`django.shortcuts.redirect` function that makes it + easier to issue redirects given an object, a view name, or a URL. + +* The ``postgresql_psycopg2`` backend now supports :ref:`native PostgreSQL + autocommit `. This is an advanced, PostgreSQL-specific + feature, that can make certain read-heavy applications a good deal + faster. + +What's next? +============ + +We'll take a short break, and then work on Django 1.2 will begin -- no rest for +the weary! If you'd like to help, discussion of Django development, including +progress toward the 1.2 release, takes place daily on the django-developers +mailing list: + + * http://groups.google.com/group/django-developers + +... and in the ``#django-dev`` IRC channel on ``irc.freenode.net``. Feel free to +join the discussions! + +Django's online documentation also includes pointers on how to contribute to +Django: + + * :ref:`How to contribute to Django ` + +Contributions on any level -- developing code, writing documentation or simply +triaging tickets and helping to test proposed bugfixes -- are always welcome and +appreciated. + +And that's the way it is. diff --git a/docs/releases/index.txt b/docs/releases/index.txt index bdbd22910c..e5c4fde537 100644 --- a/docs/releases/index.txt +++ b/docs/releases/index.txt @@ -3,7 +3,7 @@ Release notes ============= -Releases notes for the official Django releases. Each release note will tell you +Release notes for the official Django releases. Each release note will tell you what's new in each version, and will also describe any backwards-incompatible changes made in that version. @@ -21,6 +21,8 @@ changes made in that version. 1.0.2 1.1-alpha-1 1.1-beta-1 + 1.1-rc-1 + 1.1 .. seealso:: 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() + +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\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 `, 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:: + + (, , ) + +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 `. + 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 `. + .. 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 +`_ 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:: {% trans "myvar" noop %} +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 ` 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:: - + -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() -- cgit v1.3