diff options
| author | Andrew Godwin <andrew@aeracode.org> | 2012-10-26 08:41:13 +0100 |
|---|---|---|
| committer | Andrew Godwin <andrew@aeracode.org> | 2012-10-26 08:41:13 +0100 |
| commit | 6a632e04578776e877adc5e2dc53f008c890a0d4 (patch) | |
| tree | aa47200fb63adf44609066a45601bd3b8768ec1c /docs | |
| parent | a589fdff81ab36c57ff0a1003e60ee0dd55f3a88 (diff) | |
| parent | fabe9c9e5f0a437b5389faaf469ce53091abd3cf (diff) | |
Merge branch 'master' into schema-alteration
Conflicts:
django/db/backends/__init__.py
django/db/models/fields/related.py
django/db/models/options.py
Diffstat (limited to 'docs')
112 files changed, 4735 insertions, 4058 deletions
diff --git a/docs/faq/admin.txt b/docs/faq/admin.txt index ea6aa2e74e..872ad254c9 100644 --- a/docs/faq/admin.txt +++ b/docs/faq/admin.txt @@ -68,6 +68,18 @@ For example, if your ``list_filter`` includes ``sites``, and there's only one site in your database, it won't display a "Site" filter. In that case, filtering by site would be meaningless. +Some objects aren't appearing in the admin. +------------------------------------------- + +Inconsistent row counts may be caused by missing foreign key values or a +foreign key field incorrectly set to :attr:`null=False +<django.db.models.Field.null>`. If you have a record with a +:class:`~django.db.models.ForeignKey` pointing to a non-existent object and +that foreign key is included is +:attr:`~django.contrib.admin.ModelAdmin.list_display`, the record will not be +shown in the admin changelist because the Django model is declaring an +integrity constraint that is not implemented at the database level. + How can I customize the functionality of the admin interface? ------------------------------------------------------------- @@ -104,4 +116,3 @@ example, some browsers may not support rounded corners. These are considered acceptable variations in rendering. .. _YUI's A-grade: http://yuilibrary.com/yui/docs/tutorials/gbs/ - diff --git a/docs/howto/apache-auth.txt b/docs/howto/apache-auth.txt deleted file mode 100644 index 719fbc1769..0000000000 --- a/docs/howto/apache-auth.txt +++ /dev/null @@ -1,45 +0,0 @@ -========================================================= -Authenticating against Django's user database from Apache -========================================================= - -Since keeping multiple authentication databases in sync is a common problem when -dealing with Apache, you can configuring Apache to authenticate against Django's -:doc:`authentication system </topics/auth>` directly. This requires Apache -version >= 2.2 and mod_wsgi >= 2.0. For example, you could: - -* Serve static/media files directly from Apache only to authenticated users. - -* Authenticate access to a Subversion_ repository against Django users with - a certain permission. - -* Allow certain users to connect to a WebDAV share created with mod_dav_. - -.. _Subversion: http://subversion.tigris.org/ -.. _mod_dav: http://httpd.apache.org/docs/2.2/mod/mod_dav.html - -Configuring Apache -================== - -To check against Django's authorization database from a Apache configuration -file, you'll need to set 'wsgi' as the value of ``AuthBasicProvider`` or -``AuthDigestProvider`` directive and then use the ``WSGIAuthUserScript`` -directive to set the path to your authentification script: - -.. code-block:: apache - - <Location /example/> - AuthType Basic - AuthName "example.com" - AuthBasicProvider wsgi - WSGIAuthUserScript /usr/local/wsgi/scripts/auth.wsgi - Require valid-user - </Location> - -Your auth.wsgi script will have to implement either a -``check_password(environ, user, password)`` function (for ``AuthBasicProvider``) -or a ``get_realm_hash(environ, user, realm)`` function (for ``AuthDigestProvider``). - -See the `mod_wsgi documentation`_ for more details about the implementation -of such a solution. - -.. _mod_wsgi documentation: http://code.google.com/p/modwsgi/wiki/AccessControlMechanisms#Apache_Authentication_Provider diff --git a/docs/howto/custom-model-fields.txt b/docs/howto/custom-model-fields.txt index 9ff06479c6..1e9d5d8701 100644 --- a/docs/howto/custom-model-fields.txt +++ b/docs/howto/custom-model-fields.txt @@ -448,6 +448,13 @@ called when it is created, you should be using `The SubfieldBase metaclass`_ mentioned earlier. Otherwise :meth:`.to_python` won't be called automatically. +.. warning:: + + If your custom field allows ``null=True``, any field method that takes + ``value`` as an argument, like :meth:`~Field.to_python` and + :meth:`~Field.get_prep_value`, should handle the case when ``value`` is + ``None``. + Converting Python objects to query values ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/howto/custom-template-tags.txt b/docs/howto/custom-template-tags.txt index 5b27af82d6..70b6288bee 100644 --- a/docs/howto/custom-template-tags.txt +++ b/docs/howto/custom-template-tags.txt @@ -760,8 +760,6 @@ A few things to note about the ``simple_tag`` helper function: * If the argument was a template variable, our function is passed the current value of the variable, not the variable itself. -.. versionadded:: 1.3 - If your template tag needs to access the current context, you can use the ``takes_context`` argument when registering your tag: diff --git a/docs/howto/deployment/wsgi/apache-auth.txt b/docs/howto/deployment/wsgi/apache-auth.txt new file mode 100644 index 0000000000..5f700f1cb3 --- /dev/null +++ b/docs/howto/deployment/wsgi/apache-auth.txt @@ -0,0 +1,130 @@ +========================================================= +Authenticating against Django's user database from Apache +========================================================= + +Since keeping multiple authentication databases in sync is a common problem when +dealing with Apache, you can configure Apache to authenticate against Django's +:doc:`authentication system </topics/auth>` directly. This requires Apache +version >= 2.2 and mod_wsgi >= 2.0. For example, you could: + +* Serve static/media files directly from Apache only to authenticated users. + +* Authenticate access to a Subversion_ repository against Django users with + a certain permission. + +* Allow certain users to connect to a WebDAV share created with mod_dav_. + +.. note:: + If you have installed a :ref:`custom User model <auth-custom-user>` and + want to use this default auth handler, it must support an `is_active` + attribute. If you want to use group based authorization, your custom user + must have a relation named 'groups', referring to a related object that has + a 'name' field. You can also specify your own custom mod_wsgi + auth handler if your custom cannot conform to these requirements. + +.. _Subversion: http://subversion.tigris.org/ +.. _mod_dav: http://httpd.apache.org/docs/2.2/mod/mod_dav.html + +Authentication with mod_wsgi +============================ + +Make sure that mod_wsgi is installed and activated and that you have +followed the steps to setup +:doc:`Apache with mod_wsgi </howto/deployment/wsgi/modwsgi>` + +Next, edit your Apache configuration to add a location that you want +only authenticated users to be able to view: + +.. code-block:: apache + + WSGIScriptAlias / /path/to/mysite.com/mysite/wsgi.py + + WSGIProcessGroup %{GLOBAL} + WSGIApplicationGroup django + + <Location "/secret"> + AuthType Basic + AuthName "Top Secret" + Require valid-user + AuthBasicProvider wsgi + WSGIAuthUserScript /path/to/mysite.com/mysite/wsgi.py + </Location> + +The ``WSGIAuthUserScript`` directive tells mod_wsgi to execute the +``check_password`` function in specified wsgi script, passing the user name and +password that it receives from the prompt. In this example, the +``WSGIAuthUserScript`` is the same as the ``WSGIScriptAlias`` that defines your +application :doc:`that is created by django-admin.py startproject +</howto/deployment/wsgi/index>`. + +.. admonition:: Using Apache 2.2 with authentication + + Make sure that ``mod_auth_basic`` and ``mod_authz_user`` are loaded. + + These might be compiled statically into Apache, or you might need to use + LoadModule to load them dynamically in your ``httpd.conf``: + + .. code-block:: apache + + LoadModule auth_basic_module modules/mod_auth_basic.so + LoadModule authz_user_module modules/mod_authz_user.so + +Finally, edit your WSGI script ``mysite.wsgi`` to tie Apache's +authentication to your site's authentication mechanisms by importing the +check_user function: + +.. code-block:: python + + import os + import sys + + os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings' + + from django.contrib.auth.handlers.modwsgi import check_password + + from django.core.handlers.wsgi import WSGIHandler + application = WSGIHandler() + + +Requests beginning with ``/secret/`` will now require a user to authenticate. + +The mod_wsgi `access control mechanisms documentation`_ provides additional +details and information about alternative methods of authentication. + +.. _access control mechanisms documentation: http://code.google.com/p/modwsgi/wiki/AccessControlMechanisms + +Authorization with mod_wsgi and Django groups +--------------------------------------------- + +mod_wsgi also provides functionality to restrict a particular location to +members of a group. + +In this case, the Apache configuration should look like this: + +.. code-block:: apache + + WSGIScriptAlias / /path/to/mysite.com/mysite/wsgi.py + + WSGIProcessGroup %{GLOBAL} + WSGIApplicationGroup django + + <Location "/secret"> + AuthType Basic + AuthName "Top Secret" + AuthBasicProvider wsgi + WSGIAuthUserScript /path/to/mysite.com/mysite/wsgi.py + WSGIAuthGroupScript /path/to/mysite.com/mysite/wsgi.py + Require group secret-agents + Require valid-user + </Location> + +To support the ``WSGIAuthGroupScript`` directive, the same WSGI script +``mysite.wsgi`` must also import the ``groups_for_user`` function which +returns a list groups the given user belongs to. + +.. code-block:: python + + from django.contrib.auth.handlers.modwsgi import check_password, groups_for_user + +Requests for ``/secret/`` will now also require user to be a member of the +"secret-agents" group. diff --git a/docs/howto/deployment/wsgi/index.txt b/docs/howto/deployment/wsgi/index.txt index ecb302cee3..769d406b1b 100644 --- a/docs/howto/deployment/wsgi/index.txt +++ b/docs/howto/deployment/wsgi/index.txt @@ -16,6 +16,7 @@ documentation for the following WSGI servers: :maxdepth: 1 modwsgi + apache-auth gunicorn uwsgi diff --git a/docs/howto/deployment/wsgi/modwsgi.txt b/docs/howto/deployment/wsgi/modwsgi.txt index 8398f12eb7..7f68485dff 100644 --- a/docs/howto/deployment/wsgi/modwsgi.txt +++ b/docs/howto/deployment/wsgi/modwsgi.txt @@ -25,7 +25,9 @@ Basic configuration =================== Once you've got mod_wsgi installed and activated, edit your Apache server's -``httpd.conf`` file and add:: +``httpd.conf`` file and add + +.. code-block:: apache WSGIScriptAlias / /path/to/mysite.com/mysite/wsgi.py WSGIPythonPath /path/to/mysite.com @@ -56,21 +58,32 @@ for you; otherwise, you'll need to create it. See the :doc:`WSGI overview documentation</howto/deployment/wsgi/index>` for the default contents you should put in this file, and what else you can add to it. +.. warning:: + + If multiple Django sites are run in a single mod_wsgi process, all of them + will use the settings of whichever one happens to run first. This can be + solved with a minor edit to ``wsgi.py`` (see comment in the file for + details), or by :ref:`using mod_wsgi daemon mode<daemon-mode>` and ensuring + that each site runs in its own daemon process. + + Using a virtualenv ================== If you install your project's Python dependencies inside a `virtualenv`_, you'll need to add the path to this virtualenv's ``site-packages`` directory to -your Python path as well. To do this, you can add another line to your -Apache configuration:: +your Python path as well. To do this, add an additional path to your +`WSGIPythonPath` directive, with multiple paths separated by a colon:: - WSGIPythonPath /path/to/your/venv/lib/python2.X/site-packages + WSGIPythonPath /path/to/mysite.com:/path/to/your/venv/lib/python2.X/site-packages Make sure you give the correct path to your virtualenv, and replace ``python2.X`` with the correct Python version (e.g. ``python2.7``). .. _virtualenv: http://www.virtualenv.org +.. _daemon-mode: + Using mod_wsgi daemon mode ========================== @@ -177,6 +190,13 @@ other approaches: 3. Copy the admin static files so that they live within your Apache document root. +Authenticating against Django's user database from Apache +========================================================= + +Django provides a handler to allow Apache to authenticate users directly +against Django's authentication backends. See the :doc:`mod_wsgi authentication +documentation </howto/deployment/wsgi/apache-auth>`. + If you get a UnicodeEncodeError =============================== diff --git a/docs/howto/error-reporting.txt b/docs/howto/error-reporting.txt index 64af2a0980..78e797b607 100644 --- a/docs/howto/error-reporting.txt +++ b/docs/howto/error-reporting.txt @@ -44,8 +44,6 @@ setting. .. seealso:: - .. versionadded:: 1.3 - Server error emails are sent using the logging framework, so you can customize this behavior by :doc:`customizing your logging configuration </topics/logging>`. @@ -99,8 +97,6 @@ The best way to disable this behavior is to set .. seealso:: - .. versionadded:: 1.3 - 404 errors are logged using the logging framework. By default, these log records are ignored, but you can use them for error reporting by writing a handler and :doc:`configuring logging </topics/logging>` appropriately. diff --git a/docs/howto/index.txt b/docs/howto/index.txt index 737ee71da4..d39222be26 100644 --- a/docs/howto/index.txt +++ b/docs/howto/index.txt @@ -9,7 +9,6 @@ you quickly accomplish common tasks. .. toctree:: :maxdepth: 1 - apache-auth auth-remote-user custom-management-commands custom-model-fields diff --git a/docs/howto/jython.txt b/docs/howto/jython.txt index 762250212a..461a5d3804 100644 --- a/docs/howto/jython.txt +++ b/docs/howto/jython.txt @@ -6,9 +6,10 @@ Running Django on Jython .. admonition:: Python 2.6 support - Django 1.5 has dropped support for Python 2.5. Until Jython provides a new - version that supports 2.6, Django 1.5 is no more compatible with Jython. - Please use Django 1.4 if you want to use Django over Jython. + Django 1.5 has dropped support for Python 2.5. Therefore, you have to use + a Jython 2.7 alpha release if you want to use Django 1.5 with Jython. + Please use Django 1.4 if you want to keep using Django on a stable Jython + version. Jython_ is an implementation of Python that runs on the Java platform (JVM). Django runs cleanly on Jython version 2.5 or later, which means you can deploy diff --git a/docs/howto/outputting-csv.txt b/docs/howto/outputting-csv.txt index 1a606069b8..bcc6f3827b 100644 --- a/docs/howto/outputting-csv.txt +++ b/docs/howto/outputting-csv.txt @@ -21,7 +21,7 @@ Here's an example:: def some_view(request): # Create the HttpResponse object with the appropriate CSV header. response = HttpResponse(mimetype='text/csv') - response['Content-Disposition'] = 'attachment; filename=somefilename.csv' + response['Content-Disposition'] = 'attachment; filename="somefilename.csv"' writer = csv.writer(response) writer.writerow(['First row', 'Foo', 'Bar', 'Baz']) @@ -93,7 +93,7 @@ Here's an example, which generates the same CSV file as above:: def some_view(request): # Create the HttpResponse object with the appropriate CSV header. response = HttpResponse(mimetype='text/csv') - response['Content-Disposition'] = 'attachment; filename=somefilename.csv' + response['Content-Disposition'] = 'attachment; filename="somefilename.csv"' # The data is hard-coded here, but you could load it from a database or # some other source. diff --git a/docs/howto/outputting-pdf.txt b/docs/howto/outputting-pdf.txt index e7e4bdcfa5..9d87b97710 100644 --- a/docs/howto/outputting-pdf.txt +++ b/docs/howto/outputting-pdf.txt @@ -52,7 +52,7 @@ Here's a "Hello World" example:: def some_view(request): # Create the HttpResponse object with the appropriate PDF headers. response = HttpResponse(mimetype='application/pdf') - response['Content-Disposition'] = 'attachment; filename=somefilename.pdf' + response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"' # Create the PDF object, using the response object as its "file." p = canvas.Canvas(response) @@ -87,7 +87,7 @@ mention: the PDF using whatever program/plugin they've been configured to use for PDFs. Here's what that code would look like:: - response['Content-Disposition'] = 'filename=somefilename.pdf' + response['Content-Disposition'] = 'filename="somefilename.pdf"' * Hooking into the ReportLab API is easy: Just pass ``response`` as the first argument to ``canvas.Canvas``. The ``Canvas`` class expects a @@ -121,7 +121,7 @@ Here's the above "Hello World" example rewritten to use :mod:`io`:: def some_view(request): # Create the HttpResponse object with the appropriate PDF headers. response = HttpResponse(mimetype='application/pdf') - response['Content-Disposition'] = 'attachment; filename=somefilename.pdf' + response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"' buffer = BytesIO() diff --git a/docs/howto/static-files.txt b/docs/howto/static-files.txt index f8c591891d..964b5fab61 100644 --- a/docs/howto/static-files.txt +++ b/docs/howto/static-files.txt @@ -2,8 +2,6 @@ Managing static files ===================== -.. versionadded:: 1.3 - Django developers mostly concern themselves with the dynamic parts of web applications -- the views and templates that render anew for each request. But web applications have other parts: the static files (images, CSS, diff --git a/docs/index.txt b/docs/index.txt index 8b29c95fa2..5055edf7e7 100644 --- a/docs/index.txt +++ b/docs/index.txt @@ -181,7 +181,6 @@ testing of Django applications: :doc:`Overview <howto/deployment/index>` | :doc:`WSGI servers <howto/deployment/wsgi/index>` | :doc:`FastCGI/SCGI/AJP <howto/deployment/fastcgi>` | - :doc:`Apache authentication <howto/apache-auth>` | :doc:`Handling static files <howto/static-files>` | :doc:`Tracking code errors by email <howto/error-reporting>` @@ -241,7 +240,7 @@ applications: * :doc:`Authentication <topics/auth>` * :doc:`Caching <topics/cache>` * :doc:`Logging <topics/logging>` -* :doc:`Sending e-mails <topics/email>` +* :doc:`Sending emails <topics/email>` * :doc:`Syndication feeds (RSS/Atom) <ref/contrib/syndication>` * :doc:`Comments <ref/contrib/comments/index>`, :doc:`comment moderation <ref/contrib/comments/moderation>` and :doc:`custom comments <ref/contrib/comments/custom>` * :doc:`Pagination <topics/pagination>` diff --git a/docs/internals/committers.txt b/docs/internals/committers.txt index ca56d36880..7900dd8cd0 100644 --- a/docs/internals/committers.txt +++ b/docs/internals/committers.txt @@ -407,6 +407,18 @@ Jeremy Dunck .. _vlogger: http://youtube.com/bryanveloso/ .. _shoutcaster: http://twitch.tv/vlogalonstar/ +`Preston Holmes`_ + Preston is a recovering neuroscientist who originally discovered Django as + part of a sweeping move to Python from a grab bag of half a dozen + languages. He was drawn to Django's balance of practical batteries included + philosophy, care and thought in code design, and strong open source + community. In addition to his current job in private progressive education, + Preston contributes some developer time to local non-profits. + + Preston lives with his family and animal menagerie in Santa Barbara, CA, USA. + +.. _Preston Holmes: http://www.ptone.com/ + Specialists ----------- diff --git a/docs/internals/contributing/committing-code.txt b/docs/internals/contributing/committing-code.txt index d36bc78fe1..67dda02f8b 100644 --- a/docs/internals/contributing/committing-code.txt +++ b/docs/internals/contributing/committing-code.txt @@ -187,7 +187,15 @@ Django's Git repository: For the curious, we're using a `Trac plugin`_ for this. - .. _Trac plugin: https://github.com/aaugustin/trac-github +.. note:: + + Note that the Trac integration doesn't know anything about pull requests. + So if you try to close a pull request with the phrase "closes #400" in your + commit message, GitHub will close the pull request, but the Trac plugin + will also close the same numbered ticket in Trac. + + +.. _Trac plugin: https://github.com/aaugustin/trac-github * If your commit references a ticket in the Django `ticket tracker`_ but does *not* close the ticket, include the phrase "Refs #xxxxx", where "xxxxx" diff --git a/docs/internals/contributing/localizing.txt b/docs/internals/contributing/localizing.txt index 263087b5fa..0cde77882c 100644 --- a/docs/internals/contributing/localizing.txt +++ b/docs/internals/contributing/localizing.txt @@ -55,7 +55,7 @@ The format files aren't managed by the use of Transifex. To change them, you must :doc:`create a patch<writing-code/submitting-patches>` against the Django source tree, as for any code change: -* Create a diff against the current Subversion trunk. +* Create a diff against the current Git master branch. * Open a ticket in Django's ticket system, set its ``Component`` field to ``Translations``, and attach the patch to it. diff --git a/docs/internals/contributing/triaging-tickets.txt b/docs/internals/contributing/triaging-tickets.txt index ab879e5caf..84f70fd731 100644 --- a/docs/internals/contributing/triaging-tickets.txt +++ b/docs/internals/contributing/triaging-tickets.txt @@ -171,15 +171,6 @@ concrete actionable issues. They are enhancement requests that we might consider adding someday to the framework if an excellent patch is submitted. These tickets are not a high priority. -Fixed on a branch -~~~~~~~~~~~~~~~~~ - -Used to indicate that a ticket is resolved as part of a major body of work -that will eventually be merged to trunk. Tickets in this stage generally -don't need further work. This may happen in the case of major -features/refactors in each release cycle, or as part of the annual Google -Summer of Code efforts. - Other triage attributes ----------------------- diff --git a/docs/internals/contributing/writing-code/coding-style.txt b/docs/internals/contributing/writing-code/coding-style.txt index 2fa0233e3d..a699e39bd8 100644 --- a/docs/internals/contributing/writing-code/coding-style.txt +++ b/docs/internals/contributing/writing-code/coding-style.txt @@ -140,9 +140,9 @@ Model style a tuple of tuples, with an all-uppercase name, either near the top of the model module or just above the model class. Example:: - GENDER_CHOICES = ( - ('M', 'Male'), - ('F', 'Female'), + DIRECTION_CHOICES = ( + ('U', 'Up'), + ('D', 'Down'), ) Use of ``django.conf.settings`` diff --git a/docs/internals/contributing/writing-code/unit-tests.txt b/docs/internals/contributing/writing-code/unit-tests.txt index 4de506a654..a828b06b36 100644 --- a/docs/internals/contributing/writing-code/unit-tests.txt +++ b/docs/internals/contributing/writing-code/unit-tests.txt @@ -163,6 +163,26 @@ associated tests will be skipped. .. _gettext: http://www.gnu.org/software/gettext/manual/gettext.html .. _selenium: http://pypi.python.org/pypi/selenium +Code coverage +~~~~~~~~~~~~~ + +Contributors are encouraged to run coverage on the test suite to identify areas +that need additional tests. The coverage tool installation and use is described +in :ref:`testing code coverage<topics-testing-code-coverage>`. + +To run coverage on the Django test suite using the standard test settings:: + + coverage run ./runtests.py --settings=test_sqlite + +After running coverage, generate the html report by running:: + + coverage html + +When running coverage for the Django tests, the included ``.coveragerc`` +settings file defines ``coverage_html`` as the output directory for the report +and also excludes several directories not relevant to the results +(test code or external code included in Django). + .. _contrib-apps: Contrib apps diff --git a/docs/internals/contributing/writing-documentation.txt b/docs/internals/contributing/writing-documentation.txt index c8d7039a68..469f8614b9 100644 --- a/docs/internals/contributing/writing-documentation.txt +++ b/docs/internals/contributing/writing-documentation.txt @@ -30,8 +30,9 @@ If you'd like to start contributing to our docs, get the development version of Django from the source code repository (see :ref:`installing-development-version`). The development version has the latest-and-greatest documentation, just as it has latest-and-greatest code. -Generally, we only revise documentation in the development version, as our -policy is to freeze documentation for existing releases (see +We also backport documentation fixes and improvements, at the discretion of the +committer, to the last release branch. That's because it's highly advantageous +to have the docs for the last release be up-to-date and correct (see :ref:`differences-between-doc-versions`). Getting started with Sphinx diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt index 4add751912..10bbfe1a91 100644 --- a/docs/internals/deprecation.txt +++ b/docs/internals/deprecation.txt @@ -23,7 +23,7 @@ these changes. * The :mod:`django.contrib.gis.db.backend` module will be removed in favor of the specific backends. -* ``SMTPConnection`` will be removed in favor of a generic E-mail backend API. +* ``SMTPConnection`` will be removed in favor of a generic Email backend API. * The many to many SQL generation functions on the database backends will be removed. @@ -134,16 +134,16 @@ these changes. * The function-based generic view modules will be removed in favor of their class-based equivalents, outlined :doc:`here - </topics/class-based-views/index>`: + </topics/class-based-views/index>`. * The :class:`~django.core.servers.basehttp.AdminMediaHandler` will be removed. In its place use :class:`~django.contrib.staticfiles.handlers.StaticFilesHandler`. * The :ttag:`url` and :ttag:`ssi` template tags will be - modified so that the first argument to each tag is a - template variable, not an implied string. Until then, the new-style - behavior is provided in the ``future`` template tag library. + modified so that the first argument to each tag is a template variable, not + an implied string. In 1.4, this behavior is provided by a version of the tag + in the ``future`` template tag library. * The :djadmin:`reset` and :djadmin:`sqlreset` management commands will be removed. @@ -286,6 +286,13 @@ these changes. * The ``mimetype`` argument to :class:`~django.http.HttpResponse` ``__init__`` will be removed (``content_type`` should be used instead). +* When :class:`~django.http.HttpResponse` is instantiated with an iterator, + or when :attr:`~django.http.HttpResponse.content` is set to an iterator, + that iterator will be immediately consumed. + +* The ``AUTH_PROFILE_MODULE`` setting, and the ``get_profile()`` method on + the User model, will be removed. + 2.0 --- diff --git a/docs/intro/tutorial02.txt b/docs/intro/tutorial02.txt index fd13230c8b..b87b280d7c 100644 --- a/docs/intro/tutorial02.txt +++ b/docs/intro/tutorial02.txt @@ -440,20 +440,30 @@ Open your settings file (``mysite/settings.py``, remember) and look at the filesystem directories to check when loading Django templates. It's a search path. +Create a ``mytemplates`` directory in your project directory. Templates can +live anywhere on your filesystem that Django can access. (Django runs as +whatever user your server runs.) However, keeping your templates within the +project is a good convention to follow. + +When you’ve done that, create a directory polls in your template directory. +Within that, create a file called index.html. Note that our +``loader.get_template('polls/index.html')`` code from above maps to +[template_directory]/polls/index.html” on the filesystem. + By default, :setting:`TEMPLATE_DIRS` is empty. So, let's add a line to it, to tell Django where our templates live:: TEMPLATE_DIRS = ( - '/home/my_username/mytemplates', # Change this to your own directory. + '/path/to/mysite/mytemplates', # Change this to your own directory. ) Now copy the template ``admin/base_site.html`` from within the default Django admin template directory in the source code of Django itself (``django/contrib/admin/templates``) into an ``admin`` subdirectory of whichever directory you're using in :setting:`TEMPLATE_DIRS`. For example, if -your :setting:`TEMPLATE_DIRS` includes ``'/home/my_username/mytemplates'``, as +your :setting:`TEMPLATE_DIRS` includes ``'/path/to/mysite/mytemplates'``, as above, then copy ``django/contrib/admin/templates/admin/base_site.html`` to -``/home/my_username/mytemplates/admin/base_site.html``. Don't forget that +``/path/to/mysite/mytemplates/admin/base_site.html``. Don't forget that ``admin`` subdirectory. .. admonition:: Where are the Django source files? diff --git a/docs/intro/tutorial03.txt b/docs/intro/tutorial03.txt index 03d4bf68b3..169e6cd59f 100644 --- a/docs/intro/tutorial03.txt +++ b/docs/intro/tutorial03.txt @@ -10,7 +10,7 @@ Philosophy ========== A view is a "type" of Web page in your Django application that generally serves -a specific function and has a specific template. For example, in a Weblog +a specific function and has a specific template. For example, in a blog application, you might have the following views: * Blog homepage -- displays the latest few entries. @@ -41,42 +41,55 @@ In our poll application, we'll have the following four views: In Django, each view is represented by a simple Python function. -Design your URLs -================ +Write your first view +===================== + +Let's write the first view. Open the file ``polls/views.py`` +and put the following Python code in it:: + + from django.http import HttpResponse + + def index(request): + return HttpResponse("Hello, world. You're at the poll index.") -The first step of writing views is to design your URL structure. You do this by -creating a Python module, called a URLconf. URLconfs are how Django associates -a given URL with given Python code. +This is the simplest view possible in Django. Now we have a problem, how does +this view get called? For that we need to map it to a URL, in Django this is +done in a configuration file called a URLconf. -When a user requests a Django-powered page, the system looks at the -:setting:`ROOT_URLCONF` setting, which contains a string in Python dotted -syntax. Django loads that module and looks for a module-level variable called -``urlpatterns``, which is a sequence of tuples in the following format:: +.. admonition:: What is a URLconf? - (regular expression, Python callback function [, optional dictionary]) + In Django, web pages and other content are delivered by views and + determining which view is called is done by Python modules informally + titled 'URLconfs'. These modules are pure Python code and are a simple + mapping between URL patterns (as simple regular expressions) to Python + callback functions (your views). This tutorial provides basic instruction + in their use, and you can refer to :mod:`django.core.urlresolvers` for + more information. -Django starts at the first regular expression and makes its way down the list, -comparing the requested URL against each regular expression until it finds one -that matches. +To create a URLconf in the polls directory, create a file called ``urls.py``. +Your app directory should now look like:: -When it finds a match, Django calls the Python callback function, with an -:class:`~django.http.HttpRequest` object as the first argument, any "captured" -values from the regular expression as keyword arguments, and, optionally, -arbitrary keyword arguments from the dictionary (an optional third item in the -tuple). + polls/ + __init__.py + admin.py + models.py + tests.py + urls.py + views.py -For more on :class:`~django.http.HttpRequest` objects, see the -:doc:`/ref/request-response`. For more details on URLconfs, see the -:doc:`/topics/http/urls`. +In the ``polls/urls.py`` file include the following code:: -When you ran ``django-admin.py startproject mysite`` at the beginning of -Tutorial 1, it created a default URLconf in ``mysite/urls.py``. It also -automatically set your :setting:`ROOT_URLCONF` setting (in ``settings.py``) to -point at that file:: + from django.conf.urls import patterns, url - ROOT_URLCONF = 'mysite.urls' + from polls import views -Time for an example. Edit ``mysite/urls.py`` so it looks like this:: + urlpatterns = patterns('', + url(r'^$', views.index, name='index') + ) + +The next step is to point the root URLconf at the ``polls.urls`` module. In +``mysite/urls.py`` insert an :func:`~django.conf.urls.include`, leaving you +with:: from django.conf.urls import patterns, include, url @@ -84,111 +97,156 @@ Time for an example. Edit ``mysite/urls.py`` so it looks like this:: admin.autodiscover() urlpatterns = patterns('', - url(r'^polls/$', 'polls.views.index'), - url(r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'), - url(r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'), - url(r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), + url(r'^polls/', include('polls.urls')), url(r'^admin/', include(admin.site.urls)), ) -This is worth a review. When somebody requests a page from your Web site -- say, -"/polls/23/", Django will load this Python module, because it's pointed to by -the :setting:`ROOT_URLCONF` setting. It finds the variable named ``urlpatterns`` -and traverses the regular expressions in order. When it finds a regular -expression that matches -- ``r'^polls/(?P<poll_id>\d+)/$'`` -- it loads the -function ``detail()`` from ``polls/views.py``. Finally, it calls that -``detail()`` function like so:: - - detail(request=<HttpRequest object>, poll_id='23') - -The ``poll_id='23'`` part comes from ``(?P<poll_id>\d+)``. Using parentheses -around a pattern "captures" the text matched by that pattern and sends it as an -argument to the view function; the ``?P<poll_id>`` defines the name that will be -used to identify the matched pattern; and ``\d+`` is a regular expression to -match a sequence of digits (i.e., a number). +You have now wired an `index` view into the URLconf. Go to +http://localhost:8000/polls/ in your browser, and you should see the text +"*Hello, world. You're at the poll index.*", which you defined in the +``index`` view. -Because the URL patterns are regular expressions, there really is no limit on -what you can do with them. And there's no need to add URL cruft such as ``.php`` --- unless you have a sick sense of humor, in which case you can do something -like this:: +The :func:`~django.conf.urls.url` function is passed four arguments, two +required: ``regex`` and ``view``, and two optional: ``kwargs``, and ``name``. +At this point, it's worth reviewing what these arguments are for. - (r'^polls/latest\.php$', 'polls.views.index'), +:func:`~django.conf.urls.url` argument: regex +--------------------------------------------- -But, don't do that. It's silly. +The term `regex` is a commonly used short form meaning `regular expression`, +which is a syntax for matching patterns in strings, or in this case, url +patterns. Django starts at the first regular expression and makes its way down +the list, comparing the requested URL against each regular expression until it +finds one that matches. Note that these regular expressions do not search GET and POST parameters, or -the domain name. For example, in a request to ``http://www.example.com/myapp/``, -the URLconf will look for ``myapp/``. In a request to -``http://www.example.com/myapp/?page=3``, the URLconf will look for ``myapp/``. +the domain name. For example, in a request to +``http://www.example.com/myapp/``, the URLconf will look for ``myapp/``. In a +request to ``http://www.example.com/myapp/?page=3``, the URLconf will also +look for ``myapp/``. If you need help with regular expressions, see `Wikipedia's entry`_ and the documentation of the :mod:`re` module. Also, the O'Reilly book "Mastering -Regular Expressions" by Jeffrey Friedl is fantastic. +Regular Expressions" by Jeffrey Friedl is fantastic. In practice, however, +you don't need to be an expert on regular expressions, as you really only need +to know how to capture simple patterns. In fact, complex regexes can have poor +lookup performance, so you probably shouldn't rely on the full power of regexes. Finally, a performance note: these regular expressions are compiled the first -time the URLconf module is loaded. They're super fast. +time the URLconf module is loaded. They're super fast (as long as the lookups +aren't too complex as noted above). .. _Wikipedia's entry: http://en.wikipedia.org/wiki/Regular_expression -Write your first view -===================== +:func:`~django.conf.urls.url` argument: view +-------------------------------------------- -Well, we haven't created any views yet -- we just have the URLconf. But let's -make sure Django is following the URLconf properly. +When Django finds a regular expression match, Django calls the specified view +function, with an :class:`~django.http.HttpRequest` object as the first +argument and any “captured” values from the regular expression as other +arguments. If the regex uses simple captures, values are passed as positional +arguments; if it uses named captures, values are passed as keyword arguments. +We'll give an example of this in a bit. -Fire up the Django development Web server: +:func:`~django.conf.urls.url` argument: kwargs +---------------------------------------------- -.. code-block:: bash +Arbitrary keyword arguments can be passed in a dictionary to the target view. We +aren't going to use this feature of Django in the tutorial. - python manage.py runserver +:func:`~django.conf.urls.url` argument: name +--------------------------------------------- -Now go to "http://localhost:8000/polls/" on your domain in your Web browser. -You should get a pleasantly-colored error page with the following message:: +Naming your URL lets you refer to it unambiguously from elsewhere in Django +especially templates. This powerful feature allows you to make global changes +to the url patterns of your project while only touching a single file. - ViewDoesNotExist at /polls/ +Writing more views +================== - Could not import polls.views.index. View does not exist in module polls.views. +Now let's add a few more views to ``polls/views.py``. These views are +slightly different, because they take an argument:: -This error happened because you haven't written a function ``index()`` in the -module ``polls/views.py``. + def detail(request, poll_id): + return HttpResponse("You're looking at poll %s." % poll_id) -Try "/polls/23/", "/polls/23/results/" and "/polls/23/vote/". The error -messages tell you which view Django tried (and failed to find, because you -haven't written any views yet). + def results(request, poll_id): + return HttpResponse("You're looking at the results of poll %s." % poll_id) -Time to write the first view. Open the file ``polls/views.py`` -and put the following Python code in it:: + def vote(request, poll_id): + return HttpResponse("You're voting on poll %s." % poll_id) - from django.http import HttpResponse +Wire these news views into the ``polls.urls`` module by adding the following +:func:`~django.conf.urls.url` calls:: - def index(request): - return HttpResponse("Hello, world. You're at the poll index.") + from django.conf.urls import patterns, url -This is the simplest view possible. Go to "/polls/" in your browser, and you -should see your text. + from polls import views -Now lets add a few more views. These views are slightly different, because -they take an argument (which, remember, is passed in from whatever was -captured by the regular expression in the URLconf):: + urlpatterns = patterns('', + # ex: /polls/ + url(r'^$', views.index, name='index'), + # ex: /polls/5/ + url(r'^(?P<poll_id>\d+)/$', views.detail, name='detail'), + # ex: /polls/5/results/ + url(r'^(?P<poll_id>\d+)/results/$', views.results, name='results'), + # ex: /polls/5/vote/ + url(r'^(?P<poll_id>\d+)/vote/$', views.vote, name='vote'), + ) - def detail(request, poll_id): - return HttpResponse("You're looking at poll %s." % poll_id) +Take a look in your browser, at "/polls/34/". It'll run the ``detail()`` +method and display whatever ID you provide in the URL. Try +"/polls/34/results/" and "/polls/34/vote/" too -- these will display the +placeholder results and voting pages. - def results(request, poll_id): - return HttpResponse("You're looking at the results of poll %s." % poll_id) +When somebody requests a page from your Web site -- say, "/polls/34/", Django +will load the ``mysite.urls`` Python module because it's pointed to by the +:setting:`ROOT_URLCONF` setting. It finds the variable named ``urlpatterns`` +and traverses the regular expressions in order. The +:func:`~django.conf.urls.include` functions we are using simply reference +other URLconfs. Note that the regular expressions for the +:func:`~django.conf.urls.include` functions don't have a ``$`` (end-of-string +match character) but rather a trailing slash. Whenever Django encounters +:func:`~django.conf.urls.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. - def vote(request, poll_id): - return HttpResponse("You're voting on poll %s." % poll_id) +The idea behind :func:`~django.conf.urls.include` is to make it easy to +plug-and-play URLs. Since polls are in their own URLconf +(``polls/urls.py``), they can be placed under "/polls/", or under +"/fun_polls/", or under "/content/polls/", or any other path root, and the +app will still work. -Take a look in your browser, at "/polls/34/". It'll run the `detail()` method -and display whatever ID you provide in the URL. Try "/polls/34/results/" and -"/polls/34/vote/" too -- these will display the placeholder results and voting -pages. +Here's what happens if a user goes to "/polls/34/" in this system: + +* Django will find the match at ``'^polls/'`` + +* Then, Django will strip off the matching text (``"polls/"``) and send the + remaining text -- ``"34/"`` -- to the 'polls.urls' URLconf for + further processing which matches ``r'^(?P<poll_id>\d+)/$'`` resulting in a + call to the ``detail()`` view like so:: + + detail(request=<HttpRequest object>, poll_id='34') + +The ``poll_id='34'`` part comes from ``(?P<poll_id>\d+)``. Using parentheses +around a pattern "captures" the text matched by that pattern and sends it as an +argument to the view function; ``?P<poll_id>`` defines the name that will +be used to identify the matched pattern; and ``\d+`` is a regular expression to +match a sequence of digits (i.e., a number). + +Because the URL patterns are regular expressions, there really is no limit on +what you can do with them. And there's no need to add URL cruft such as ``.php`` +-- unless you have a sick sense of humor, in which case you can do something +like this:: + + (r'^polls/latest\.php$', 'polls.views.index'), + +But, don't do that. It's silly. Write views that actually do something ====================================== -Each view is responsible for doing one of two things: Returning an +Each view is responsible for doing one of two things: returning an :class:`~django.http.HttpResponse` object containing the content for the requested page, or raising an exception such as :exc:`~django.http.Http404`. The rest is up to you. @@ -205,51 +263,21 @@ in :doc:`Tutorial 1 </intro/tutorial01>`. Here's one stab at the ``index()`` view, which displays the latest 5 poll questions in the system, separated by commas, according to publication date:: - from polls.models import Poll from django.http import HttpResponse + from polls.models import Poll + def index(request): - latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5] + latest_poll_list = Poll.objects.order_by('-pub_date')[:5] output = ', '.join([p.question for p in latest_poll_list]) return HttpResponse(output) -There's a problem here, though: The page's design is hard-coded in the view. If +There's a problem here, though: the page's design is hard-coded in the view. If you want to change the way the page looks, you'll have to edit this Python code. -So let's use Django's template system to separate the design from Python:: - - from django.template import Context, loader - from polls.models import Poll - from django.http import HttpResponse - - def index(request): - latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5] - t = loader.get_template('polls/index.html') - c = Context({ - 'latest_poll_list': latest_poll_list, - }) - return HttpResponse(t.render(c)) - -That code loads the template called "polls/index.html" and passes it a context. -The context is a dictionary mapping template variable names to Python objects. - -Reload the page. Now you'll see an error:: - - TemplateDoesNotExist at /polls/ - polls/index.html - -Ah. There's no template yet. First, create a directory, somewhere on your -filesystem, whose contents Django can access. (Django runs as whatever user your -server runs.) Don't put them under your document root, though. You probably -shouldn't make them public, just for security's sake. -Then edit :setting:`TEMPLATE_DIRS` in your ``settings.py`` to tell Django where -it can find templates -- just as you did in the "Customize the admin look and -feel" section of Tutorial 2. - -When you've done that, create a directory ``polls`` in your template directory. -Within that, create a file called ``index.html``. Note that our -``loader.get_template('polls/index.html')`` code from above maps to -"[template_directory]/polls/index.html" on the filesystem. +So let's use Django's template system to separate the design from Python. +First, create a directory ``polls`` in your template directory you specified +in setting:`TEMPLATE_DIRS`. Within that, create a file called ``index.html``. Put the following code in that template: .. code-block:: html+django @@ -264,36 +292,58 @@ Put the following code in that template: <p>No polls are available.</p> {% endif %} +Now let's use that html template in our index view:: + + from django.http import HttpResponse + from django.template import Context, loader + + from polls.models import Poll + + def index(request): + latest_poll_list = Poll.objects.order_by('-pub_date')[:5] + template = loader.get_template('polls/index.html') + context = Context({ + 'latest_poll_list': latest_poll_list, + }) + return HttpResponse(template.render(context)) + +That code loads the template called ``polls/index.html`` and passes it a +context. The context is a dictionary mapping template variable names to Python +objects. + Load the page in your Web browser, and you should see a bulleted-list containing the "What's up" poll from Tutorial 1. The link points to the poll's detail page. -A shortcut: render_to_response() --------------------------------- +A shortcut: :func:`~django.shortcuts.render` +-------------------------------------------- It's a very common idiom to load a template, fill a context and return an :class:`~django.http.HttpResponse` object with the result of the rendered template. Django provides a shortcut. Here's the full ``index()`` view, rewritten:: - from django.shortcuts import render_to_response + from django.shortcuts import render + from polls.models import Poll def index(request): latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5] - return render_to_response('polls/index.html', {'latest_poll_list': latest_poll_list}) + context = {'latest_poll_list': latest_poll_list} + return render(request, 'polls/index.html', context) Note that once we've done this in all these views, we no longer need to import :mod:`~django.template.loader`, :class:`~django.template.Context` and -:class:`~django.http.HttpResponse`. +:class:`~django.http.HttpResponse` (you'll want to keep ``HttpResponse`` if you +still have the stub methods for ``detail``, ``results``, and ``vote``). -The :func:`~django.shortcuts.render_to_response` function takes a template name -as its first argument and a dictionary as its optional second argument. It -returns an :class:`~django.http.HttpResponse` object of the given template -rendered with the given context. +The :func:`~django.shortcuts.render` function takes the request object as its +first argument, a template name as its second argument and a dictionary as its +optional third argument. It returns an :class:`~django.http.HttpResponse` +object of the given template rendered with the given context. -Raising 404 -=========== +Raising a 404 error +=================== Now, let's tackle the poll detail view -- the page that displays the question for a given poll. Here's the view:: @@ -302,10 +352,10 @@ for a given poll. Here's the view:: # ... def detail(request, poll_id): try: - p = Poll.objects.get(pk=poll_id) + poll = Poll.objects.get(pk=poll_id) except Poll.DoesNotExist: raise Http404 - return render_to_response('polls/detail.html', {'poll': p}) + return render(request, 'polls/detail.html', {'poll': poll}) The new concept here: The view raises the :exc:`~django.http.Http404` exception if a poll with the requested ID doesn't exist. @@ -317,18 +367,18 @@ later, but if you'd like to quickly get the above example working, just:: will get you started for now. -A shortcut: get_object_or_404() -------------------------------- +A shortcut: :func:`~django.shortcuts.get_object_or_404` +------------------------------------------------------- It's a very common idiom to use :meth:`~django.db.models.query.QuerySet.get` and raise :exc:`~django.http.Http404` if the object doesn't exist. Django provides a shortcut. Here's the ``detail()`` view, rewritten:: - from django.shortcuts import render_to_response, get_object_or_404 + from django.shortcuts import render, get_object_or_404 # ... def detail(request, poll_id): - p = get_object_or_404(Poll, pk=poll_id) - return render_to_response('polls/detail.html', {'poll': p}) + poll = get_object_or_404(Poll, pk=poll_id) + return render(request, 'polls/detail.html', {'poll': poll}) The :func:`~django.shortcuts.get_object_or_404` function takes a Django model as its first argument and an arbitrary number of keyword arguments, which it @@ -345,7 +395,8 @@ exist. :exc:`~django.core.exceptions.ObjectDoesNotExist`? Because that would couple the model layer to the view layer. One of the - foremost design goals of Django is to maintain loose coupling. + foremost design goals of Django is to maintain loose coupling. Some + controlled coupling is introduced in the :mod:`django.shortcuts` module. There's also a :func:`~django.shortcuts.get_list_or_404` function, which works just as :func:`~django.shortcuts.get_object_or_404` -- except using @@ -366,11 +417,11 @@ special: It's just a normal view. You normally won't have to bother with writing 404 views. If you don't set ``handler404``, the built-in view :func:`django.views.defaults.page_not_found` -is used by default. In this case, you still have one obligation: create a -``404.html`` template in the root of your template directory. The default 404 -view will use that template for all 404 errors. If :setting:`DEBUG` is set to -``False`` (in your settings module) and if you didn't create a ``404.html`` -file, an ``Http500`` is raised instead. So remember to create a ``404.html``. +is used by default. Optionally, you can create a ``404.html`` template +in the root of your template directory. The default 404 view will then use that +template for all 404 errors when :setting:`DEBUG` is set to ``False`` (in your +settings module). If you do create the template, add at least some dummy +content like "Page not found". A couple more things to note about 404 views: @@ -388,11 +439,14 @@ Similarly, your root URLconf may define a ``handler500``, which points to a view to call in case of server errors. Server errors happen when you have runtime errors in view code. +Likewise, you should create a ``500.html`` template at the root of your +template directory and add some content like "Something went wrong". + Use the template system ======================= Back to the ``detail()`` view for our poll application. Given the context -variable ``poll``, here's what the "polls/detail.html" template might look +variable ``poll``, here's what the ``polls/detail.html`` template might look like: .. code-block:: html+django @@ -417,75 +471,67 @@ suitable for use in the :ttag:`{% for %}<for>` tag. See the :doc:`template guide </topics/templates>` for more about templates. -Simplifying the URLconfs -======================== +Removing hardcoded URLs in templates +==================================== -Take some time to play around with the views and template system. As you edit -the URLconf, you may notice there's a fair bit of redundancy in it:: +Remember, when we wrote the link to a poll in the ``polls/index.html`` +template, the link was partially hardcoded like this: - urlpatterns = patterns('', - url(r'^polls/$', 'polls.views.index'), - url(r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'), - url(r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'), - url(r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), - ) +.. code-block:: html+django -Namely, ``polls.views`` is in every callback. + <li><a href="/polls/{{ poll.id }}/">{{ poll.question }}</a></li> -Because this is a common case, the URLconf framework provides a shortcut for -common prefixes. You can factor out the common prefixes and add them as the -first argument to :func:`~django.conf.urls.patterns`, like so:: +The problem with this hardcoded, tightly-coupled approach is that it becomes +challenging to change URLs on projects with a lot of templates. However, since +you defined the name argument in the :func:`~django.conf.urls.url` functions in +the ``polls.urls`` module, you can remove a reliance on specific URL paths +defined in your url configurations by using the ``{% url %}`` template tag: - urlpatterns = patterns('polls.views', - url(r'^polls/$', 'index'), - url(r'^polls/(?P<poll_id>\d+)/$', 'detail'), - url(r'^polls/(?P<poll_id>\d+)/results/$', 'results'), - url(r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'), - ) +.. code-block:: html+django -This is functionally identical to the previous formatting. It's just a bit -tidier. + <li><a href="{% url 'detail' poll.id %}">{{ poll.question }}</a></li> -Since you generally don't want the prefix for one app to be applied to every -callback in your URLconf, you can concatenate multiple -:func:`~django.conf.urls.patterns`. Your full ``mysite/urls.py`` might -now look like this:: +.. note:: - from django.conf.urls import patterns, include, url + If ``{% url 'detail' poll.id %}`` (with quotes) doesn't work, but + ``{% url detail poll.id %}`` (without quotes) does, that means you're + using a version of Django < 1.5. In this case, add the following + declaration at the top of your template: - from django.contrib import admin - admin.autodiscover() + .. code-block:: html+django - urlpatterns = patterns('polls.views', - url(r'^polls/$', 'index'), - url(r'^polls/(?P<poll_id>\d+)/$', 'detail'), - url(r'^polls/(?P<poll_id>\d+)/results/$', 'results'), - url(r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'), - ) + {% load url from future %} - urlpatterns += patterns('', - url(r'^admin/', include(admin.site.urls)), - ) +The way this works is by looking up the URL definition as specified in the +``polls.urls`` module. You can see exactly where the URL name of 'detail' is +defined below:: -Decoupling the URLconfs -======================= + ... + # the 'name' value as called by the {% url %} template tag + url(r'^(?P<poll_id>\d+)/$', views.detail, name='detail'), + ... -While we're at it, we should take the time to decouple our poll-app URLs from -our Django project configuration. Django apps are meant to be pluggable -- that -is, each particular app should be transferable to another Django installation -with minimal fuss. +If you want to change the URL of the polls detail view to something else, +perhaps to something like ``polls/specifics/12/`` instead of doing it in the +template (or templates) you would change it in ``polls/urls.py``:: -Our poll app is pretty decoupled at this point, thanks to the strict directory -structure that ``python manage.py startapp`` created, but one part of it is -coupled to the Django settings: The URLconf. + ... + # added the word 'specifics' + url(r'^specifics/(?P<poll_id>\d+)/$', views.detail, name='detail'), + ... -We've been editing the URLs in ``mysite/urls.py``, but the URL design of an -app is specific to the app, not to the Django installation -- so let's move the -URLs within the app directory. +Namespacing URL names +====================== -Copy the file ``mysite/urls.py`` to ``polls/urls.py``. Then, change -``mysite/urls.py`` to remove the poll-specific URLs and insert an -:func:`~django.conf.urls.include`, leaving you with:: +The tutorial project has just one app, ``polls``. In real Django projects, +there might be five, ten, twenty apps or more. How does Django differentiate +the URL names between them? For example, the ``polls`` app has a ``detail`` +view, and so might an app on the same project that is for a blog. How does one +make it so that Django knows which app view to create for a url when using the +``{% url %}`` template tag? + +The answer is to add namespaces to your root URLconf. In the +``mysite/urls.py`` file, go ahead and change it to include namespacing:: from django.conf.urls import patterns, include, url @@ -493,74 +539,21 @@ Copy the file ``mysite/urls.py`` to ``polls/urls.py``. Then, change admin.autodiscover() urlpatterns = patterns('', - url(r'^polls/', include('polls.urls')), + url(r'^polls/', include('polls.urls', namespace="polls")), url(r'^admin/', include(admin.site.urls)), ) -:func:`~django.conf.urls.include` simply references another URLconf. -Note that the regular expression doesn't have a ``$`` (end-of-string match -character) but has the trailing slash. Whenever Django encounters -:func:`~django.conf.urls.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. - -Here's what happens if a user goes to "/polls/34/" in this system: - -* Django will find the match at ``'^polls/'`` - -* Then, Django will strip off the matching text (``"polls/"``) and send the - remaining text -- ``"34/"`` -- to the 'polls.urls' URLconf for - further processing. - -Now that we've decoupled that, we need to decouple the ``polls.urls`` -URLconf by removing the leading "polls/" from each line, removing the -lines registering the admin site, and removing the ``include`` import which -is no longer used. Your ``polls/urls.py`` file should now look like -this:: - - from django.conf.urls import patterns, url - - urlpatterns = patterns('polls.views', - url(r'^$', 'index'), - url(r'^(?P<poll_id>\d+)/$', 'detail'), - url(r'^(?P<poll_id>\d+)/results/$', 'results'), - url(r'^(?P<poll_id>\d+)/vote/$', 'vote'), - ) - -The idea behind :func:`~django.conf.urls.include` and URLconf -decoupling is to make it easy to plug-and-play URLs. Now that polls are in their -own URLconf, they can be placed under "/polls/", or under "/fun_polls/", or -under "/content/polls/", or any other path root, and the app will still work. - -All the poll app cares about is its relative path, not its absolute path. - -Removing hardcoded URLs in templates ------------------------------------- - -Remember, when we wrote the link to a poll in our template, the link was -partially hardcoded like this: +Now change your ``polls/index.html`` template from: .. code-block:: html+django - <li><a href="/polls/{{ poll.id }}/">{{ poll.question }}</a></li> + <li><a href="{% url 'detail' poll.id %}">{{ poll.question }}</a></li> -To use the decoupled URLs we've just introduced, replace the hardcoded link -with the :ttag:`url` template tag: +to point at the namespaced detail view: .. code-block:: html+django - <li><a href="{% url 'polls.views.detail' poll.id %}">{{ poll.question }}</a></li> - -.. note:: - - If ``{% url 'polls.views.detail' poll.id %}`` (with quotes) doesn't work, - but ``{% url polls.views.detail poll.id %}`` (without quotes) does, that - means you're using a version of Django ≤ 1.4. In this case, add the - following declaration at the top of your template: - - .. code-block:: html+django - - {% load url from future %} + <li><a href="{% url 'polls:detail' poll.id %}">{{ poll.question }}</a></li> When you're comfortable with writing views, read :doc:`part 4 of this tutorial </intro/tutorial04>` to learn about simple form processing and generic views. diff --git a/docs/intro/tutorial04.txt b/docs/intro/tutorial04.txt index 49e597ca29..8909caf98b 100644 --- a/docs/intro/tutorial04.txt +++ b/docs/intro/tutorial04.txt @@ -18,7 +18,7 @@ tutorial, so that the template contains an HTML ``<form>`` element: {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} - <form action="{% url 'polls.views.vote' poll.id %}" method="post"> + <form action="{% url 'polls:vote' poll.id %}" method="post"> {% csrf_token %} {% for choice in poll.choice_set.all %} <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" /> @@ -35,7 +35,7 @@ A quick rundown: selects one of the radio buttons and submits the form, it'll send the POST data ``choice=3``. This is HTML Forms 101. -* We set the form's ``action`` to ``{% url 'polls.views.vote' poll.id %}``, and we +* We set the form's ``action`` to ``{% url 'polls:vote' poll.id %}``, and we set ``method="post"``. Using ``method="post"`` (as opposed to ``method="get"``) is very important, because the act of submitting this form will alter data server-side. Whenever you create a form that alters @@ -52,34 +52,18 @@ A quick rundown: forms that are targeted at internal URLs should use the :ttag:`{% csrf_token %}<csrf_token>` template tag. -The :ttag:`{% csrf_token %}<csrf_token>` tag requires information from the -request object, which is not normally accessible from within the template -context. To fix this, a small adjustment needs to be made to the ``detail`` -view, so that it looks like the following:: - - from django.template import RequestContext - # ... - def detail(request, poll_id): - p = get_object_or_404(Poll, pk=poll_id) - return render_to_response('polls/detail.html', {'poll': p}, - context_instance=RequestContext(request)) - -The details of how this works are explained in the documentation for -:ref:`RequestContext <subclassing-context-requestcontext>`. - Now, let's create a Django view that handles the submitted data and does something with it. Remember, in :doc:`Tutorial 3 </intro/tutorial03>`, we created a URLconf for the polls application that includes this line:: - (r'^(?P<poll_id>\d+)/vote/$', 'vote'), + url(r'^(?P<poll_id>\d+)/vote/$', views.vote, name='vote'), We also created a dummy implementation of the ``vote()`` function. Let's create a real version. Add the following to ``polls/views.py``:: - from django.shortcuts import get_object_or_404, render_to_response + from django.shortcuts import get_object_or_404, render from django.http import HttpResponseRedirect, HttpResponse from django.core.urlresolvers import reverse - from django.template import RequestContext from polls.models import Choice, Poll # ... def vote(request, poll_id): @@ -88,17 +72,17 @@ create a real version. Add the following to ``polls/views.py``:: selected_choice = p.choice_set.get(pk=request.POST['choice']) except (KeyError, Choice.DoesNotExist): # Redisplay the poll voting form. - return render_to_response('polls/detail.html', { + return render(request, 'polls/detail.html', { 'poll': p, 'error_message': "You didn't select a choice.", - }, context_instance=RequestContext(request)) + }) else: selected_choice.votes += 1 selected_choice.save() # Always return an HttpResponseRedirect after successfully dealing # with POST data. This prevents data from being posted twice if a # user hits the Back button. - return HttpResponseRedirect(reverse('polls.views.results', args=(p.id,))) + return HttpResponseRedirect(reverse('polls:results', args=(p.id,))) This code includes a few things we haven't covered yet in this tutorial: @@ -142,8 +126,7 @@ This code includes a few things we haven't covered yet in this tutorial: '/polls/3/results/' ... where the ``3`` is the value of ``p.id``. This redirected URL will - then call the ``'results'`` view to display the final page. Note that you - need to use the full name of the view here (including the prefix). + then call the ``'results'`` view to display the final page. As mentioned in Tutorial 3, ``request`` is a :class:`~django.http.HttpRequest` object. For more on :class:`~django.http.HttpRequest` objects, see the @@ -153,14 +136,14 @@ After somebody votes in a poll, the ``vote()`` view redirects to the results page for the poll. Let's write that view:: def results(request, poll_id): - p = get_object_or_404(Poll, pk=poll_id) - return render_to_response('polls/results.html', {'poll': p}) + poll = get_object_or_404(Poll, pk=poll_id) + return render(request, 'polls/results.html', {'poll': poll}) This is almost exactly the same as the ``detail()`` view from :doc:`Tutorial 3 </intro/tutorial03>`. The only difference is the template name. We'll fix this redundancy later. -Now, create a ``results.html`` template: +Now, create a ``polls/results.html`` template: .. code-block:: html+django @@ -172,7 +155,7 @@ Now, create a ``results.html`` template: {% endfor %} </ul> - <a href="{% url 'polls.views.detail' poll.id %}">Vote again?</a> + <a href="{% url 'polls:detail' poll.id %}">Vote again?</a> Now, go to ``/polls/1/`` in your browser and vote in the poll. You should see a results page that gets updated each time you vote. If you submit the form @@ -215,19 +198,7 @@ Read on for details. You should know basic math before you start using a calculator. -First, open the ``polls/urls.py`` URLconf. It looks like this, according to the -tutorial so far:: - - from django.conf.urls import patterns, url - - urlpatterns = patterns('polls.views', - url(r'^$', 'index'), - url(r'^(?P<poll_id>\d+)/$', 'detail'), - url(r'^(?P<poll_id>\d+)/results/$', 'results'), - url(r'^(?P<poll_id>\d+)/vote/$', 'vote'), - ) - -Change it like so:: +First, open the ``polls/urls.py`` URLconf and change it like so:: from django.conf.urls import patterns, url from django.views.generic import DetailView, ListView @@ -239,18 +210,18 @@ Change it like so:: queryset=Poll.objects.order_by('-pub_date')[:5], context_object_name='latest_poll_list', template_name='polls/index.html'), - name='poll_index'), + name='index'), url(r'^(?P<pk>\d+)/$', DetailView.as_view( model=Poll, template_name='polls/detail.html'), - name='poll_detail'), + name='detail'), url(r'^(?P<pk>\d+)/results/$', DetailView.as_view( model=Poll, template_name='polls/results.html'), - name='poll_results'), - url(r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), + name='results'), + url(r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote', name='vote'), ) We're using two generic views here: @@ -267,15 +238,6 @@ two views abstract the concepts of "display a list of objects" and ``"pk"``, so we've changed ``poll_id`` to ``pk`` for the generic views. -* We've added the ``name`` argument to the views (e.g. ``name='poll_results'``) - so that we have a way to refer to their URL later on (see the - documentation about :ref:`naming URL patterns - <naming-url-patterns>` for information). We're also using the - :func:`~django.conf.urls.url` function from - :mod:`django.conf.urls` here. It's a good habit to use - :func:`~django.conf.urls.url` when you are providing a - pattern name like this. - By default, the :class:`~django.views.generic.list.DetailView` generic view uses a template called ``<app name>/<model name>_detail.html``. In our case, it'll use the template ``"polls/poll_detail.html"``. The @@ -308,41 +270,13 @@ You can now delete the ``index()``, ``detail()`` and ``results()`` views from ``polls/views.py``. We don't need them anymore -- they have been replaced by generic views. -The last thing to do is fix the URL handling to account for the use of -generic views. In the vote view above, we used the -:func:`~django.core.urlresolvers.reverse` function to avoid -hard-coding our URLs. Now that we've switched to a generic view, we'll -need to change the :func:`~django.core.urlresolvers.reverse` call to -point back to our new generic view. We can't simply use the view -function anymore -- generic views can be (and are) used multiple times --- but we can use the name we've given:: - - return HttpResponseRedirect(reverse('poll_results', args=(p.id,))) - -The same rule apply for the :ttag:`url` template tag. For example in the -``results.html`` template: - -.. code-block:: html+django - - <a href="{% url 'poll_detail' poll.id %}">Vote again?</a> - Run the server, and use your new polling app based on generic views. For full details on generic views, see the :doc:`generic views documentation </topics/class-based-views/index>`. -Coming soon -=========== - -The tutorial ends here for the time being. Future installments of the tutorial -will cover: - -* Advanced form processing -* Using the RSS framework -* Using the cache framework -* Using the comments framework -* Advanced admin features: Permissions -* Advanced admin features: Custom JavaScript +What's next? +============ -In the meantime, you might want to check out some pointers on :doc:`where to go -from here </intro/whatsnext>` +The tutorial ends here for the time being. In the meantime, you might want to +check out some pointers on :doc:`where to go from here </intro/whatsnext>`. diff --git a/docs/intro/whatsnext.txt b/docs/intro/whatsnext.txt index ea4b18de03..500a858d47 100644 --- a/docs/intro/whatsnext.txt +++ b/docs/intro/whatsnext.txt @@ -216,15 +216,13 @@ We follow this policy: "New in version X.Y", being X.Y the next release version (hence, the one being developed). -* Documentation for a particular Django release is frozen once the version - has been released officially. It remains a snapshot of the docs as of the - moment of the release. We will make exceptions to this rule in - the case of retroactive security updates or other such retroactive - changes. Once documentation is frozen, we add a note to the top of each - frozen document that says "These docs are frozen for Django version XXX" - and links to the current version of that document. +* Documentation fixes and improvements may be backported to the last release + branch, at the discretion of the committer, however, once a version of + Django is :ref:`no longer supported<backwards-compatibility-policy>`, that + version of the docs won't get any further updates. * The `main documentation Web page`_ includes links to documentation for - all previous versions. + all previous versions. Be sure you are using the version of the docs + corresponding to the version of Django you are using! .. _main documentation Web page: https://docs.djangoproject.com/en/dev/ diff --git a/docs/misc/api-stability.txt b/docs/misc/api-stability.txt index 2839ee3594..4f232e795b 100644 --- a/docs/misc/api-stability.txt +++ b/docs/misc/api-stability.txt @@ -155,8 +155,6 @@ Certain APIs are explicitly marked as "internal" in a couple of ways: Local flavors ------------- -.. versionchanged:: 1.3 - :mod:`django.contrib.localflavor` contains assorted pieces of code that are useful for particular countries or cultures. This data is local in nature, and is subject to change on timelines that will diff --git a/docs/misc/distributions.txt b/docs/misc/distributions.txt index 729ce0717b..1b324234d1 100644 --- a/docs/misc/distributions.txt +++ b/docs/misc/distributions.txt @@ -11,7 +11,7 @@ requires. Typically, these packages are based on the latest stable release of Django, so if you want to use the development version of Django you'll need to follow the instructions for :ref:`installing the development version -<installing-development-version>` from our Subversion repository. +<installing-development-version>` from our Git repository. If you're using Linux or a Unix installation, such as OpenSolaris, check with your distributor to see if they already package Django. If diff --git a/docs/ref/class-based-views/generic-date-based.txt b/docs/ref/class-based-views/generic-date-based.txt index 64b269f514..c6af23e421 100644 --- a/docs/ref/class-based-views/generic-date-based.txt +++ b/docs/ref/class-based-views/generic-date-based.txt @@ -87,16 +87,24 @@ YearArchiveView * ``year``: A :class:`~datetime.date` object representing the given year. + .. versionchanged:: 1.5 + + Previously, this returned a string. + * ``next_year``: A :class:`~datetime.date` object representing the first day of the next year, according to :attr:`~BaseDateListView.allow_empty` and :attr:`~DateMixin.allow_future`. + .. versionadded:: 1.5 + * ``previous_year``: A :class:`~datetime.date` object representing the first day of the previous year, according to :attr:`~BaseDateListView.allow_empty` and :attr:`~DateMixin.allow_future`. + .. versionadded:: 1.5 + **Notes** * Uses a default ``template_name_suffix`` of ``_archive_year``. diff --git a/docs/ref/class-based-views/mixins-date-based.txt b/docs/ref/class-based-views/mixins-date-based.txt index 01181ebb6c..561e525e70 100644 --- a/docs/ref/class-based-views/mixins-date-based.txt +++ b/docs/ref/class-based-views/mixins-date-based.txt @@ -318,12 +318,16 @@ BaseDateListView Returns the aggregation period for ``date_list``. Returns :attr:`~BaseDateListView.date_list_period` by default. - .. method:: get_date_list(queryset, date_type=None) + .. method:: get_date_list(queryset, date_type=None, ordering='ASC') Returns the list of dates of type ``date_type`` for which ``queryset`` contains entries. For example, ``get_date_list(qs, 'year')`` will return the list of years for which ``qs`` has entries. If ``date_type`` isn't provided, the result of - :meth:`BaseDateListView.get_date_list_period` is used. See - :meth:`~django.db.models.query.QuerySet.dates()` for the ways that the - ``date_type`` argument can be used. + :meth:`~BaseDateListView.get_date_list_period` is used. ``date_type`` + and ``ordering`` are simply passed to + :meth:`QuerySet.dates()<django.db.models.query.QuerySet.dates>`. + + .. versionchanged:: 1.5 + The ``ordering`` parameter was added, and the default order was + changed to ascending. diff --git a/docs/ref/contrib/admin/_images/raw_id_fields.png b/docs/ref/contrib/admin/_images/raw_id_fields.png Binary files differnew file mode 100644 index 0000000000..0774c40469 --- /dev/null +++ b/docs/ref/contrib/admin/_images/raw_id_fields.png diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt index 66a5a2cc4f..6ed929cb7d 100644 --- a/docs/ref/contrib/admin/index.txt +++ b/docs/ref/contrib/admin/index.txt @@ -60,6 +60,8 @@ Other topics For information about serving the static files (images, JavaScript, and CSS) associated with the admin in production, see :ref:`serving-files`. + Having problems? Try :doc:`/faq/admin`. + ``ModelAdmin`` objects ====================== @@ -129,8 +131,6 @@ subclass:: date_hierarchy = 'pub_date' - .. versionadded:: 1.3 - This will intelligently populate itself based on available data, e.g. if all the dates are in one month, it'll show the day-level drill-down only. @@ -307,7 +307,9 @@ subclass:: By default a ``ModelForm`` is dynamically created for your model. It is used to create the form presented on both the add/change pages. You can easily provide your own ``ModelForm`` to override any default form behavior - on the add/change pages. + on the add/change pages. Alternatively, you can customize the default + form rather than specifying an entirely new one by using the + :meth:`ModelAdmin.get_form` method. For an example see the section `Adding custom validation to the admin`_. @@ -373,7 +375,8 @@ subclass:: .. attribute:: ModelAdmin.inlines - See :class:`InlineModelAdmin` objects below. + See :class:`InlineModelAdmin` objects below as well as + :meth:`ModelAdmin.get_formsets`. .. attribute:: ModelAdmin.list_display @@ -576,8 +579,6 @@ subclass:: class PersonAdmin(ModelAdmin): list_filter = ('is_staff', 'company') - .. versionadded:: 1.3 - Field names in ``list_filter`` can also span relations using the ``__`` lookup, for example:: @@ -748,8 +749,6 @@ subclass:: .. attribute:: ModelAdmin.paginator - .. versionadded:: 1.3 - The paginator class to be used for pagination. By default, :class:`django.core.paginator.Paginator` is used. If the custom paginator class doesn't have the same constructor interface as @@ -804,6 +803,14 @@ subclass:: class ArticleAdmin(admin.ModelAdmin): raw_id_fields = ("newspaper",) + The ``raw_id_fields`` ``Input`` widget should contain a primary key if the + field is a ``ForeignKey`` or a comma separated list of values if the field + is a ``ManyToManyField``. The ``raw_id_fields`` widget shows a magnifying + glass button next to the field which allows users to search for and select + a value: + + .. image:: _images/raw_id_fields.png + .. attribute:: ModelAdmin.readonly_fields By default the admin shows all fields as editable. Any fields in this @@ -966,8 +973,6 @@ templates used by the :class:`ModelAdmin` views: .. method:: ModelAdmin.delete_model(self, request, obj) - .. versionadded:: 1.3 - The ``delete_model`` method is given the ``HttpRequest`` and a model instance. Use this method to do pre- or post-delete operations. @@ -1049,6 +1054,16 @@ templates used by the :class:`ModelAdmin` views: changelist that will be linked to the change view, as described in the :attr:`ModelAdmin.list_display_links` section. +.. method:: ModelAdmin.get_inline_instances(self, request, obj=None) + + .. versionadded:: 1.5 + + The ``get_inline_instances`` method is given the ``HttpRequest`` and the + ``obj`` being edited (or ``None`` on an add form) and is expected to return + a ``list`` or ``tuple`` of :class:`~django.contrib.admin.InlineModelAdmin` + objects, as described below in the :class:`~django.contrib.admin.InlineModelAdmin` + section. + .. method:: ModelAdmin.get_urls(self) The ``get_urls`` method on a ``ModelAdmin`` returns the URLs to be used for @@ -1115,6 +1130,38 @@ templates used by the :class:`ModelAdmin` views: (r'^my_view/$', self.admin_site.admin_view(self.my_view, cacheable=True)) +.. method:: ModelAdmin.get_form(self, request, obj=None, **kwargs) + + Returns a :class:`~django.forms.ModelForm` class for use in the admin add + and change views, see :meth:`add_view` and :meth:`change_view`. + + If you wanted to hide a field from non-superusers, for example, you could + override ``get_form`` as follows:: + + class MyModelAdmin(admin.ModelAdmin): + def get_form(self, request, obj=None, **kwargs): + self.exclude = [] + if not request.user.is_superuser: + self.exclude.append('field_to_hide') + return super(MyModelAdmin, self).get_form(request, obj, **kwargs) + +.. method:: ModelAdmin.get_formsets(self, request, obj=None) + + Yields :class:`InlineModelAdmin`\s for use in admin add and change views. + + For example if you wanted to display a particular inline only in the change + view, you could override ``get_formsets`` as follows:: + + class MyModelAdmin(admin.ModelAdmin): + inlines = [MyInline, SomeOtherInline] + + def get_formsets(self, request, obj=None): + for inline in self.get_inline_instances(request, obj): + # hide MyInline in the add view + if isinstance(inline, MyInline) and obj is None: + continue + yield inline.get_formset(request, obj) + .. method:: ModelAdmin.formfield_for_foreignkey(self, db_field, request, **kwargs) The ``formfield_for_foreignkey`` method on a ``ModelAdmin`` allows you to @@ -1213,8 +1260,6 @@ templates used by the :class:`ModelAdmin` views: .. method:: ModelAdmin.get_paginator(queryset, per_page, orphans=0, allow_empty_first_page=True) - .. versionadded:: 1.3 - Returns an instance of the paginator to use for this view. By default, instantiates an instance of :attr:`paginator`. @@ -1295,8 +1340,6 @@ on your ``ModelAdmin``:: } js = ("my_code.js",) -.. versionchanged:: 1.3 - The :doc:`staticfiles app </ref/contrib/staticfiles>` prepends :setting:`STATIC_URL` (or :setting:`MEDIA_URL` if :setting:`STATIC_URL` is ``None``) to any media paths. The same rules apply as :ref:`regular media @@ -1394,18 +1437,15 @@ adds some of its own (the shared features are actually defined in the - :attr:`~ModelAdmin.exclude` - :attr:`~ModelAdmin.filter_horizontal` - :attr:`~ModelAdmin.filter_vertical` +- :attr:`~ModelAdmin.ordering` - :attr:`~ModelAdmin.prepopulated_fields` +- :meth:`~ModelAdmin.queryset` - :attr:`~ModelAdmin.radio_fields` - :attr:`~ModelAdmin.readonly_fields` - :attr:`~InlineModelAdmin.raw_id_fields` - :meth:`~ModelAdmin.formfield_for_foreignkey` - :meth:`~ModelAdmin.formfield_for_manytomany` -.. versionadded:: 1.3 - -- :attr:`~ModelAdmin.ordering` -- :meth:`~ModelAdmin.queryset` - .. versionadded:: 1.4 - :meth:`~ModelAdmin.has_add_permission` @@ -1436,8 +1476,6 @@ The ``InlineModelAdmin`` class adds: through to ``inlineformset_factory`` when creating the formset for this inline. - .. _ref-contrib-admin-inline-extra: - .. attribute:: InlineModelAdmin.extra This controls the number of extra forms the formset will display in @@ -1813,8 +1851,6 @@ Templates can override or extend base admin templates as described in .. attribute:: AdminSite.login_form - .. versionadded:: 1.3 - Subclass of :class:`~django.contrib.auth.forms.AuthenticationForm` that will be used by the admin site login view. diff --git a/docs/ref/contrib/comments/example.txt b/docs/ref/contrib/comments/example.txt index e78d83c35d..2bff778c2f 100644 --- a/docs/ref/contrib/comments/example.txt +++ b/docs/ref/contrib/comments/example.txt @@ -152,27 +152,6 @@ enable it in your project's ``urls.py``: Now you should have the latest comment feeds being served off ``/feeds/latest/``. -.. versionchanged:: 1.3 - -Prior to Django 1.3, the LatestCommentFeed was deployed using the -syndication feed view: - -.. code-block:: python - - from django.conf.urls import patterns - from django.contrib.comments.feeds import LatestCommentFeed - - feeds = { - 'latest': LatestCommentFeed, - } - - urlpatterns = patterns('', - # ... - (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed', - {'feed_dict': feeds}), - # ... - ) - Moderation ========== diff --git a/docs/ref/contrib/comments/index.txt b/docs/ref/contrib/comments/index.txt index 4b1dd96280..1c6ff7c7ed 100644 --- a/docs/ref/contrib/comments/index.txt +++ b/docs/ref/contrib/comments/index.txt @@ -254,6 +254,56 @@ you can include a hidden form input called ``next`` in your comment form. For ex <input type="hidden" name="next" value="{% url 'my_comment_was_posted' %}" /> +Providing a comment form for authenticated users +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If a user is already authenticated, it makes little sense to display the name, +email, and URL fields, since these can already be retrieved from their login +data and profile. In addition, some sites will only accept comments from +authenticated users. + +To provide a comment form for authenticated users, you can manually provide the +additional fields expected by the Django comments framework. For example, +assuming comments are attached to the model "object":: + + {% if user.is_authenticated %} + {% get_comment_form for object as form %} + <form action="{% comment_form_target %}" method="POST"> + {% csrf_token %} + {{ form.comment }} + {{ form.honeypot }} + {{ form.content_type }} + {{ form.object_pk }} + {{ form.timestamp }} + {{ form.security_hash }} + <input type="hidden" name="next" value="{% url 'object_detail_view' object.id %}" /> + <input type="submit" value="Add comment" id="id_submit" /> + </form> + {% else %} + <p>Please <a href="{% url 'auth_login' %}">log in</a> to leave a comment.</p> + {% endif %} + +The honeypot, content_type, object_pk, timestamp, and security_hash fields are +fields that would have been created automatically if you had simply used +``{{ form }}`` in your template, and are referred to in `Notes on the comment +form`_ below. + +Note that we do not need to specify the user to be associated with comments +submitted by authenticated users. This is possible because the :doc:`Built-in +Comment Models</ref/contrib/comments/models>` that come with Django associate +comments with authenticated users by default. + +In this example, the honeypot field will still be visible to the user; you'll +need to hide that field in your CSS:: + + #id_honeypot { + display: none; + } + +If you want to accept either anonymous or authenticated comments, replace the +contents of the "else" clause above with a standard comment form and the right +thing will happen whether a user is logged in or not. + .. _notes-on-the-comment-form: Notes on the comment form diff --git a/docs/ref/contrib/comments/moderation.txt b/docs/ref/contrib/comments/moderation.txt index f03c7fda0d..39b3ea7913 100644 --- a/docs/ref/contrib/comments/moderation.txt +++ b/docs/ref/contrib/comments/moderation.txt @@ -136,10 +136,6 @@ Simply subclassing :class:`CommentModerator` and changing the values of these options will automatically enable the various moderation methods for any models registered using the subclass. -.. versionchanged:: 1.3 - -``moderate_after`` and ``close_after`` now accept 0 as a valid value. - Adding custom moderation methods -------------------------------- diff --git a/docs/ref/contrib/contenttypes.txt b/docs/ref/contrib/contenttypes.txt index e98da6e429..dfbeabc302 100644 --- a/docs/ref/contrib/contenttypes.txt +++ b/docs/ref/contrib/contenttypes.txt @@ -423,8 +423,6 @@ pointing at it will be deleted as well. In the example above, this means that if a ``Bookmark`` object were deleted, any ``TaggedItem`` objects pointing at it would be deleted at the same time. -.. versionadded:: 1.3 - Unlike :class:`~django.db.models.ForeignKey`, :class:`~django.contrib.contenttypes.generic.GenericForeignKey` does not accept an :attr:`~django.db.models.ForeignKey.on_delete` argument to customize this diff --git a/docs/ref/contrib/csrf.txt b/docs/ref/contrib/csrf.txt index 8d352ff8b2..32d8a705bc 100644 --- a/docs/ref/contrib/csrf.txt +++ b/docs/ref/contrib/csrf.txt @@ -72,9 +72,9 @@ To enable CSRF protection for your views, follow these steps: :func:`~django.shortcuts.render_to_response()` wrapper that takes care of this step for you. -The utility script ``extras/csrf_migration_helper.py`` can help to automate the -finding of code and templates that may need these steps. It contains full help -on how to use it. +The utility script ``extras/csrf_migration_helper.py`` (located in the Django +distribution, but not installed) can help to automate the finding of code and +templates that may need these steps. It contains full help on how to use it. .. _csrf-ajax: diff --git a/docs/ref/contrib/flatpages.txt b/docs/ref/contrib/flatpages.txt index 3de449708f..7ff9165642 100644 --- a/docs/ref/contrib/flatpages.txt +++ b/docs/ref/contrib/flatpages.txt @@ -158,9 +158,7 @@ For more on middleware, read the :doc:`middleware docs :class:`~django.contrib.flatpages.middleware.FlatpageFallbackMiddleware` only steps in once another view has successfully produced a 404 response. If another view or middleware class attempts to produce a 404 but ends up - raising an exception instead (such as a ``TemplateDoesNotExist`` - exception if your site does not have an appropriate template to - use for HTTP 404 responses), the response will become an HTTP 500 + raising an exception instead, the response will become an HTTP 500 ("Internal Server Error") and the :class:`~django.contrib.flatpages.middleware.FlatpageFallbackMiddleware` will not attempt to serve a flat page. @@ -239,8 +237,6 @@ template. Getting a list of :class:`~django.contrib.flatpages.models.FlatPage` objects in your templates ============================================================================================== -.. versionadded:: 1.3 - The flatpages app provides a template tag that allows you to iterate over all of the available flatpages on the :ref:`current site <hooking-into-current-site-from-views>`. diff --git a/docs/ref/contrib/formtools/form-wizard.txt b/docs/ref/contrib/formtools/form-wizard.txt index d5231de3e5..0ced1bf155 100644 --- a/docs/ref/contrib/formtools/form-wizard.txt +++ b/docs/ref/contrib/formtools/form-wizard.txt @@ -226,7 +226,7 @@ Hooking the wizard into a URLconf --------------------------------- Finally, we need to specify which forms to use in the wizard, and then -deploy the new :class:`WizardView` object at an URL in the ``urls.py``. The +deploy the new :class:`WizardView` object at a URL in the ``urls.py``. The wizard's :meth:`as_view` method takes a list of your :class:`~django.forms.Form` classes as an argument during instantiation:: diff --git a/docs/ref/contrib/gis/admin.txt b/docs/ref/contrib/gis/admin.txt index aa6ba58630..d1a9fc1dcb 100644 --- a/docs/ref/contrib/gis/admin.txt +++ b/docs/ref/contrib/gis/admin.txt @@ -45,7 +45,7 @@ GeoDjango's admin site .. attribute:: openlayers_url Link to the URL of the OpenLayers JavaScript. Defaults to - ``'http://openlayers.org/api/2.8/OpenLayers.js'``. + ``'http://openlayers.org/api/2.11/OpenLayers.js'``. .. attribute:: modifiable diff --git a/docs/ref/contrib/gis/db-api.txt b/docs/ref/contrib/gis/db-api.txt index 318110ef04..519f79f0d4 100644 --- a/docs/ref/contrib/gis/db-api.txt +++ b/docs/ref/contrib/gis/db-api.txt @@ -282,7 +282,7 @@ Method PostGIS Oracle SpatiaLite :meth:`GeoQuerySet.extent3d` X :meth:`GeoQuerySet.force_rhr` X :meth:`GeoQuerySet.geohash` X -:meth:`GeoQuerySet.geojson` X +:meth:`GeoQuerySet.geojson` X X :meth:`GeoQuerySet.gml` X X X :meth:`GeoQuerySet.intersection` X X X :meth:`GeoQuerySet.kml` X X diff --git a/docs/ref/contrib/gis/geoip.txt b/docs/ref/contrib/gis/geoip.txt index a30573d860..e37c4c60b0 100644 --- a/docs/ref/contrib/gis/geoip.txt +++ b/docs/ref/contrib/gis/geoip.txt @@ -23,10 +23,10 @@ to the GPL-licensed `Python GeoIP`__ interface provided by MaxMind. In order to perform IP-based geolocation, the :class:`GeoIP` object requires the GeoIP C libary and either the GeoIP `Country`__ or `City`__ datasets in binary format (the CSV files will not work!). These datasets may be -`downloaded from MaxMind`__. Grab the ``GeoIP.dat.gz`` and ``GeoLiteCity.dat.gz`` -and unzip them in a directory corresponding to what you set -:setting:`GEOIP_PATH` with in your settings. See the example and reference below -for more details. +`downloaded from MaxMind`__. Grab the ``GeoLiteCountry/GeoIP.dat.gz`` and +``GeoLiteCity.dat.gz`` files and unzip them in a directory corresponding to what +you set :setting:`GEOIP_PATH` with in your settings. See the example and +reference below for more details. __ http://www.maxmind.com/app/c __ http://www.maxmind.com/app/python diff --git a/docs/ref/contrib/gis/geoquerysets.txt b/docs/ref/contrib/gis/geoquerysets.txt index eeec2e2133..69280dc028 100644 --- a/docs/ref/contrib/gis/geoquerysets.txt +++ b/docs/ref/contrib/gis/geoquerysets.txt @@ -947,7 +947,7 @@ __ http://geohash.org/ .. method:: GeoQuerySet.geojson(**kwargs) -*Availability*: PostGIS +*Availability*: PostGIS, SpatiaLite Attaches a ``geojson`` attribute to every model in the queryset that contains the `GeoJSON`__ representation of the geometry. diff --git a/docs/ref/contrib/gis/geos.txt b/docs/ref/contrib/gis/geos.txt index f4e706d275..eb20b1f411 100644 --- a/docs/ref/contrib/gis/geos.txt +++ b/docs/ref/contrib/gis/geos.txt @@ -163,6 +163,11 @@ WKB / EWKB ``buffer`` GeoJSON ``str`` or ``unicode`` ============= ====================== +.. note:: + + The new 3D/4D WKT notation with an intermediary Z or M (like + ``POINT Z (3, 4, 5)``) is only supported with GEOS 3.3.0 or later. + Properties ~~~~~~~~~~ @@ -232,8 +237,6 @@ Returns a boolean indicating whether the geometry is valid. .. attribute:: GEOSGeometry.valid_reason -.. versionadded:: 1.3 - Returns a string describing the reason why a geometry is invalid. .. attribute:: GEOSGeometry.srid @@ -270,14 +273,18 @@ Essentially the SRID is prepended to the WKT representation, for example .. attribute:: GEOSGeometry.hex Returns the WKB of this Geometry in hexadecimal form. Please note -that the SRID and Z values are not included in this representation +that the SRID value is not included in this representation because it is not a part of the OGC specification (use the :attr:`GEOSGeometry.hexewkb` property instead). +.. versionchanged:: 1.5 + + Prior to Django 1.5, the Z value of the geometry was dropped. + .. attribute:: GEOSGeometry.hexewkb Returns the EWKB of this Geometry in hexadecimal form. This is an -extension of the WKB specification that includes SRID and Z values +extension of the WKB specification that includes the SRID value that are a part of this geometry. .. note:: @@ -316,16 +323,20 @@ correspondg to the GEOS geometry. .. attribute:: GEOSGeometry.wkb Returns the WKB (Well-Known Binary) representation of this Geometry -as a Python buffer. SRID and Z values are not included, use the +as a Python buffer. SRID value is not included, use the :attr:`GEOSGeometry.ewkb` property instead. +.. versionchanged:: 1.5 + + Prior to Django 1.5, the Z value of the geometry was dropped. + .. _ewkb: .. attribute:: GEOSGeometry.ewkb Return the EWKB representation of this Geometry as a Python buffer. This is an extension of the WKB specification that includes any SRID -and Z values that are a part of this geometry. +value that are a part of this geometry. .. note:: @@ -413,11 +424,36 @@ quarter circle (defaults is 8). Returns a :class:`GEOSGeometry` representing the points making up this geometry that do not make up other. +.. method:: GEOSGeometry.interpolate(distance) +.. method:: GEOSGeometry.interpolate_normalized(distance) + +.. versionadded:: 1.5 + +Given a distance (float), returns the point (or closest point) within the +geometry (:class:`LineString` or :class:`MultiLineString`) at that distance. +The normalized version takes the distance as a float between 0 (origin) and 1 +(endpoint). + +Reverse of :meth:`GEOSGeometry.project`. + .. method:: GEOSGeometry:intersection(other) Returns a :class:`GEOSGeometry` representing the points shared by this geometry and other. +.. method:: GEOSGeometry.project(point) +.. method:: GEOSGeometry.project_normalized(point) + +.. versionadded:: 1.5 + +Returns the distance (float) from the origin of the geometry +(:class:`LineString` or :class:`MultiLineString`) to the point projected on the +geometry (that is to a point of the line the closest to the given point). +The normalized version returns the distance as a float between 0 (origin) and 1 +(endpoint). + +Reverse of :meth:`GEOSGeometry.interpolate`. + .. method:: GEOSGeometry.relate(other) Returns the DE-9IM intersection matrix (a string) representing the @@ -530,8 +566,6 @@ corresponding to the SRID of the geometry or ``None``. .. method:: GEOSGeometry.transform(ct, clone=False) -.. versionchanged:: 1.3 - Transforms the geometry according to the given coordinate transformation paramter (``ct``), which may be an integer SRID, spatial reference WKT string, a PROJ.4 string, a :class:`~django.contrib.gis.gdal.SpatialReference` object, or a @@ -796,7 +830,7 @@ Writer Objects All writer objects have a ``write(geom)`` method that returns either the WKB or WKT of the given geometry. In addition, :class:`WKBWriter` objects also have properties that may be used to change the byte order, and or -include the SRID and 3D values (in other words, EWKB). +include the SRID value (in other words, EWKB). .. class:: WKBWriter @@ -858,7 +892,7 @@ so that the Z value is included in the WKB. Outdim Value Description ============ =========================== 2 The default, output 2D WKB. -3 Output 3D EWKB. +3 Output 3D WKB. ============ =========================== Example:: diff --git a/docs/ref/contrib/gis/index.txt b/docs/ref/contrib/gis/index.txt index 1b1e7688d0..6a1402bfab 100644 --- a/docs/ref/contrib/gis/index.txt +++ b/docs/ref/contrib/gis/index.txt @@ -15,7 +15,7 @@ of spatially enabled data. :maxdepth: 2 tutorial - install + install/index model-api db-api geoquerysets diff --git a/docs/ref/contrib/gis/install.txt b/docs/ref/contrib/gis/install.txt deleted file mode 100644 index b815973202..0000000000 --- a/docs/ref/contrib/gis/install.txt +++ /dev/null @@ -1,1267 +0,0 @@ -.. _ref-gis-install: - -====================== -GeoDjango Installation -====================== - -.. highlight:: console - -Overview -======== -In general, GeoDjango installation requires: - -1. :ref:`Python and Django <django>` -2. :ref:`spatial_database` -3. :ref:`geospatial_libs` - -Details for each of the requirements and installation instructions -are provided in the sections below. In addition, platform-specific -instructions are available for: - -* :ref:`macosx` -* :ref:`ubuntudebian` -* :ref:`windows` - -.. admonition:: Use the Source - - Because GeoDjango takes advantage of the latest in the open source geospatial - software technology, recent versions of the libraries are necessary. - If binary packages aren't available for your platform, - :ref:`installation from source <build_from_source>` - may be required. When compiling the libraries from source, please follow the - directions closely, especially if you're a beginner. - -Requirements -============ - -.. _django: - -Python and Django ------------------ - -Because GeoDjango is included with Django, please refer to Django's -:ref:`installation instructions <installing-official-release>` for details on -how to install. - - -.. _spatial_database: - -Spatial database ----------------- -PostgreSQL (with PostGIS), MySQL, Oracle, and SQLite (with SpatiaLite) are -the spatial databases currently supported. - -.. note:: - - PostGIS is recommended, because it is the most mature and feature-rich - open source spatial database. - -The geospatial libraries required for a GeoDjango installation depends -on the spatial database used. The following lists the library requirements, -supported versions, and any notes for each of the supported database backends: - -================== ============================== ================== ========================================= -Database Library Requirements Supported Versions Notes -================== ============================== ================== ========================================= -PostgreSQL GEOS, PROJ.4, PostGIS 8.1+ Requires PostGIS. -MySQL GEOS 5.x Not OGC-compliant; limited functionality. -Oracle GEOS 10.2, 11 XE not supported; not tested with 9. -SQLite GEOS, GDAL, PROJ.4, SpatiaLite 3.6.+ Requires SpatiaLite 2.3+, pysqlite2 2.5+ -================== ============================== ================== ========================================= - -.. _geospatial_libs: - -Geospatial libraries --------------------- -GeoDjango uses and/or provides interfaces for the following open source -geospatial libraries: - -======================== ==================================== ================================ ========================== -Program Description Required Supported Versions -======================== ==================================== ================================ ========================== -:ref:`GEOS <ref-geos>` Geometry Engine Open Source Yes 3.3, 3.2, 3.1, 3.0 -`PROJ.4`_ Cartographic Projections library Yes (PostgreSQL and SQLite only) 4.8, 4.7, 4.6, 4.5, 4.4 -:ref:`GDAL <ref-gdal>` Geospatial Data Abstraction Library No (but, required for SQLite) 1.9, 1.8, 1.7, 1.6, 1.5 -:ref:`GeoIP <ref-geoip>` IP-based geolocation library No 1.4 -`PostGIS`__ Spatial extensions for PostgreSQL Yes (PostgreSQL only) 1.5, 1.4, 1.3 -`SpatiaLite`__ Spatial extensions for SQLite Yes (SQLite only) 3.0, 2.4, 2.3 -======================== ==================================== ================================ ========================== - -.. admonition:: Install GDAL - - While :ref:`gdalbuild` is technically not required, it is *recommended*. - Important features of GeoDjango (including the :ref:`ref-layermapping`, - geometry reprojection, and the geographic admin) depend on its - functionality. - -.. note:: - - The GeoDjango interfaces to GEOS, GDAL, and GeoIP may be used - independently of Django. In other words, no database or settings file - required -- just import them as normal from :mod:`django.contrib.gis`. - -.. _PROJ.4: http://trac.osgeo.org/proj/ -__ http://postgis.refractions.net/ -__ http://www.gaia-gis.it/gaia-sins/ - -.. _build_from_source: - -Building from source -==================== - -When installing from source on UNIX and GNU/Linux systems, please follow -the installation instructions carefully, and install the libraries in the -given order. If using MySQL or Oracle as the spatial database, only GEOS -is required. - -.. note:: - - On Linux platforms, it may be necessary to run the ``ldconfig`` - command after installing each library. For example:: - - $ sudo make install - $ sudo ldconfig - -.. note:: - - OS X users are required to install `Apple Developer Tools`_ in order - to compile software from source. This is typically included on your - OS X installation DVDs. - -.. _Apple Developer Tools: https://developer.apple.com/technologies/tools/ - -.. _geosbuild: - -GEOS ----- - -GEOS is a C++ library for performing geometric operations, and is the default -internal geometry representation used by GeoDjango (it's behind the "lazy" -geometries). Specifically, the C API library is called (e.g., ``libgeos_c.so``) -directly from Python using ctypes. - -First, download GEOS 3.3.5 from the refractions Web site and untar the source -archive:: - - $ wget http://download.osgeo.org/geos/geos-3.3.5.tar.bz2 - $ tar xjf geos-3.3.5.tar.bz2 - -Next, change into the directory where GEOS was unpacked, run the configure -script, compile, and install:: - - $ cd geos-3.3.5 - $ ./configure - $ make - $ sudo make install - $ cd .. - -Troubleshooting -^^^^^^^^^^^^^^^ - -Can't find GEOS library -~~~~~~~~~~~~~~~~~~~~~~~ - -When GeoDjango can't find GEOS, this error is raised: - -.. code-block:: text - - ImportError: Could not find the GEOS library (tried "geos_c"). Try setting GEOS_LIBRARY_PATH in your settings. - -The most common solution is to properly configure your :ref:`libsettings` *or* set -:ref:`geoslibrarypath` in your settings. - -If using a binary package of GEOS (e.g., on Ubuntu), you may need to :ref:`binutils`. - -.. _geoslibrarypath: - -``GEOS_LIBRARY_PATH`` -~~~~~~~~~~~~~~~~~~~~~ - -If your GEOS library is in a non-standard location, or you don't want to -modify the system's library path then the :setting:`GEOS_LIBRARY_PATH` -setting may be added to your Django settings file with the full path to the -GEOS C library. For example: - -.. code-block:: python - - GEOS_LIBRARY_PATH = '/home/bob/local/lib/libgeos_c.so' - -.. note:: - - The setting must be the *full* path to the **C** shared library; in - other words you want to use ``libgeos_c.so``, not ``libgeos.so``. - -See also :ref:`My logs are filled with GEOS-related errors <geos-exceptions-in-logfile>`. - -.. _proj4: - -PROJ.4 ------- - -`PROJ.4`_ is a library for converting geospatial data to different coordinate -reference systems. - -First, download the PROJ.4 source code and datum shifting files [#]_:: - - $ wget http://download.osgeo.org/proj/proj-4.8.0.tar.gz - $ wget http://download.osgeo.org/proj/proj-datumgrid-1.5.tar.gz - -Next, untar the source code archive, and extract the datum shifting files in the -``nad`` subdirectory. This must be done *prior* to configuration:: - - $ tar xzf proj-4.8.0.tar.gz - $ cd proj-4.8.0/nad - $ tar xzf ../../proj-datumgrid-1.5.tar.gz - $ cd .. - -Finally, configure, make and install PROJ.4:: - - $ ./configure - $ make - $ sudo make install - $ cd .. - -.. _postgis: - -PostGIS -------- - -`PostGIS`__ adds geographic object support to PostgreSQL, turning it -into a spatial database. :ref:`geosbuild` and :ref:`proj4` should be -installed prior to building PostGIS. - -.. note:: - - The `psycopg2`_ module is required for use as the database adaptor - when using GeoDjango with PostGIS. - -.. _psycopg2: http://initd.org/psycopg/ - -First download the source archive, and extract:: - - $ wget http://postgis.refractions.net/download/postgis-1.5.5.tar.gz - $ tar xzf postgis-1.5.5.tar.gz - $ cd postgis-1.5.5 - -Next, configure, make and install PostGIS:: - - $ ./configure - -Finally, make and install:: - - $ make - $ sudo make install - $ cd .. - -.. note:: - - GeoDjango does not automatically create a spatial database. Please - consult the section on :ref:`spatialdb_template` for more information. - -__ http://postgis.refractions.net/ - -.. _gdalbuild: - -GDAL ----- - -`GDAL`__ is an excellent open source geospatial library that has support for -reading most vector and raster spatial data formats. Currently, GeoDjango only -supports :ref:`GDAL's vector data <ref-gdal>` capabilities [#]_. -:ref:`geosbuild` and :ref:`proj4` should be installed prior to building GDAL. - -First download the latest GDAL release version and untar the archive:: - - $ wget http://download.osgeo.org/gdal/gdal-1.9.1.tar.gz - $ tar xzf gdal-1.9.1.tar.gz - $ cd gdal-1.9.1 - -Configure, make and install:: - - $ ./configure - $ make # Go get some coffee, this takes a while. - $ sudo make install - $ cd .. - -.. note:: - - Because GeoDjango has it's own Python interface, the preceding instructions - do not build GDAL's own Python bindings. The bindings may be built by - adding the ``--with-python`` flag when running ``configure``. See - `GDAL/OGR In Python`__ for more information on GDAL's bindings. - -If you have any problems, please see the troubleshooting section below for -suggestions and solutions. - -__ http://trac.osgeo.org/gdal/ -__ http://trac.osgeo.org/gdal/wiki/GdalOgrInPython - -.. _gdaltrouble: - -Troubleshooting -^^^^^^^^^^^^^^^ - -Can't find GDAL library -~~~~~~~~~~~~~~~~~~~~~~~ - -When GeoDjango can't find the GDAL library, the ``HAS_GDAL`` flag -will be false: - -.. code-block:: pycon - - >>> from django.contrib.gis import gdal - >>> gdal.HAS_GDAL - False - -The solution is to properly configure your :ref:`libsettings` *or* set -:ref:`gdallibrarypath` in your settings. - -.. _gdallibrarypath: - -``GDAL_LIBRARY_PATH`` -~~~~~~~~~~~~~~~~~~~~~ - -If your GDAL library is in a non-standard location, or you don't want to -modify the system's library path then the :setting:`GDAL_LIBRARY_PATH` -setting may be added to your Django settings file with the full path to -the GDAL library. For example: - -.. code-block:: python - - GDAL_LIBRARY_PATH = '/home/sue/local/lib/libgdal.so' - -.. _gdaldata: - -Can't find GDAL data files (``GDAL_DATA``) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -When installed from source, GDAL versions 1.5.1 and below have an autoconf bug -that places data in the wrong location. [#]_ This can lead to error messages -like this: - -.. code-block:: text - - ERROR 4: Unable to open EPSG support file gcs.csv. - ... - OGRException: OGR failure. - -The solution is to set the ``GDAL_DATA`` environment variable to the location of the -GDAL data files before invoking Python (typically ``/usr/local/share``; use -``gdal-config --datadir`` to find out). For example:: - - $ export GDAL_DATA=`gdal-config --datadir` - $ python manage.py shell - -If using Apache, you may need to add this environment variable to your configuration -file: - -.. code-block:: apache - - SetEnv GDAL_DATA /usr/local/share - -.. _spatialite: - -SpatiaLite ----------- - -.. note:: - - Mac OS X users should follow the instructions in the :ref:`kyngchaos` section, - as it is much easier than building from source. - -`SpatiaLite`__ adds spatial support to SQLite, turning it into a full-featured -spatial database. Because SpatiaLite has special requirements, it typically -requires SQLite and pysqlite2 (the Python SQLite DB-API adaptor) to be built from -source. :ref:`geosbuild` and :ref:`proj4` should be installed prior to building -SpatiaLite. - -After installation is complete, don't forget to read the post-installation -docs on :ref:`create_spatialite_db`. - -__ http://www.gaia-gis.it/gaia-sins/ - -.. _sqlite: - -SQLite -^^^^^^ - -Typically, SQLite packages are not compiled to include the `R*Tree module`__ -- -thus it must be compiled from source. First download the latest amalgamation -source archive from the `SQLite download page`__, and extract:: - - $ wget http://sqlite.org/sqlite-amalgamation-3.6.23.1.tar.gz - $ tar xzf sqlite-amalgamation-3.6.23.1.tar.gz - $ cd sqlite-3.6.23.1 - -Next, run the ``configure`` script -- however the ``CFLAGS`` environment variable -needs to be customized so that SQLite knows to build the R*Tree module:: - - $ CFLAGS="-DSQLITE_ENABLE_RTREE=1" ./configure - $ make - $ sudo make install - $ cd .. - -.. note:: - - If using Ubuntu, installing a newer SQLite from source can be very difficult - because it links to the existing ``libsqlite3.so`` in ``/usr/lib`` which - many other packages depend on. Unfortunately, the best solution at this time - is to overwrite the existing library by adding ``--prefix=/usr`` to the - ``configure`` command. - -__ http://www.sqlite.org/rtree.html -__ http://www.sqlite.org/download.html - -.. _spatialitebuild : - -SpatiaLite library (``libspatialite``) and tools (``spatialite``) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -After SQLite has been built with the R*Tree module enabled, get the latest -SpatiaLite library source and tools bundle from the `download page`__:: - - $ wget http://www.gaia-gis.it/gaia-sins/libspatialite-sources/libspatialite-amalgamation-2.3.1.tar.gz - $ wget http://www.gaia-gis.it/gaia-sins/spatialite-tools-sources/spatialite-tools-2.3.1.tar.gz - $ tar xzf libspatialite-amalgamation-2.3.1.tar.gz - $ tar xzf spatialite-tools-2.3.1.tar.gz - -Prior to attempting to build, please read the important notes below to see if -customization of the ``configure`` command is necessary. If not, then run the -``configure`` script, make, and install for the SpatiaLite library:: - - $ cd libspatialite-amalgamation-2.3.1 - $ ./configure # May need to modified, see notes below. - $ make - $ sudo make install - $ cd .. - -Finally, do the same for the SpatiaLite tools:: - - $ cd spatialite-tools-2.3.1 - $ ./configure # May need to modified, see notes below. - $ make - $ sudo make install - $ cd .. - -.. note:: - - If you've installed GEOS and PROJ.4 from binary packages, you will have to specify - their paths when running the ``configure`` scripts for *both* the library and the - tools (the configure scripts look, by default, in ``/usr/local``). For example, - on Debian/Ubuntu distributions that have GEOS and PROJ.4 packages, the command would be:: - - $ ./configure --with-proj-include=/usr/include --with-proj-lib=/usr/lib --with-geos-include=/usr/include --with-geos-lib=/usr/lib - -.. note:: - - For Mac OS X users building from source, the SpatiaLite library *and* tools - need to have their ``target`` configured:: - - $ ./configure --target=macosx - -__ http://www.gaia-gis.it/gaia-sins/libspatialite-sources/ - -.. _pysqlite2: - -pysqlite2 -^^^^^^^^^ - -Because SpatiaLite must be loaded as an external extension, it requires the -``enable_load_extension`` method, which is only available in versions 2.5+ of -pysqlite2. Thus, download pysqlite2 2.6, and untar:: - - $ wget http://pysqlite.googlecode.com/files/pysqlite-2.6.0.tar.gz - $ tar xzf pysqlite-2.6.0.tar.gz - $ cd pysqlite-2.6.0 - -Next, use a text editor (e.g., ``emacs`` or ``vi``) to edit the ``setup.cfg`` file -to look like the following: - -.. code-block:: ini - - [build_ext] - #define= - include_dirs=/usr/local/include - library_dirs=/usr/local/lib - libraries=sqlite3 - #define=SQLITE_OMIT_LOAD_EXTENSION - -.. note:: - - The important thing here is to make sure you comment out the - ``define=SQLITE_OMIT_LOAD_EXTENSION`` flag and that the ``include_dirs`` - and ``library_dirs`` settings are uncommented and set to the appropriate - path if the SQLite header files and libraries are not in ``/usr/include`` - and ``/usr/lib``, respectively. - -After modifying ``setup.cfg`` appropriately, then run the ``setup.py`` script -to build and install:: - - $ sudo python setup.py install - -Post-installation -================= - -.. _spatialdb_template: - -Creating a spatial database template for PostGIS ------------------------------------------------- - -Creating a spatial database with PostGIS is different than normal because -additional SQL must be loaded to enable spatial functionality. Because of -the steps in this process, it's better to create a database template that -can be reused later. - -First, you need to be able to execute the commands as a privileged database -user. For example, you can use the following to become the ``postgres`` user:: - - $ sudo su - postgres - -.. note:: - - The location *and* name of the PostGIS SQL files (e.g., from - ``POSTGIS_SQL_PATH`` below) depends on the version of PostGIS. - PostGIS versions 1.3 and below use ``<pg_sharedir>/contrib/lwpostgis.sql``; - whereas version 1.4 uses ``<sharedir>/contrib/postgis.sql`` and - version 1.5 uses ``<sharedir>/contrib/postgis-1.5/postgis.sql``. - - To complicate matters, :ref:`ubuntudebian` distributions have their - own separate directory naming system that changes each release. - - The example below assumes PostGIS 1.5, thus you may need to modify - ``POSTGIS_SQL_PATH`` and the name of the SQL file for the specific - version of PostGIS you are using. - -Once you're a database super user, then you may execute the following commands -to create a PostGIS spatial database template:: - - $ POSTGIS_SQL_PATH=`pg_config --sharedir`/contrib/postgis-1.5 - # Creating the template spatial database. - $ createdb -E UTF8 template_postgis - $ createlang -d template_postgis plpgsql # Adding PLPGSQL language support. - # Allows non-superusers the ability to create from this template - $ psql -d postgres -c "UPDATE pg_database SET datistemplate='true' WHERE datname='template_postgis';" - # Loading the PostGIS SQL routines - $ psql -d template_postgis -f $POSTGIS_SQL_PATH/postgis.sql - $ psql -d template_postgis -f $POSTGIS_SQL_PATH/spatial_ref_sys.sql - # Enabling users to alter spatial tables. - $ psql -d template_postgis -c "GRANT ALL ON geometry_columns TO PUBLIC;" - $ psql -d template_postgis -c "GRANT ALL ON geography_columns TO PUBLIC;" - $ psql -d template_postgis -c "GRANT ALL ON spatial_ref_sys TO PUBLIC;" - -These commands may be placed in a shell script for later use; for convenience -the following scripts are available: - -=============== ============================================= -PostGIS version Bash shell script -=============== ============================================= -1.3 :download:`create_template_postgis-1.3.sh` -1.4 :download:`create_template_postgis-1.4.sh` -1.5 :download:`create_template_postgis-1.5.sh` -Debian/Ubuntu :download:`create_template_postgis-debian.sh` -=============== ============================================= - -Afterwards, you may create a spatial database by simply specifying -``template_postgis`` as the template to use (via the ``-T`` option):: - - $ createdb -T template_postgis <db name> - -.. note:: - - While the ``createdb`` command does not require database super-user privileges, - it must be executed by a database user that has permissions to create databases. - You can create such a user with the following command:: - - $ createuser --createdb <user> - -.. _create_spatialite_db: - -Creating a spatial database for SpatiaLite ------------------------------------------- - -After you've installed SpatiaLite, you'll need to create a number of spatial -metadata tables in your database in order to perform spatial queries. - -If you're using SpatiaLite 2.4 or newer, use the ``spatialite`` utility to -call the ``InitSpatialMetaData()`` function, like this:: - - $ spatialite geodjango.db "SELECT InitSpatialMetaData();" - the SPATIAL_REF_SYS table already contains some row(s) - InitSpatiaMetaData ()error:"table spatial_ref_sys already exists" - 0 - -You can safely ignore the error messages shown. When you've done this, you can -skip the rest of this section. - -If you're using SpatiaLite 2.3, you'll need to download a -database-initialization file and execute its SQL queries in your database. - -First, get it from the `SpatiaLite Resources`__ page:: - - $ wget http://www.gaia-gis.it/spatialite-2.3.1/init_spatialite-2.3.sql.gz - $ gunzip init_spatialite-2.3.sql.gz - -Then, use the ``spatialite`` command to initialize a spatial database:: - - $ spatialite geodjango.db < init_spatialite-2.3.sql - -.. note:: - - The parameter ``geodjango.db`` is the *filename* of the SQLite database - you want to use. Use the same in the :setting:`DATABASES` ``"name"`` key - inside your ``settings.py``. - -__ http://www.gaia-gis.it/spatialite-2.3.1/resources.html - -Add ``django.contrib.gis`` to :setting:`INSTALLED_APPS` -------------------------------------------------------- - -Like other Django contrib applications, you will *only* need to add -:mod:`django.contrib.gis` to :setting:`INSTALLED_APPS` in your settings. -This is the so that ``gis`` templates can be located -- if not done, then -features such as the geographic admin or KML sitemaps will not function properly. - -.. _addgoogleprojection: - -Add Google projection to ``spatial_ref_sys`` table --------------------------------------------------- - -.. note:: - - If you're running PostGIS 1.4 or above, you can skip this step. The entry - is already included in the default ``spatial_ref_sys`` table. - -In order to conduct database transformations to the so-called "Google" -projection (a spherical mercator projection used by Google Maps), -an entry must be added to your spatial database's ``spatial_ref_sys`` table. -Invoke the Django shell from your project and execute the -``add_srs_entry`` function: - -.. code-block:: pycon - - $ python manage shell - >>> from django.contrib.gis.utils import add_srs_entry - >>> add_srs_entry(900913) - -This adds an entry for the 900913 SRID to the ``spatial_ref_sys`` (or equivalent) -table, making it possible for the spatial database to transform coordinates in -this projection. You only need to execute this command *once* per spatial database. - -Troubleshooting -=============== - -If you can't find the solution to your problem here then participate in the -community! You can: - -* Join the ``#geodjango`` IRC channel on FreeNode. Please be patient and polite - -- while you may not get an immediate response, someone will attempt to answer - your question as soon as they see it. -* Ask your question on the `GeoDjango`__ mailing list. -* File a ticket on the `Django trac`__ if you think there's a bug. Make - sure to provide a complete description of the problem, versions used, - and specify the component as "GIS". - -__ http://groups.google.com/group/geodjango -__ https://code.djangoproject.com/newticket - -.. _libsettings: - -Library environment settings ----------------------------- - -By far, the most common problem when installing GeoDjango is that the -external shared libraries (e.g., for GEOS and GDAL) cannot be located. [#]_ -Typically, the cause of this problem is that the operating system isn't aware -of the directory where the libraries built from source were installed. - -In general, the library path may be set on a per-user basis by setting -an environment variable, or by configuring the library path for the entire -system. - -``LD_LIBRARY_PATH`` environment variable -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -A user may set this environment variable to customize the library paths -they want to use. The typical library directory for software -built from source is ``/usr/local/lib``. Thus, ``/usr/local/lib`` needs -to be included in the ``LD_LIBRARY_PATH`` variable. For example, the user -could place the following in their bash profile:: - - export LD_LIBRARY_PATH=/usr/local/lib - -Setting system library path -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -On GNU/Linux systems, there is typically a file in ``/etc/ld.so.conf``, which may include -additional paths from files in another directory, such as ``/etc/ld.so.conf.d``. -As the root user, add the custom library path (like ``/usr/local/lib``) on a -new line in ``ld.so.conf``. This is *one* example of how to do so:: - - $ sudo echo /usr/local/lib >> /etc/ld.so.conf - $ sudo ldconfig - -For OpenSolaris users, the system library path may be modified using the -``crle`` utility. Run ``crle`` with no options to see the current configuration -and use ``crle -l`` to set with the new library path. Be *very* careful when -modifying the system library path:: - - # crle -l $OLD_PATH:/usr/local/lib - -.. _binutils: - -Install ``binutils`` -^^^^^^^^^^^^^^^^^^^^ - -GeoDjango uses the ``find_library`` function (from the ``ctypes.util`` Python -module) to discover libraries. The ``find_library`` routine uses a program -called ``objdump`` (part of the ``binutils`` package) to verify a shared -library on GNU/Linux systems. Thus, if ``binutils`` is not installed on your -Linux system then Python's ctypes may not be able to find your library even if -your library path is set correctly and geospatial libraries were built perfectly. - -The ``binutils`` package may be installed on Debian and Ubuntu systems using the -following command:: - - $ sudo apt-get install binutils - -Similarly, on Red Hat and CentOS systems:: - - $ sudo yum install binutils - -Platform-specific instructions -============================== - -.. _macosx: - -Mac OS X --------- - -Because of the variety of packaging systems available for OS X, users have -several different options for installing GeoDjango. These options are: - -* :ref:`homebrew` -* :ref:`kyngchaos` -* :ref:`fink` -* :ref:`macports` -* :ref:`build_from_source` - -.. note:: - - Currently, the easiest and recommended approach for installing GeoDjango - on OS X is to use the KyngChaos packages. - -This section also includes instructions for installing an upgraded version -of :ref:`macosx_python` from packages provided by the Python Software -Foundation, however, this is not required. - -.. _macosx_python: - -Python -^^^^^^ - -Although OS X comes with Python installed, users can use framework -installers (`2.6`__ and `2.7`__ are available) provided by -the Python Software Foundation. An advantage to using the installer is -that OS X's Python will remain "pristine" for internal operating system -use. - -__ http://python.org/ftp/python/2.6.6/python-2.6.6-macosx10.3.dmg -__ http://python.org/ftp/python/2.7.3/ - -.. note:: - - You will need to modify the ``PATH`` environment variable in your - ``.profile`` file so that the new version of Python is used when - ``python`` is entered at the command-line:: - - export PATH=/Library/Frameworks/Python.framework/Versions/Current/bin:$PATH - -.. _homebrew: - -Homebrew -^^^^^^^^ - -`Homebrew`__ provides "recipes" for building binaries and packages from source. -It provides recipes for the GeoDjango prerequisites on Macintosh computers -running OS X. Because Homebrew still builds the software from source, the -`Apple Developer Tools`_ are required. - -Summary:: - - $ brew install postgresql - $ brew install postgis - $ brew install gdal - $ brew install libgeoip - -__ http://mxcl.github.com/homebrew/ - -.. _kyngchaos: - -KyngChaos packages -^^^^^^^^^^^^^^^^^^ - -William Kyngesburye provides a number of `geospatial library binary packages`__ -that make it simple to get GeoDjango installed on OS X without compiling -them from source. However, the `Apple Developer Tools`_ are still necessary -for compiling the Python database adapters :ref:`psycopg2_kyngchaos` (for PostGIS) -and :ref:`pysqlite2_kyngchaos` (for SpatiaLite). - -.. note:: - - SpatiaLite users should consult the :ref:`spatialite_kyngchaos` section - after installing the packages for additional instructions. - -Download the framework packages for: - -* UnixImageIO -* PROJ -* GEOS -* SQLite3 (includes the SpatiaLite library) -* GDAL - -Install the packages in the order they are listed above, as the GDAL and SQLite -packages require the packages listed before them. - -Afterwards, you can also install the KyngChaos binary packages for `PostgreSQL -and PostGIS`__. - -After installing the binary packages, you'll want to add the following to -your ``.profile`` to be able to run the package programs from the command-line:: - - export PATH=/Library/Frameworks/UnixImageIO.framework/Programs:$PATH - export PATH=/Library/Frameworks/PROJ.framework/Programs:$PATH - export PATH=/Library/Frameworks/GEOS.framework/Programs:$PATH - export PATH=/Library/Frameworks/SQLite3.framework/Programs:$PATH - export PATH=/Library/Frameworks/GDAL.framework/Programs:$PATH - export PATH=/usr/local/pgsql/bin:$PATH - -__ http://www.kyngchaos.com/software/frameworks -__ http://www.kyngchaos.com/software/postgres - -.. _psycopg2_kyngchaos: - -psycopg2 -~~~~~~~~ - -After you've installed the KyngChaos binaries and modified your ``PATH``, as -described above, ``psycopg2`` may be installed using the following command:: - - $ sudo pip install psycopg2 - -.. note:: - - If you don't have ``pip``, follow the the :ref:`installation instructions - <installing-official-release>` to install it. - -.. _pysqlite2_kyngchaos: - -pysqlite2 -~~~~~~~~~ - -Follow the :ref:`pysqlite2` source install instructions, however, -when editing the ``setup.cfg`` use the following instead: - -.. code-block:: ini - - [build_ext] - #define= - include_dirs=/Library/Frameworks/SQLite3.framework/unix/include - library_dirs=/Library/Frameworks/SQLite3.framework/unix/lib - libraries=sqlite3 - #define=SQLITE_OMIT_LOAD_EXTENSION - -.. _spatialite_kyngchaos: - -SpatiaLite -~~~~~~~~~~ - -When :ref:`create_spatialite_db`, the ``spatialite`` program is required. -However, instead of attempting to compile the SpatiaLite tools from source, -download the `SpatiaLite Binaries`__ for OS X, and install ``spatialite`` in a -location available in your ``PATH``. For example:: - - $ curl -O http://www.gaia-gis.it/spatialite/spatialite-tools-osx-x86-2.3.1.tar.gz - $ tar xzf spatialite-tools-osx-x86-2.3.1.tar.gz - $ cd spatialite-tools-osx-x86-2.3.1/bin - $ sudo cp spatialite /Library/Frameworks/SQLite3.framework/Programs - -Finally, for GeoDjango to be able to find the KyngChaos SpatiaLite library, -add the following to your ``settings.py``: - -.. code-block:: python - - SPATIALITE_LIBRARY_PATH='/Library/Frameworks/SQLite3.framework/SQLite3' - -__ http://www.gaia-gis.it/spatialite-2.3.1/binaries.html - -.. _fink: - -Fink -^^^^ - -`Kurt Schwehr`__ has been gracious enough to create GeoDjango packages for users -of the `Fink`__ package system. The following packages are available, depending -on which version of Python you want to use: - -* ``django-gis-py26`` -* ``django-gis-py25`` -* ``django-gis-py24`` - -__ http://schwehr.org/blog/ -__ http://www.finkproject.org/ - -.. _macports: - -MacPorts -^^^^^^^^ - -`MacPorts`__ may be used to install GeoDjango prerequisites on Macintosh -computers running OS X. Because MacPorts still builds the software from source, -the `Apple Developer Tools`_ are required. - -Summary:: - - $ sudo port install postgresql83-server - $ sudo port install geos - $ sudo port install proj - $ sudo port install postgis - $ sudo port install gdal +geos - $ sudo port install libgeoip - -.. note:: - - You will also have to modify the ``PATH`` in your ``.profile`` so - that the MacPorts programs are accessible from the command-line:: - - export PATH=/opt/local/bin:/opt/local/lib/postgresql83/bin - - In addition, add the ``DYLD_FALLBACK_LIBRARY_PATH`` setting so that - the libraries can be found by Python:: - - export DYLD_FALLBACK_LIBRARY_PATH=/opt/local/lib:/opt/local/lib/postgresql83 - -__ http://www.macports.org/ - -.. _ubuntudebian: - -Ubuntu & Debian GNU/Linux -------------------------- - -.. note:: - - The PostGIS SQL files are not placed in the PostgreSQL share directory in - the Debian and Ubuntu packages. Instead, they're located in a special - directory depending on the release. In this case, use the - :download:`create_template_postgis-debian.sh` script - -.. _ubuntu: - -Ubuntu -^^^^^^ - -11.10 through 12.04 -~~~~~~~~~~~~~~~~~~~ - -In Ubuntu 11.10, PostgreSQL was upgraded to 9.1. The installation command is: - -.. code-block:: bash - - $ sudo apt-get install binutils gdal-bin libproj-dev \ - postgresql-9.1-postgis postgresql-server-dev-9.1 python-psycopg2 - -.. _ubuntu10: - -10.04 through 11.04 -~~~~~~~~~~~~~~~~~~~ - -In Ubuntu 10.04, PostgreSQL was upgraded to 8.4 and GDAL was upgraded to 1.6. -Ubuntu 10.04 uses PostGIS 1.4, while Ubuntu 10.10 uses PostGIS 1.5 (with -geography support). The installation command is: - -.. code-block:: bash - - $ sudo apt-get install binutils gdal-bin libproj-dev postgresql-8.4-postgis \ - postgresql-server-dev-8.4 python-psycopg2 - -.. _ibex: - -8.10 -~~~~ - -Use the synaptic package manager to install the following packages: - -.. code-block:: bash - - $ sudo apt-get install binutils gdal-bin postgresql-8.3-postgis \ - postgresql-server-dev-8.3 python-psycopg2 - -That's it! For the curious, the required binary prerequisites packages are: - -* ``binutils``: for ctypes to find libraries -* ``postgresql-8.3`` -* ``postgresql-server-dev-8.3``: for ``pg_config`` -* ``postgresql-8.3-postgis``: for PostGIS 1.3.3 -* ``libgeos-3.0.0``, and ``libgeos-c1``: for GEOS 3.0.0 -* ``libgdal1-1.5.0``: for GDAL 1.5.0 library -* ``proj``: for PROJ 4.6.0 -- but no datum shifting files, see note below -* ``python-psycopg2`` - -Optional packages to consider: - -* ``libgeoip1``: for :ref:`GeoIP <ref-geoip>` support -* ``gdal-bin``: for GDAL command line programs like ``ogr2ogr`` -* ``python-gdal`` for GDAL's own Python bindings -- includes interfaces for raster manipulation - -.. note:: - - On this version of Ubuntu the ``proj`` package does not come with the - datum shifting files installed, which will cause problems with the - geographic admin because the ``null`` datum grid is not available for - transforming geometries to the spherical mercator projection. A solution - is to download the datum-shifting files, create the grid file, and - install it yourself: - - .. code-block:: bash - - $ wget http://download.osgeo.org/proj/proj-datumgrid-1.4.tar.gz - $ mkdir nad - $ cd nad - $ tar xzf ../proj-datumgrid-1.4.tar.gz - $ nad2bin null < null.lla - $ sudo cp null /usr/share/proj - - Otherwise, the Ubuntu ``proj`` package is fine for general use as long as you - do not plan on doing any database transformation of geometries to the - Google projection (900913). - -.. _debian: - -Debian ------- - -.. _lenny: - -5.0 (Lenny) -^^^^^^^^^^^ - -This version is comparable to Ubuntu :ref:`ibex`, so the command -is very similar: - -.. code-block:: bash - - $ sudo apt-get install binutils libgdal1-1.5.0 postgresql-8.3 \ - postgresql-8.3-postgis postgresql-server-dev-8.3 \ - python-psycopg2 python-setuptools - -This assumes that you are using PostgreSQL version 8.3. Else, replace ``8.3`` -in the above command with the appropriate PostgreSQL version. - -.. note:: - - Please read the note in the Ubuntu :ref:`ibex` install documentation - about the ``proj`` package -- it also applies here because the package does - not include the datum shifting files. - -.. _post_install: - -Post-installation notes -~~~~~~~~~~~~~~~~~~~~~~~ - -If the PostgreSQL database cluster was not initiated after installing, then it -can be created (and started) with the following command: - -.. code-block:: bash - - $ sudo pg_createcluster --start 8.3 main - -Afterwards, the ``/etc/init.d/postgresql-8.3`` script should be used to manage -the starting and stopping of PostgreSQL. - -In addition, the SQL files for PostGIS are placed in a different location on -Debian 5.0 . Thus when :ref:`spatialdb_template` either: - -* Create a symbolic link to these files: - - .. code-block:: bash - - $ sudo ln -s /usr/share/postgresql-8.3-postgis/{lwpostgis,spatial_ref_sys}.sql \ - /usr/share/postgresql/8.3 - - If not running PostgreSQL 8.3, then replace ``8.3`` in the command above with - the correct version. - -* Or use the :download:`create_template_postgis-debian.sh` to create the spatial database. - -.. _windows: - -Windows -------- - -Proceed through the following sections sequentially in order to install -GeoDjango on Windows. - -.. note:: - - These instructions assume that you are using 32-bit versions of - all programs. While 64-bit versions of Python and PostgreSQL 9.0 - are available, 64-bit versions of spatial libraries, like - GEOS and GDAL, are not yet provided by the :ref:`OSGeo4W` installer. - -Python -^^^^^^ - -First, download the latest `Python 2.7 installer`__ from the Python Web site. -Next, run the installer and keep the defaults -- for example, keep -'Install for all users' checked and the installation path set as -``C:\Python27``. - -.. note:: - - You may already have a version of Python installed in ``C:\python`` as ESRI - products sometimes install a copy there. *You should still install a - fresh version of Python 2.7.* - -__ http://python.org/download/ - -PostgreSQL -^^^^^^^^^^ - -First, download the latest `PostgreSQL 9.0 installer`__ from the -`EnterpriseDB`__ Web site. After downloading, simply run the installer, -follow the on-screen directions, and keep the default options unless -you know the consequences of changing them. - -.. note:: - - The PostgreSQL installer creates both a new Windows user to be the - 'postgres service account' and a ``postgres`` database superuser - You will be prompted once to set the password for both accounts -- - make sure to remember it! - -When the installer completes, it will ask to launch the Application Stack -Builder (ASB) on exit -- keep this checked, as it is necessary to -install :ref:`postgisasb`. - -.. note:: - - If installed successfully, the PostgreSQL server will run in the - background each time the system as started as a Windows service. - A :menuselection:`PostgreSQL 9.0` start menu group will created - and contains shortcuts for the ASB as well as the 'SQL Shell', - which will launch a ``psql`` command window. - -__ http://www.enterprisedb.com/products-services-training/pgdownload -__ http://www.enterprisedb.com - -.. _postgisasb: - -PostGIS -^^^^^^^ - -From within the Application Stack Builder (to run outside of the installer, -:menuselection:`Start --> Programs --> PostgreSQL 9.0`), select -:menuselection:`PostgreSQL Database Server 9.0 on port 5432` from the drop down -menu. Next, expand the :menuselection:`Categories --> Spatial Extensions` menu -tree and select :menuselection:`PostGIS 1.5 for PostgreSQL 9.0`. - -After clicking next, you will be prompted to select your mirror, PostGIS -will be downloaded, and the PostGIS installer will begin. Select only the -default options during install (e.g., do not uncheck the option to create a -default PostGIS database). - -.. note:: - - You will be prompted to enter your ``postgres`` database superuser - password in the 'Database Connection Information' dialog. - -psycopg2 -^^^^^^^^ - -The ``psycopg2`` Python module provides the interface between Python and the -PostgreSQL database. Download the latest `Windows installer`__ for your version -of Python and PostgreSQL and run using the default settings. [#]_ - -__ http://www.stickpeople.com/projects/python/win-psycopg/ - -.. _osgeo4w: - -OSGeo4W -^^^^^^^ - -The `OSGeo4W installer`_ makes it simple to install the PROJ.4, GDAL, and GEOS -libraries required by GeoDjango. First, download the `OSGeo4W installer`_, -and run it. Select :menuselection:`Express Web-GIS Install` and click next. -In the 'Select Packages' list, ensure that GDAL is selected; MapServer and -Apache are also enabled by default, but are not required by GeoDjango and -may be unchecked safely. After clicking next, the packages will be -automatically downloaded and installed, after which you may exit the -installer. - -.. _OSGeo4W installer: http://trac.osgeo.org/osgeo4w/ - -Modify Windows environment -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -In order to use GeoDjango, you will need to add your Python and OSGeo4W -directories to your Windows system ``Path``, as well as create ``GDAL_DATA`` -and ``PROJ_LIB`` environment variables. The following set of commands, -executable with ``cmd.exe``, will set this up: - -.. code-block:: bat - - set OSGEO4W_ROOT=C:\OSGeo4W - set PYTHON_ROOT=C:\Python27 - set GDAL_DATA=%OSGEO4W_ROOT%\share\gdal - set PROJ_LIB=%OSGEO4W_ROOT%\share\proj - set PATH=%PATH%;%PYTHON_ROOT%;%OSGEO4W_ROOT%\bin - reg ADD "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v Path /t REG_EXPAND_SZ /f /d "%PATH%" - reg ADD "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v GDAL_DATA /t REG_EXPAND_SZ /f /d "%GDAL_DATA%" - reg ADD "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v PROJ_LIB /t REG_EXPAND_SZ /f /d "%PROJ_LIB%" - -For your convenience, these commands are available in the executable batch -script, :download:`geodjango_setup.bat`. - -.. note:: - - Administrator privileges are required to execute these commands. - To do this, right-click on :download:`geodjango_setup.bat` and select - :menuselection:`Run as administrator`. You need to log out and log back in again - for the settings to take effect. - -.. note:: - - If you customized the Python or OSGeo4W installation directories, - then you will need to modify the ``OSGEO4W_ROOT`` and/or ``PYTHON_ROOT`` - variables accordingly. - -Install Django and set up database -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Finally, :ref:`install Django <installing-official-release>` on your system. -You do not need to create a spatial database template, as one named -``template_postgis`` is created for you when installing PostGIS. - -To administer the database, you can either use the pgAdmin III program -(:menuselection:`Start --> PostgreSQL 9.0 --> pgAdmin III`) or the -SQL Shell (:menuselection:`Start --> PostgreSQL 9.0 --> SQL Shell`). -For example, to create a ``geodjango`` spatial database and user, the following -may be executed from the SQL Shell as the ``postgres`` user:: - - postgres# CREATE USER geodjango PASSWORD 'my_passwd'; - postgres# CREATE DATABASE geodjango OWNER geodjango TEMPLATE template_postgis ENCODING 'utf8'; - -.. rubric:: Footnotes -.. [#] The datum shifting files are needed for converting data to and from - certain projections. - For example, the PROJ.4 string for the `Google projection (900913 or 3857) - <http://spatialreference.org/ref/sr-org/6864/prj/>`_ requires the - ``null`` grid file only included in the extra datum shifting files. - It is easier to install the shifting files now, then to have debug a - problem caused by their absence later. -.. [#] Specifically, GeoDjango provides support for the `OGR - <http://gdal.org/ogr>`_ library, a component of GDAL. -.. [#] See `GDAL ticket #2382 <http://trac.osgeo.org/gdal/ticket/2382>`_. -.. [#] GeoDjango uses the :func:`~ctypes.util.find_library` routine from - :mod:`ctypes.util` to locate shared libraries. -.. [#] The ``psycopg2`` Windows installers are packaged and maintained by - `Jason Erickson <http://www.stickpeople.com/projects/python/win-psycopg/>`_. diff --git a/docs/ref/contrib/gis/create_template_postgis-1.3.sh b/docs/ref/contrib/gis/install/create_template_postgis-1.3.sh index c9ab4fcebf..c9ab4fcebf 100755 --- a/docs/ref/contrib/gis/create_template_postgis-1.3.sh +++ b/docs/ref/contrib/gis/install/create_template_postgis-1.3.sh diff --git a/docs/ref/contrib/gis/create_template_postgis-1.4.sh b/docs/ref/contrib/gis/install/create_template_postgis-1.4.sh index 57a1373f96..57a1373f96 100755 --- a/docs/ref/contrib/gis/create_template_postgis-1.4.sh +++ b/docs/ref/contrib/gis/install/create_template_postgis-1.4.sh diff --git a/docs/ref/contrib/gis/create_template_postgis-1.5.sh b/docs/ref/contrib/gis/install/create_template_postgis-1.5.sh index 081b5f2656..081b5f2656 100755 --- a/docs/ref/contrib/gis/create_template_postgis-1.5.sh +++ b/docs/ref/contrib/gis/install/create_template_postgis-1.5.sh diff --git a/docs/ref/contrib/gis/create_template_postgis-debian.sh b/docs/ref/contrib/gis/install/create_template_postgis-debian.sh index 3e621837fa..3e621837fa 100755 --- a/docs/ref/contrib/gis/create_template_postgis-debian.sh +++ b/docs/ref/contrib/gis/install/create_template_postgis-debian.sh diff --git a/docs/ref/contrib/gis/geodjango_setup.bat b/docs/ref/contrib/gis/install/geodjango_setup.bat index b3e6cc6822..b3e6cc6822 100644 --- a/docs/ref/contrib/gis/geodjango_setup.bat +++ b/docs/ref/contrib/gis/install/geodjango_setup.bat diff --git a/docs/ref/contrib/gis/install/geolibs.txt b/docs/ref/contrib/gis/install/geolibs.txt new file mode 100644 index 0000000000..c78f0c0e62 --- /dev/null +++ b/docs/ref/contrib/gis/install/geolibs.txt @@ -0,0 +1,282 @@ +.. _geospatial_libs: + +=============================== +Installing Geospatial libraries +=============================== + +GeoDjango uses and/or provides interfaces for the following open source +geospatial libraries: + +======================== ==================================== ================================ ========================== +Program Description Required Supported Versions +======================== ==================================== ================================ ========================== +:ref:`GEOS <ref-geos>` Geometry Engine Open Source Yes 3.3, 3.2, 3.1, 3.0 +`PROJ.4`_ Cartographic Projections library Yes (PostgreSQL and SQLite only) 4.8, 4.7, 4.6, 4.5, 4.4 +:ref:`GDAL <ref-gdal>` Geospatial Data Abstraction Library No (but, required for SQLite) 1.9, 1.8, 1.7, 1.6, 1.5 +:ref:`GeoIP <ref-geoip>` IP-based geolocation library No 1.4 +`PostGIS`__ Spatial extensions for PostgreSQL Yes (PostgreSQL only) 2.0, 1.5, 1.4, 1.3 +`SpatiaLite`__ Spatial extensions for SQLite Yes (SQLite only) 3.0, 2.4, 2.3 +======================== ==================================== ================================ ========================== + +.. admonition:: Install GDAL + + While :ref:`gdalbuild` is technically not required, it is *recommended*. + Important features of GeoDjango (including the :ref:`ref-layermapping`, + geometry reprojection, and the geographic admin) depend on its + functionality. + +.. note:: + + The GeoDjango interfaces to GEOS, GDAL, and GeoIP may be used + independently of Django. In other words, no database or settings file + required -- just import them as normal from :mod:`django.contrib.gis`. + +.. _PROJ.4: http://trac.osgeo.org/proj/ +__ http://postgis.refractions.net/ +__ http://www.gaia-gis.it/gaia-sins/ + + +On Debian/Ubuntu, you are advised to install the following packages which will +install, directly or by dependency, the required geospatial libraries: + +.. code-block:: bash + + $ sudo apt-get install binutils libproj-dev gdal-bin + +Optional packages to consider: + +* ``libgeoip1``: for :ref:`GeoIP <ref-geoip>` support +* ``gdal-bin``: for GDAL command line programs like ``ogr2ogr`` +* ``python-gdal`` for GDAL's own Python bindings -- includes interfaces for raster manipulation + +Please also consult platform-specific instructions if you are on :ref:`macosx` +or :ref:`windows`. + +.. _build_from_source: + +Building from source +==================== + +When installing from source on UNIX and GNU/Linux systems, please follow +the installation instructions carefully, and install the libraries in the +given order. If using MySQL or Oracle as the spatial database, only GEOS +is required. + +.. note:: + + On Linux platforms, it may be necessary to run the ``ldconfig`` + command after installing each library. For example:: + + $ sudo make install + $ sudo ldconfig + +.. note:: + + OS X users are required to install `Apple Developer Tools`_ in order + to compile software from source. This is typically included on your + OS X installation DVDs. + +.. _Apple Developer Tools: https://developer.apple.com/technologies/tools/ + +.. _geosbuild: + +GEOS +---- + +GEOS is a C++ library for performing geometric operations, and is the default +internal geometry representation used by GeoDjango (it's behind the "lazy" +geometries). Specifically, the C API library is called (e.g., ``libgeos_c.so``) +directly from Python using ctypes. + +First, download GEOS 3.3.5 from the refractions Web site and untar the source +archive:: + + $ wget http://download.osgeo.org/geos/geos-3.3.5.tar.bz2 + $ tar xjf geos-3.3.5.tar.bz2 + +Next, change into the directory where GEOS was unpacked, run the configure +script, compile, and install:: + + $ cd geos-3.3.5 + $ ./configure + $ make + $ sudo make install + $ cd .. + +Troubleshooting +^^^^^^^^^^^^^^^ + +Can't find GEOS library +~~~~~~~~~~~~~~~~~~~~~~~ + +When GeoDjango can't find GEOS, this error is raised: + +.. code-block:: text + + ImportError: Could not find the GEOS library (tried "geos_c"). Try setting GEOS_LIBRARY_PATH in your settings. + +The most common solution is to properly configure your :ref:`libsettings` *or* set +:ref:`geoslibrarypath` in your settings. + +If using a binary package of GEOS (e.g., on Ubuntu), you may need to :ref:`binutils`. + +.. _geoslibrarypath: + +``GEOS_LIBRARY_PATH`` +~~~~~~~~~~~~~~~~~~~~~ + +If your GEOS library is in a non-standard location, or you don't want to +modify the system's library path then the :setting:`GEOS_LIBRARY_PATH` +setting may be added to your Django settings file with the full path to the +GEOS C library. For example: + +.. code-block:: python + + GEOS_LIBRARY_PATH = '/home/bob/local/lib/libgeos_c.so' + +.. note:: + + The setting must be the *full* path to the **C** shared library; in + other words you want to use ``libgeos_c.so``, not ``libgeos.so``. + +See also :ref:`My logs are filled with GEOS-related errors <geos-exceptions-in-logfile>`. + +.. _proj4: + +PROJ.4 +------ + +`PROJ.4`_ is a library for converting geospatial data to different coordinate +reference systems. + +First, download the PROJ.4 source code and datum shifting files [#]_:: + + $ wget http://download.osgeo.org/proj/proj-4.8.0.tar.gz + $ wget http://download.osgeo.org/proj/proj-datumgrid-1.5.tar.gz + +Next, untar the source code archive, and extract the datum shifting files in the +``nad`` subdirectory. This must be done *prior* to configuration:: + + $ tar xzf proj-4.8.0.tar.gz + $ cd proj-4.8.0/nad + $ tar xzf ../../proj-datumgrid-1.5.tar.gz + $ cd .. + +Finally, configure, make and install PROJ.4:: + + $ ./configure + $ make + $ sudo make install + $ cd .. + +.. _gdalbuild: + +GDAL +---- + +`GDAL`__ is an excellent open source geospatial library that has support for +reading most vector and raster spatial data formats. Currently, GeoDjango only +supports :ref:`GDAL's vector data <ref-gdal>` capabilities [#]_. +:ref:`geosbuild` and :ref:`proj4` should be installed prior to building GDAL. + +First download the latest GDAL release version and untar the archive:: + + $ wget http://download.osgeo.org/gdal/gdal-1.9.1.tar.gz + $ tar xzf gdal-1.9.1.tar.gz + $ cd gdal-1.9.1 + +Configure, make and install:: + + $ ./configure + $ make # Go get some coffee, this takes a while. + $ sudo make install + $ cd .. + +.. note:: + + Because GeoDjango has it's own Python interface, the preceding instructions + do not build GDAL's own Python bindings. The bindings may be built by + adding the ``--with-python`` flag when running ``configure``. See + `GDAL/OGR In Python`__ for more information on GDAL's bindings. + +If you have any problems, please see the troubleshooting section below for +suggestions and solutions. + +__ http://trac.osgeo.org/gdal/ +__ http://trac.osgeo.org/gdal/wiki/GdalOgrInPython + +.. _gdaltrouble: + +Troubleshooting +^^^^^^^^^^^^^^^ + +Can't find GDAL library +~~~~~~~~~~~~~~~~~~~~~~~ + +When GeoDjango can't find the GDAL library, the ``HAS_GDAL`` flag +will be false: + +.. code-block:: pycon + + >>> from django.contrib.gis import gdal + >>> gdal.HAS_GDAL + False + +The solution is to properly configure your :ref:`libsettings` *or* set +:ref:`gdallibrarypath` in your settings. + +.. _gdallibrarypath: + +``GDAL_LIBRARY_PATH`` +~~~~~~~~~~~~~~~~~~~~~ + +If your GDAL library is in a non-standard location, or you don't want to +modify the system's library path then the :setting:`GDAL_LIBRARY_PATH` +setting may be added to your Django settings file with the full path to +the GDAL library. For example: + +.. code-block:: python + + GDAL_LIBRARY_PATH = '/home/sue/local/lib/libgdal.so' + +.. _gdaldata: + +Can't find GDAL data files (``GDAL_DATA``) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When installed from source, GDAL versions 1.5.1 and below have an autoconf bug +that places data in the wrong location. [#]_ This can lead to error messages +like this: + +.. code-block:: text + + ERROR 4: Unable to open EPSG support file gcs.csv. + ... + OGRException: OGR failure. + +The solution is to set the ``GDAL_DATA`` environment variable to the location of the +GDAL data files before invoking Python (typically ``/usr/local/share``; use +``gdal-config --datadir`` to find out). For example:: + + $ export GDAL_DATA=`gdal-config --datadir` + $ python manage.py shell + +If using Apache, you may need to add this environment variable to your configuration +file: + +.. code-block:: apache + + SetEnv GDAL_DATA /usr/local/share + +.. rubric:: Footnotes +.. [#] The datum shifting files are needed for converting data to and from + certain projections. + For example, the PROJ.4 string for the `Google projection (900913 or 3857) + <http://spatialreference.org/ref/sr-org/6864/prj/>`_ requires the + ``null`` grid file only included in the extra datum shifting files. + It is easier to install the shifting files now, then to have debug a + problem caused by their absence later. +.. [#] Specifically, GeoDjango provides support for the `OGR + <http://gdal.org/ogr>`_ library, a component of GDAL. +.. [#] See `GDAL ticket #2382 <http://trac.osgeo.org/gdal/ticket/2382>`_. + diff --git a/docs/ref/contrib/gis/install/index.txt b/docs/ref/contrib/gis/install/index.txt new file mode 100644 index 0000000000..c710866813 --- /dev/null +++ b/docs/ref/contrib/gis/install/index.txt @@ -0,0 +1,535 @@ +.. _ref-gis-install: + +====================== +GeoDjango Installation +====================== + +.. highlight:: console + +Overview +======== +In general, GeoDjango installation requires: + +1. :ref:`Python and Django <django>` +2. :ref:`spatial_database` +3. :ref:`geospatial_libs` + +Details for each of the requirements and installation instructions +are provided in the sections below. In addition, platform-specific +instructions are available for: + +* :ref:`macosx` +* :ref:`windows` + +.. admonition:: Use the Source + + Because GeoDjango takes advantage of the latest in the open source geospatial + software technology, recent versions of the libraries are necessary. + If binary packages aren't available for your platform, installation from + source may be required. When compiling the libraries from source, please + follow the directions closely, especially if you're a beginner. + +Requirements +============ + +.. _django: + +Python and Django +----------------- + +Because GeoDjango is included with Django, please refer to Django's +:ref:`installation instructions <installing-official-release>` for details on +how to install. + + +.. _spatial_database: + +Spatial database +---------------- +PostgreSQL (with PostGIS), MySQL, Oracle, and SQLite (with SpatiaLite) are +the spatial databases currently supported. + +.. note:: + + PostGIS is recommended, because it is the most mature and feature-rich + open source spatial database. + +The geospatial libraries required for a GeoDjango installation depends +on the spatial database used. The following lists the library requirements, +supported versions, and any notes for each of the supported database backends: + +================== ============================== ================== ========================================= +Database Library Requirements Supported Versions Notes +================== ============================== ================== ========================================= +PostgreSQL GEOS, PROJ.4, PostGIS 8.2+ Requires PostGIS. +MySQL GEOS 5.x Not OGC-compliant; limited functionality. +Oracle GEOS 10.2, 11 XE not supported; not tested with 9. +SQLite GEOS, GDAL, PROJ.4, SpatiaLite 3.6.+ Requires SpatiaLite 2.3+, pysqlite2 2.5+ +================== ============================== ================== ========================================= + +See also `this comparison matrix`__ on the OSGeo Wiki for +PostgreSQL/PostGIS/GEOS/GDAL possible combinations. + +__ http://trac.osgeo.org/postgis/wiki/UsersWikiPostgreSQLPostGIS + +Installation +============ + +Geospatial libraries +-------------------- + +.. toctree:: + :maxdepth: 1 + + geolibs + +Database installation +--------------------- + +.. toctree:: + :maxdepth: 1 + + postgis + spatialite + +Add ``django.contrib.gis`` to :setting:`INSTALLED_APPS` +------------------------------------------------------- + +Like other Django contrib applications, you will *only* need to add +:mod:`django.contrib.gis` to :setting:`INSTALLED_APPS` in your settings. +This is the so that ``gis`` templates can be located -- if not done, then +features such as the geographic admin or KML sitemaps will not function properly. + +.. _addgoogleprojection: + +Add Google projection to ``spatial_ref_sys`` table +-------------------------------------------------- + +.. note:: + + If you're running PostGIS 1.4 or above, you can skip this step. The entry + is already included in the default ``spatial_ref_sys`` table. + +In order to conduct database transformations to the so-called "Google" +projection (a spherical mercator projection used by Google Maps), +an entry must be added to your spatial database's ``spatial_ref_sys`` table. +Invoke the Django shell from your project and execute the +``add_srs_entry`` function: + +.. code-block:: pycon + + $ python manage shell + >>> from django.contrib.gis.utils import add_srs_entry + >>> add_srs_entry(900913) + +This adds an entry for the 900913 SRID to the ``spatial_ref_sys`` (or equivalent) +table, making it possible for the spatial database to transform coordinates in +this projection. You only need to execute this command *once* per spatial database. + +Troubleshooting +=============== + +If you can't find the solution to your problem here then participate in the +community! You can: + +* Join the ``#geodjango`` IRC channel on FreeNode. Please be patient and polite + -- while you may not get an immediate response, someone will attempt to answer + your question as soon as they see it. +* Ask your question on the `GeoDjango`__ mailing list. +* File a ticket on the `Django trac`__ if you think there's a bug. Make + sure to provide a complete description of the problem, versions used, + and specify the component as "GIS". + +__ http://groups.google.com/group/geodjango +__ https://code.djangoproject.com/newticket + +.. _libsettings: + +Library environment settings +---------------------------- + +By far, the most common problem when installing GeoDjango is that the +external shared libraries (e.g., for GEOS and GDAL) cannot be located. [#]_ +Typically, the cause of this problem is that the operating system isn't aware +of the directory where the libraries built from source were installed. + +In general, the library path may be set on a per-user basis by setting +an environment variable, or by configuring the library path for the entire +system. + +``LD_LIBRARY_PATH`` environment variable +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A user may set this environment variable to customize the library paths +they want to use. The typical library directory for software +built from source is ``/usr/local/lib``. Thus, ``/usr/local/lib`` needs +to be included in the ``LD_LIBRARY_PATH`` variable. For example, the user +could place the following in their bash profile:: + + export LD_LIBRARY_PATH=/usr/local/lib + +Setting system library path +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +On GNU/Linux systems, there is typically a file in ``/etc/ld.so.conf``, which may include +additional paths from files in another directory, such as ``/etc/ld.so.conf.d``. +As the root user, add the custom library path (like ``/usr/local/lib``) on a +new line in ``ld.so.conf``. This is *one* example of how to do so:: + + $ sudo echo /usr/local/lib >> /etc/ld.so.conf + $ sudo ldconfig + +For OpenSolaris users, the system library path may be modified using the +``crle`` utility. Run ``crle`` with no options to see the current configuration +and use ``crle -l`` to set with the new library path. Be *very* careful when +modifying the system library path:: + + # crle -l $OLD_PATH:/usr/local/lib + +.. _binutils: + +Install ``binutils`` +^^^^^^^^^^^^^^^^^^^^ + +GeoDjango uses the ``find_library`` function (from the ``ctypes.util`` Python +module) to discover libraries. The ``find_library`` routine uses a program +called ``objdump`` (part of the ``binutils`` package) to verify a shared +library on GNU/Linux systems. Thus, if ``binutils`` is not installed on your +Linux system then Python's ctypes may not be able to find your library even if +your library path is set correctly and geospatial libraries were built perfectly. + +The ``binutils`` package may be installed on Debian and Ubuntu systems using the +following command:: + + $ sudo apt-get install binutils + +Similarly, on Red Hat and CentOS systems:: + + $ sudo yum install binutils + +Platform-specific instructions +============================== + +.. _macosx: + +Mac OS X +-------- + +Because of the variety of packaging systems available for OS X, users have +several different options for installing GeoDjango. These options are: + +* :ref:`homebrew` +* :ref:`kyngchaos` +* :ref:`fink` +* :ref:`macports` +* :ref:`build_from_source` + +.. note:: + + Currently, the easiest and recommended approach for installing GeoDjango + on OS X is to use the KyngChaos packages. + +This section also includes instructions for installing an upgraded version +of :ref:`macosx_python` from packages provided by the Python Software +Foundation, however, this is not required. + +.. _macosx_python: + +Python +^^^^^^ + +Although OS X comes with Python installed, users can use framework +installers (`2.6`__ and `2.7`__ are available) provided by +the Python Software Foundation. An advantage to using the installer is +that OS X's Python will remain "pristine" for internal operating system +use. + +__ http://python.org/ftp/python/2.6.6/python-2.6.6-macosx10.3.dmg +__ http://python.org/ftp/python/2.7.3/ + +.. note:: + + You will need to modify the ``PATH`` environment variable in your + ``.profile`` file so that the new version of Python is used when + ``python`` is entered at the command-line:: + + export PATH=/Library/Frameworks/Python.framework/Versions/Current/bin:$PATH + +.. _homebrew: + +Homebrew +^^^^^^^^ + +`Homebrew`__ provides "recipes" for building binaries and packages from source. +It provides recipes for the GeoDjango prerequisites on Macintosh computers +running OS X. Because Homebrew still builds the software from source, the +`Apple Developer Tools`_ are required. + +Summary:: + + $ brew install postgresql + $ brew install postgis + $ brew install gdal + $ brew install libgeoip + +__ http://mxcl.github.com/homebrew/ +.. _Apple Developer Tools: https://developer.apple.com/technologies/tools/ + +.. _kyngchaos: + +KyngChaos packages +^^^^^^^^^^^^^^^^^^ + +William Kyngesburye provides a number of `geospatial library binary packages`__ +that make it simple to get GeoDjango installed on OS X without compiling +them from source. However, the `Apple Developer Tools`_ are still necessary +for compiling the Python database adapters :ref:`psycopg2_kyngchaos` (for PostGIS) +and :ref:`pysqlite2` (for SpatiaLite). + +.. note:: + + SpatiaLite users should consult the :ref:`spatialite_macosx` section + after installing the packages for additional instructions. + +Download the framework packages for: + +* UnixImageIO +* PROJ +* GEOS +* SQLite3 (includes the SpatiaLite library) +* GDAL + +Install the packages in the order they are listed above, as the GDAL and SQLite +packages require the packages listed before them. + +Afterwards, you can also install the KyngChaos binary packages for `PostgreSQL +and PostGIS`__. + +After installing the binary packages, you'll want to add the following to +your ``.profile`` to be able to run the package programs from the command-line:: + + export PATH=/Library/Frameworks/UnixImageIO.framework/Programs:$PATH + export PATH=/Library/Frameworks/PROJ.framework/Programs:$PATH + export PATH=/Library/Frameworks/GEOS.framework/Programs:$PATH + export PATH=/Library/Frameworks/SQLite3.framework/Programs:$PATH + export PATH=/Library/Frameworks/GDAL.framework/Programs:$PATH + export PATH=/usr/local/pgsql/bin:$PATH + +__ http://www.kyngchaos.com/software/frameworks +__ http://www.kyngchaos.com/software/postgres + +.. _psycopg2_kyngchaos: + +psycopg2 +~~~~~~~~ + +After you've installed the KyngChaos binaries and modified your ``PATH``, as +described above, ``psycopg2`` may be installed using the following command:: + + $ sudo pip install psycopg2 + +.. note:: + + If you don't have ``pip``, follow the the :ref:`installation instructions + <installing-official-release>` to install it. + +.. _fink: + +Fink +^^^^ + +`Kurt Schwehr`__ has been gracious enough to create GeoDjango packages for users +of the `Fink`__ package system. The following packages are available, depending +on which version of Python you want to use: + +* ``django-gis-py26`` +* ``django-gis-py25`` +* ``django-gis-py24`` + +__ http://schwehr.org/blog/ +__ http://www.finkproject.org/ + +.. _macports: + +MacPorts +^^^^^^^^ + +`MacPorts`__ may be used to install GeoDjango prerequisites on Macintosh +computers running OS X. Because MacPorts still builds the software from source, +the `Apple Developer Tools`_ are required. + +Summary:: + + $ sudo port install postgresql83-server + $ sudo port install geos + $ sudo port install proj + $ sudo port install postgis + $ sudo port install gdal +geos + $ sudo port install libgeoip + +.. note:: + + You will also have to modify the ``PATH`` in your ``.profile`` so + that the MacPorts programs are accessible from the command-line:: + + export PATH=/opt/local/bin:/opt/local/lib/postgresql83/bin + + In addition, add the ``DYLD_FALLBACK_LIBRARY_PATH`` setting so that + the libraries can be found by Python:: + + export DYLD_FALLBACK_LIBRARY_PATH=/opt/local/lib:/opt/local/lib/postgresql83 + +__ http://www.macports.org/ + +.. _windows: + +Windows +------- + +Proceed through the following sections sequentially in order to install +GeoDjango on Windows. + +.. note:: + + These instructions assume that you are using 32-bit versions of + all programs. While 64-bit versions of Python and PostgreSQL 9.0 + are available, 64-bit versions of spatial libraries, like + GEOS and GDAL, are not yet provided by the :ref:`OSGeo4W` installer. + +Python +^^^^^^ + +First, download the latest `Python 2.7 installer`__ from the Python Web site. +Next, run the installer and keep the defaults -- for example, keep +'Install for all users' checked and the installation path set as +``C:\Python27``. + +.. note:: + + You may already have a version of Python installed in ``C:\python`` as ESRI + products sometimes install a copy there. *You should still install a + fresh version of Python 2.7.* + +__ http://python.org/download/ + +PostgreSQL +^^^^^^^^^^ + +First, download the latest `PostgreSQL 9.0 installer`__ from the +`EnterpriseDB`__ Web site. After downloading, simply run the installer, +follow the on-screen directions, and keep the default options unless +you know the consequences of changing them. + +.. note:: + + The PostgreSQL installer creates both a new Windows user to be the + 'postgres service account' and a ``postgres`` database superuser + You will be prompted once to set the password for both accounts -- + make sure to remember it! + +When the installer completes, it will ask to launch the Application Stack +Builder (ASB) on exit -- keep this checked, as it is necessary to +install :ref:`postgisasb`. + +.. note:: + + If installed successfully, the PostgreSQL server will run in the + background each time the system as started as a Windows service. + A :menuselection:`PostgreSQL 9.0` start menu group will created + and contains shortcuts for the ASB as well as the 'SQL Shell', + which will launch a ``psql`` command window. + +__ http://www.enterprisedb.com/products-services-training/pgdownload +__ http://www.enterprisedb.com + +.. _postgisasb: + +PostGIS +^^^^^^^ + +From within the Application Stack Builder (to run outside of the installer, +:menuselection:`Start --> Programs --> PostgreSQL 9.0`), select +:menuselection:`PostgreSQL Database Server 9.0 on port 5432` from the drop down +menu. Next, expand the :menuselection:`Categories --> Spatial Extensions` menu +tree and select :menuselection:`PostGIS 1.5 for PostgreSQL 9.0`. + +After clicking next, you will be prompted to select your mirror, PostGIS +will be downloaded, and the PostGIS installer will begin. Select only the +default options during install (e.g., do not uncheck the option to create a +default PostGIS database). + +.. note:: + + You will be prompted to enter your ``postgres`` database superuser + password in the 'Database Connection Information' dialog. + +psycopg2 +^^^^^^^^ + +The ``psycopg2`` Python module provides the interface between Python and the +PostgreSQL database. Download the latest `Windows installer`__ for your version +of Python and PostgreSQL and run using the default settings. [#]_ + +__ http://www.stickpeople.com/projects/python/win-psycopg/ + +.. _osgeo4w: + +OSGeo4W +^^^^^^^ + +The `OSGeo4W installer`_ makes it simple to install the PROJ.4, GDAL, and GEOS +libraries required by GeoDjango. First, download the `OSGeo4W installer`_, +and run it. Select :menuselection:`Express Web-GIS Install` and click next. +In the 'Select Packages' list, ensure that GDAL is selected; MapServer and +Apache are also enabled by default, but are not required by GeoDjango and +may be unchecked safely. After clicking next, the packages will be +automatically downloaded and installed, after which you may exit the +installer. + +.. _OSGeo4W installer: http://trac.osgeo.org/osgeo4w/ + +Modify Windows environment +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In order to use GeoDjango, you will need to add your Python and OSGeo4W +directories to your Windows system ``Path``, as well as create ``GDAL_DATA`` +and ``PROJ_LIB`` environment variables. The following set of commands, +executable with ``cmd.exe``, will set this up: + +.. code-block:: bat + + set OSGEO4W_ROOT=C:\OSGeo4W + set PYTHON_ROOT=C:\Python27 + set GDAL_DATA=%OSGEO4W_ROOT%\share\gdal + set PROJ_LIB=%OSGEO4W_ROOT%\share\proj + set PATH=%PATH%;%PYTHON_ROOT%;%OSGEO4W_ROOT%\bin + reg ADD "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v Path /t REG_EXPAND_SZ /f /d "%PATH%" + reg ADD "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v GDAL_DATA /t REG_EXPAND_SZ /f /d "%GDAL_DATA%" + reg ADD "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v PROJ_LIB /t REG_EXPAND_SZ /f /d "%PROJ_LIB%" + +For your convenience, these commands are available in the executable batch +script, :download:`geodjango_setup.bat`. + +.. note:: + + Administrator privileges are required to execute these commands. + To do this, right-click on :download:`geodjango_setup.bat` and select + :menuselection:`Run as administrator`. You need to log out and log back in again + for the settings to take effect. + +.. note:: + + If you customized the Python or OSGeo4W installation directories, + then you will need to modify the ``OSGEO4W_ROOT`` and/or ``PYTHON_ROOT`` + variables accordingly. + +Install Django and set up database +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Finally, :ref:`install Django <installing-official-release>` on your system. + +.. rubric:: Footnotes +.. [#] GeoDjango uses the :func:`~ctypes.util.find_library` routine from + :mod:`ctypes.util` to locate shared libraries. +.. [#] The ``psycopg2`` Windows installers are packaged and maintained by + `Jason Erickson <http://www.stickpeople.com/projects/python/win-psycopg/>`_. diff --git a/docs/ref/contrib/gis/install/postgis.txt b/docs/ref/contrib/gis/install/postgis.txt new file mode 100644 index 0000000000..6d7fe88203 --- /dev/null +++ b/docs/ref/contrib/gis/install/postgis.txt @@ -0,0 +1,175 @@ +.. _postgis: + +================== +Installing PostGIS +================== + +`PostGIS`__ adds geographic object support to PostgreSQL, turning it +into a spatial database. :ref:`geosbuild`, :ref:`proj4` and +:ref:`gdalbuild` should be installed prior to building PostGIS. You +might also need additional libraries, see `PostGIS requirements`_. + +.. note:: + + The `psycopg2`_ module is required for use as the database adaptor + when using GeoDjango with PostGIS. + +.. _psycopg2: http://initd.org/psycopg/ +.. _PostGIS requirements: http://www.postgis.org/documentation/manual-2.0/postgis_installation.html#id2711662 + +On Debian/Ubuntu, you are advised to install the following packages: +postgresql-x.x, postgresql-x.x-postgis, postgresql-server-dev-x.x, +python-psycopg2 (x.x matching the PostgreSQL version you want to install). +Please also consult platform-specific instructions if you are on :ref:`macosx` +or :ref:`windows`. + +Building from source +==================== + +First download the source archive, and extract:: + + $ wget http://postgis.refractions.net/download/postgis-2.0.1.tar.gz + $ tar xzf postgis-2.0.1.tar.gz + $ cd postgis-2.0.1 + +Next, configure, make and install PostGIS:: + + $ ./configure + +Finally, make and install:: + + $ make + $ sudo make install + $ cd .. + +.. note:: + + GeoDjango does not automatically create a spatial database. Please consult + the section on :ref:`spatialdb_template91` or + :ref:`spatialdb_template_earlier` for more information. + +__ http://postgis.refractions.net/ + +Post-installation +================= + +.. _spatialdb_template: +.. _spatialdb_template91: + +Creating a spatial database with PostGIS 2.0 and PostgreSQL 9.1 +--------------------------------------------------------------- + +PostGIS 2 includes an extension for Postgres 9.1 that can be used to enable +spatial functionality:: + + $ createdb <db name> + $ psql <db name> + > CREATE EXTENSION postgis; + > CREATE EXTENSION postgis_topology; + +No PostGIS topology functionalities are yet available from GeoDjango, so the +creation of the ``postgis_topology`` extension is entirely optional. + +.. _spatialdb_template_earlier: + +Creating a spatial database template for earlier versions +--------------------------------------------------------- + +If you have an earlier version of PostGIS or PostgreSQL, the CREATE +EXTENSION isn't available and you need to create the spatial database +using the following instructions. + +Creating a spatial database with PostGIS is different than normal because +additional SQL must be loaded to enable spatial functionality. Because of +the steps in this process, it's better to create a database template that +can be reused later. + +First, you need to be able to execute the commands as a privileged database +user. For example, you can use the following to become the ``postgres`` user:: + + $ sudo su - postgres + +.. note:: + + The location *and* name of the PostGIS SQL files (e.g., from + ``POSTGIS_SQL_PATH`` below) depends on the version of PostGIS. + PostGIS versions 1.3 and below use ``<pg_sharedir>/contrib/lwpostgis.sql``; + whereas version 1.4 uses ``<sharedir>/contrib/postgis.sql`` and + version 1.5 uses ``<sharedir>/contrib/postgis-1.5/postgis.sql``. + + To complicate matters, Debian/Ubuntu distributions have their own separate + directory naming system that might change with time. In this case, use the + :download:`create_template_postgis-debian.sh` script. + + The example below assumes PostGIS 1.5, thus you may need to modify + ``POSTGIS_SQL_PATH`` and the name of the SQL file for the specific + version of PostGIS you are using. + +Once you're a database super user, then you may execute the following commands +to create a PostGIS spatial database template:: + + $ POSTGIS_SQL_PATH=`pg_config --sharedir`/contrib/postgis-2.0 + # Creating the template spatial database. + $ createdb -E UTF8 template_postgis + $ createlang -d template_postgis plpgsql # Adding PLPGSQL language support. + # Allows non-superusers the ability to create from this template + $ psql -d postgres -c "UPDATE pg_database SET datistemplate='true' WHERE datname='template_postgis';" + # Loading the PostGIS SQL routines + $ psql -d template_postgis -f $POSTGIS_SQL_PATH/postgis.sql + $ psql -d template_postgis -f $POSTGIS_SQL_PATH/spatial_ref_sys.sql + # Enabling users to alter spatial tables. + $ psql -d template_postgis -c "GRANT ALL ON geometry_columns TO PUBLIC;" + $ psql -d template_postgis -c "GRANT ALL ON geography_columns TO PUBLIC;" + $ psql -d template_postgis -c "GRANT ALL ON spatial_ref_sys TO PUBLIC;" + +These commands may be placed in a shell script for later use; for convenience +the following scripts are available: + +=============== ============================================= +PostGIS version Bash shell script +=============== ============================================= +1.3 :download:`create_template_postgis-1.3.sh` +1.4 :download:`create_template_postgis-1.4.sh` +1.5 :download:`create_template_postgis-1.5.sh` +Debian/Ubuntu :download:`create_template_postgis-debian.sh` +=============== ============================================= + +Afterwards, you may create a spatial database by simply specifying +``template_postgis`` as the template to use (via the ``-T`` option):: + + $ createdb -T template_postgis <db name> + +.. note:: + + While the ``createdb`` command does not require database super-user privileges, + it must be executed by a database user that has permissions to create databases. + You can create such a user with the following command:: + + $ createuser --createdb <user> + +PostgreSQL's createdb fails +--------------------------- + +When the PostgreSQL cluster uses a non-UTF8 encoding, the +:file:`create_template_postgis-*.sh` script will fail when executing +``createdb``:: + + createdb: database creation failed: ERROR: new encoding (UTF8) is incompatible + with the encoding of the template database (SQL_ASCII) + +The `current workaround`__ is to re-create the cluster using UTF8 (back up any +databases before dropping the cluster). + +__ http://jacobian.org/writing/pg-encoding-ubuntu/ + +Managing the database +--------------------- + +To administer the database, you can either use the pgAdmin III program +(:menuselection:`Start --> PostgreSQL 9.0 --> pgAdmin III`) or the +SQL Shell (:menuselection:`Start --> PostgreSQL 9.0 --> SQL Shell`). +For example, to create a ``geodjango`` spatial database and user, the following +may be executed from the SQL Shell as the ``postgres`` user:: + + postgres# CREATE USER geodjango PASSWORD 'my_passwd'; + postgres# CREATE DATABASE geodjango OWNER geodjango TEMPLATE template_postgis ENCODING 'utf8'; diff --git a/docs/ref/contrib/gis/install/spatialite.txt b/docs/ref/contrib/gis/install/spatialite.txt new file mode 100644 index 0000000000..941d559272 --- /dev/null +++ b/docs/ref/contrib/gis/install/spatialite.txt @@ -0,0 +1,222 @@ +.. _spatialite: + +===================== +Installing Spatialite +===================== + +`SpatiaLite`__ adds spatial support to SQLite, turning it into a full-featured +spatial database. + +Check first if you can install Spatialite from system packages or binaries. For +example, on Debian-based distributions, try to install the ``spatialite-bin`` +package. For Mac OS X, follow the +:ref:`specific instructions below<spatialite_macosx>`. For Windows, you may +find binaries on `Gaia-SINS`__ home page. In any case, you should always +be able to :ref:`install from source<spatialite_source>`. + +When you are done with the installation process, skip to :ref:`create_spatialite_db`. + +__ https://www.gaia-gis.it/fossil/libspatialite +__ http://www.gaia-gis.it/gaia-sins/ + +.. _spatialite_source: + +Installing from source +~~~~~~~~~~~~~~~~~~~~~~ + +:ref:`GEOS and PROJ.4<geospatial_libs>` should be installed prior to building +SpatiaLite. + +SQLite +^^^^^^ + +Check first if SQLite is compiled with the `R*Tree module`__. Run the sqlite3 +command line interface and enter the following query:: + + sqlite> CREATE VIRTUAL TABLE testrtree USING rtree(id,minX,maxX,minY,maxY); + +If you obtain an error, you will have to recompile SQLite from source. Otherwise, +just skip this section. + +To install from sources, download the latest amalgamation source archive from +the `SQLite download page`__, and extract:: + + $ wget http://sqlite.org/sqlite-amalgamation-3.6.23.1.tar.gz + $ tar xzf sqlite-amalgamation-3.6.23.1.tar.gz + $ cd sqlite-3.6.23.1 + +Next, run the ``configure`` script -- however the ``CFLAGS`` environment variable +needs to be customized so that SQLite knows to build the R*Tree module:: + + $ CFLAGS="-DSQLITE_ENABLE_RTREE=1" ./configure + $ make + $ sudo make install + $ cd .. + +__ http://www.sqlite.org/rtree.html +__ http://www.sqlite.org/download.html + +.. _spatialitebuild : + +SpatiaLite library (``libspatialite``) and tools (``spatialite``) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Get the latest SpatiaLite library source and tools bundle from the +`download page`__:: + + $ wget http://www.gaia-gis.it/gaia-sins/libspatialite-sources/libspatialite-amalgamation-2.4.0-5.tar.gz + $ wget http://www.gaia-gis.it/gaia-sins/spatialite-tools-sources/spatialite-tools-2.4.0-5.tar.gz + $ tar xzf libspatialite-amalgamation-2.4.0-5.tar.gz + $ tar xzf spatialite-tools-2.4.0-5.tar.gz + +Prior to attempting to build, please read the important notes below to see if +customization of the ``configure`` command is necessary. If not, then run the +``configure`` script, make, and install for the SpatiaLite library:: + + $ cd libspatialite-amalgamation-2.3.1 + $ ./configure # May need to modified, see notes below. + $ make + $ sudo make install + $ cd .... _spatialite + +Finally, do the same for the SpatiaLite tools:: + + $ cd spatialite-tools-2.3.1 + $ ./configure # May need to modified, see notes below. + $ make + $ sudo make install + $ cd .. + +.. note:: + + If you've installed GEOS and PROJ.4 from binary packages, you will have to specify + their paths when running the ``configure`` scripts for *both* the library and the + tools (the configure scripts look, by default, in ``/usr/local``). For example, + on Debian/Ubuntu distributions that have GEOS and PROJ.4 packages, the command would be:: + + $ ./configure --with-proj-include=/usr/include --with-proj-lib=/usr/lib --with-geos-include=/usr/include --with-geos-lib=/usr/lib + +.. note:: + + For Mac OS X users building from source, the SpatiaLite library *and* tools + need to have their ``target`` configured:: + + $ ./configure --target=macosx + +__ http://www.gaia-gis.it/gaia-sins/libspatialite-sources/ + +.. _pysqlite2: + +pysqlite2 +^^^^^^^^^ + +If you are on Python 2.6, you will also have to compile pysqlite2, because +``SpatiaLite`` must be loaded as an external extension, and the required +``enable_load_extension`` method is only available in versions 2.5+ of +pysqlite2. Thus, download pysqlite2 2.6, and untar:: + + $ wget http://pysqlite.googlecode.com/files/pysqlite-2.6.3.tar.gz + $ tar xzf pysqlite-2.6.3.tar.gz + $ cd pysqlite-2.6.3 + +Next, use a text editor (e.g., ``emacs`` or ``vi``) to edit the ``setup.cfg`` file +to look like the following: + +.. code-block:: ini + + [build_ext] + #define= + include_dirs=/usr/local/include + library_dirs=/usr/local/lib + libraries=sqlite3 + #define=SQLITE_OMIT_LOAD_EXTENSION + +or if you are on Mac OS X: + +.. code-block:: ini + + [build_ext] + #define= + include_dirs=/Library/Frameworks/SQLite3.framework/unix/include + library_dirs=/Library/Frameworks/SQLite3.framework/unix/lib + libraries=sqlite3 + #define=SQLITE_OMIT_LOAD_EXTENSION + +.. note:: + + The important thing here is to make sure you comment out the + ``define=SQLITE_OMIT_LOAD_EXTENSION`` flag and that the ``include_dirs`` + and ``library_dirs`` settings are uncommented and set to the appropriate + path if the SQLite header files and libraries are not in ``/usr/include`` + and ``/usr/lib``, respectively. + +After modifying ``setup.cfg`` appropriately, then run the ``setup.py`` script +to build and install:: + + $ sudo python setup.py install + +.. _spatialite_macosx: + +Mac OS X-specific instructions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Mac OS X users should follow the instructions in the :ref:`kyngchaos` section, +as it is much easier than building from source. + +When :ref:`create_spatialite_db`, the ``spatialite`` program is required. +However, instead of attempting to compile the SpatiaLite tools from source, +download the `SpatiaLite Binaries`__ for OS X, and install ``spatialite`` in a +location available in your ``PATH``. For example:: + + $ curl -O http://www.gaia-gis.it/spatialite/spatialite-tools-osx-x86-2.3.1.tar.gz + $ tar xzf spatialite-tools-osx-x86-2.3.1.tar.gz + $ cd spatialite-tools-osx-x86-2.3.1/bin + $ sudo cp spatialite /Library/Frameworks/SQLite3.framework/Programs + +Finally, for GeoDjango to be able to find the KyngChaos SpatiaLite library, +add the following to your ``settings.py``: + +.. code-block:: python + + SPATIALITE_LIBRARY_PATH='/Library/Frameworks/SQLite3.framework/SQLite3' + +__ http://www.gaia-gis.it/spatialite-2.3.1/binaries.html + +.. _create_spatialite_db: + +Creating a spatial database for SpatiaLite +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +After you've installed SpatiaLite, you'll need to create a number of spatial +metadata tables in your database in order to perform spatial queries. + +If you're using SpatiaLite 2.4 or newer, use the ``spatialite`` utility to +call the ``InitSpatialMetaData()`` function, like this:: + + $ spatialite geodjango.db "SELECT InitSpatialMetaData();" + the SPATIAL_REF_SYS table already contains some row(s) + InitSpatiaMetaData ()error:"table spatial_ref_sys already exists" + 0 + +You can safely ignore the error messages shown. When you've done this, you can +skip the rest of this section. + +If you're using SpatiaLite 2.3, you'll need to download a +database-initialization file and execute its SQL queries in your database. + +First, get it from the `SpatiaLite Resources`__ page:: + + $ wget http://www.gaia-gis.it/spatialite-2.3.1/init_spatialite-2.3.sql.gz + $ gunzip init_spatialite-2.3.sql.gz + +Then, use the ``spatialite`` command to initialize a spatial database:: + + $ spatialite geodjango.db < init_spatialite-2.3.sql + +.. note:: + + The parameter ``geodjango.db`` is the *filename* of the SQLite database + you want to use. Use the same in the :setting:`DATABASES` ``"name"`` key + inside your ``settings.py``. + +__ http://www.gaia-gis.it/spatialite-2.3.1/resources.html diff --git a/docs/ref/contrib/gis/testing.txt b/docs/ref/contrib/gis/testing.txt index d12c884a1b..86979f0308 100644 --- a/docs/ref/contrib/gis/testing.txt +++ b/docs/ref/contrib/gis/testing.txt @@ -134,8 +134,6 @@ your settings:: GeoDjango tests =============== -.. versionchanged:: 1.3 - GeoDjango's test suite may be run in one of two ways, either by itself or with the rest of :ref:`Django's unit tests <running-unit-tests>`. diff --git a/docs/ref/contrib/localflavor.txt b/docs/ref/contrib/localflavor.txt index 4595f51d9e..9bb27e6e74 100644 --- a/docs/ref/contrib/localflavor.txt +++ b/docs/ref/contrib/localflavor.txt @@ -6,1403 +6,143 @@ The "local flavor" add-ons :synopsis: A collection of various Django snippets that are useful only for a particular country or culture. -Following its "batteries included" philosophy, Django comes with assorted -pieces of code that are useful for particular countries or cultures. These are -called the "local flavor" add-ons and live in the -:mod:`django.contrib.localflavor` package. +Historically, Django has shipped with ``django.contrib.localflavor`` -- +assorted pieces of code that are useful for particular countries or cultures. +Starting with Django 1.5, we've started the process of moving the code to +outside packages (i.e., packages distributed separately from Django), for +easier maintenance and to trim the size of Django's codebase. -Inside that package, country- or culture-specific code is organized into -subpackages, named using `ISO 3166 country codes`_. +The localflavor packages are named ``django-localflavor-*``, where the asterisk +is an `ISO 3166 country code`_. For example: ``django-localflavor-us`` is the +localflavor package for the U.S.A. -Most of the ``localflavor`` add-ons are localized form components deriving -from the :doc:`forms </topics/forms/index>` framework -- for example, a -:class:`~django.contrib.localflavor.us.forms.USStateField` that knows how to -validate U.S. state abbreviations, and a -:class:`~django.contrib.localflavor.fi.forms.FISocialSecurityNumber` that -knows how to validate Finnish social security numbers. +Most of these ``localflavor`` add-ons are country-specific fields for the +:doc:`forms </topics/forms/index>` framework -- for example, a +``USStateField`` that knows how to validate U.S. state abbreviations and a +``FISocialSecurityNumber`` that knows how to validate Finnish social security +numbers. To use one of these localized components, just import the relevant subpackage. For example, here's how you can create a form with a field representing a French telephone number:: from django import forms - from django.contrib.localflavor.fr.forms import FRPhoneNumberField + from django_localflavor_fr.forms import FRPhoneNumberField class MyForm(forms.Form): my_french_phone_no = FRPhoneNumberField() -Supported countries -=================== - -Countries currently supported by :mod:`~django.contrib.localflavor` are: - -* Argentina_ -* Australia_ -* Austria_ -* Belgium_ -* Brazil_ -* Canada_ -* Chile_ -* China_ -* Colombia_ -* Croatia_ -* Czech_ -* Ecuador_ -* Finland_ -* France_ -* Germany_ -* `Hong Kong`_ -* Iceland_ -* India_ -* Indonesia_ -* Ireland_ -* Israel_ -* Italy_ -* Japan_ -* Kuwait_ -* Macedonia_ -* Mexico_ -* `The Netherlands`_ -* Norway_ -* Peru_ -* Poland_ -* Portugal_ -* Paraguay_ -* Romania_ -* Russia_ -* Slovakia_ -* Slovenia_ -* `South Africa`_ -* Spain_ -* Sweden_ -* Switzerland_ -* Turkey_ -* `United Kingdom`_ -* `United States of America`_ -* Uruguay_ - -The ``django.contrib.localflavor`` package also includes a ``generic`` subpackage, -containing useful code that is not specific to one particular country or culture. -Currently, it defines date, datetime and split datetime input fields based on -those from :doc:`forms </topics/forms/index>`, but with non-US default formats. -Here's an example of how to use them:: - - from django import forms - from django.contrib.localflavor import generic - - class MyForm(forms.Form): - my_date_field = generic.forms.DateField() - -.. _ISO 3166 country codes: http://www.iso.org/iso/country_codes.htm -.. _Argentina: `Argentina (ar)`_ -.. _Australia: `Australia (au)`_ -.. _Austria: `Austria (at)`_ -.. _Belgium: `Belgium (be)`_ -.. _Brazil: `Brazil (br)`_ -.. _Canada: `Canada (ca)`_ -.. _Chile: `Chile (cl)`_ -.. _China: `China (cn)`_ -.. _Colombia: `Colombia (co)`_ -.. _Croatia: `Croatia (hr)`_ -.. _Czech: `Czech (cz)`_ -.. _Ecuador: `Ecuador (ec)`_ -.. _Finland: `Finland (fi)`_ -.. _France: `France (fr)`_ -.. _Germany: `Germany (de)`_ -.. _Hong Kong: `Hong Kong (hk)`_ -.. _The Netherlands: `The Netherlands (nl)`_ -.. _Iceland: `Iceland (is\_)`_ -.. _India: `India (in\_)`_ -.. _Indonesia: `Indonesia (id)`_ -.. _Ireland: `Ireland (ie)`_ -.. _Israel: `Israel (il)`_ -.. _Italy: `Italy (it)`_ -.. _Japan: `Japan (jp)`_ -.. _Kuwait: `Kuwait (kw)`_ -.. _Macedonia: `Macedonia (mk)`_ -.. _Mexico: `Mexico (mx)`_ -.. _Norway: `Norway (no)`_ -.. _Paraguay: `Paraguay (py)`_ -.. _Peru: `Peru (pe)`_ -.. _Poland: `Poland (pl)`_ -.. _Portugal: `Portugal (pt)`_ -.. _Romania: `Romania (ro)`_ -.. _Russia: `Russia (ru)`_ -.. _Slovakia: `Slovakia (sk)`_ -.. _Slovenia: `Slovenia (si)`_ -.. _South Africa: `South Africa (za)`_ -.. _Spain: `Spain (es)`_ -.. _Sweden: `Sweden (se)`_ -.. _Switzerland: `Switzerland (ch)`_ -.. _Turkey: `Turkey (tr)`_ -.. _United Kingdom: `United Kingdom (gb)`_ -.. _United States of America: `United States of America (us)`_ -.. _Uruguay: `Uruguay (uy)`_ - -Internationalization of localflavor -=================================== - -Localflavor has its own catalog of translations, in the directory -``django/contrib/localflavor/locale``, and it's not loaded automatically like -Django's general catalog in ``django/conf/locale``. If you want localflavor's -texts to be translated, like form fields error messages, you must include -:mod:`django.contrib.localflavor` in the :setting:`INSTALLED_APPS` setting, so -the internationalization system can find the catalog, as explained in -:ref:`how-django-discovers-translations`. - -Adding flavors -============== - -We'd love to add more of these to Django, so please `create a ticket`_ with -any code you'd like to contribute. One thing we ask is that you please use -Unicode objects (``u'mystring'``) for strings, rather than setting the encoding -in the file. See any of the existing flavors for examples. - -.. _create a ticket: https://code.djangoproject.com/newticket - -Localflavor and backwards compatibility -======================================= - -As documented in our :ref:`API stability -<misc-api-stability-localflavor>` policy, Django will always attempt -to make :mod:`django.contrib.localflavor` reflect the officially -gazetted policies of the appropriate local government authority. For -example, if a government body makes a change to add, alter, or remove -a province (or state, or county), that change will be reflected in -Django's localflavor in the next stable Django release. - -When a backwards-incompatible change is made (for example, the removal -or renaming of a province) the localflavor in question will raise a -warning when that localflavor is imported. This provides a runtime -indication that something may require attention. - -However, once you have addressed the backwards compatibility (for -example, auditing your code to see if any data migration is required), -the warning serves no purpose. The warning can then be supressed. -For example, to suppress the warnings raised by the Indonesian -localflavor you would use the following code:: - - import warnings - warnings.filterwarnings('ignore', - category=RuntimeWarning, - module='django.contrib.localflavor.id') - from django.contrib.localflavor.id import forms as id_forms - - -Argentina (``ar``) -============================================= - -.. class:: ar.forms.ARPostalCodeField - - A form field that validates input as either a classic four-digit Argentinian - postal code or a CPA_. - -.. _CPA: http://www.correoargentino.com.ar/consulta_cpa/home.php - -.. class:: ar.forms.ARDNIField - - A form field that validates input as a Documento Nacional de Identidad (DNI) - number. - -.. class:: ar.forms.ARCUITField - - A form field that validates input as a Codigo Unico de Identificacion - Tributaria (CUIT) number. - -.. class:: ar.forms.ARProvinceSelect - - A ``Select`` widget that uses a list of Argentina's provinces and autonomous - cities as its choices. - -Australia (``au``) -============================================= - -.. versionadded:: 1.4 - -.. class:: au.forms.AUPostCodeField - - A form field that validates input as an Australian postcode. - -.. class:: au.forms.AUPhoneNumberField - - A form field that validates input as an Australian phone number. Valid numbers - have ten digits. - -.. class:: au.forms.AUStateSelect - - A ``Select`` widget that uses a list of Australian states/territories as its - choices. - -.. class:: au.models.AUPhoneNumberField - - A model field that checks that the value is a valid Australian phone - number (ten digits). - -.. class:: au.models.AUStateField - - A model field that forms represent as a ``forms.AUStateField`` field and - stores the three-letter Australian state abbreviation in the database. - -.. class:: au.models.AUPostCodeField - - A model field that forms represent as a ``forms.AUPostCodeField`` field - and stores the four-digit Australian postcode in the database. - -Austria (``at``) -================ - -.. class:: at.forms.ATZipCodeField - - A form field that validates its input as an Austrian zip code, with the - format XXXX (first digit must be greater than 0). - -.. class:: at.forms.ATStateSelect - - A ``Select`` widget that uses a list of Austrian states as its choices. - -.. class:: at.forms.ATSocialSecurityNumberField - - A form field that validates its input as an Austrian social security number. - -Belgium (``be``) -================ - -.. versionadded:: 1.3 - -.. class:: be.forms.BEPhoneNumberField - - A form field that validates input as a Belgium phone number, with one of - the formats 0x xxx xx xx, 0xx xx xx xx, 04xx xx xx xx, 0x/xxx.xx.xx, - 0xx/xx.xx.xx, 04xx/xx.xx.xx, 0x.xxx.xx.xx, 0xx.xx.xx.xx, 04xx.xx.xx.xx, - 0xxxxxxxx or 04xxxxxxxx. - -.. class:: be.forms.BEPostalCodeField - - A form field that validates input as a Belgium postal code, in the range - and format 1XXX-9XXX. - -.. class:: be.forms.BEProvinceSelect - - A ``Select`` widget that uses a list of Belgium provinces as its - choices. - -.. class:: be.forms.BERegionSelect - - A ``Select`` widget that uses a list of Belgium regions as its - choices. - -Brazil (``br``) -=============== - -.. class:: br.forms.BRPhoneNumberField - - A form field that validates input as a Brazilian phone number, with the format - XX-XXXX-XXXX. - -.. class:: br.forms.BRZipCodeField - - A form field that validates input as a Brazilian zip code, with the format - XXXXX-XXX. - -.. class:: br.forms.BRStateSelect - - A ``Select`` widget that uses a list of Brazilian states/territories as its - choices. - -.. class:: br.forms.BRCPFField - - A form field that validates input as `Brazilian CPF`_. - - Input can either be of the format XXX.XXX.XXX-VD or be a group of 11 digits. - -.. _Brazilian CPF: http://en.wikipedia.org/wiki/Cadastro_de_Pessoas_F%C3%ADsicas - -.. class:: br.forms.BRCNPJField - - A form field that validates input as `Brazilian CNPJ`_. - - Input can either be of the format XX.XXX.XXX/XXXX-XX or be a group of 14 - digits. - -.. _Brazilian CNPJ: http://en.wikipedia.org/wiki/National_identification_number#Brazil - -Canada (``ca``) -=============== - -.. class:: ca.forms.CAPhoneNumberField - - A form field that validates input as a Canadian phone number, with the format - XXX-XXX-XXXX. - -.. class:: ca.forms.CAPostalCodeField - - A form field that validates input as a Canadian postal code, with the format - XXX XXX. - -.. class:: ca.forms.CAProvinceField - - A form field that validates input as a Canadian province name or abbreviation. - -.. class:: ca.forms.CASocialInsuranceNumberField - - A form field that validates input as a Canadian Social Insurance Number (SIN). - A valid number must have the format XXX-XXX-XXX and pass a `Luhn mod-10 - checksum`_. - -.. _Luhn mod-10 checksum: http://en.wikipedia.org/wiki/Luhn_algorithm - -.. class:: ca.forms.CAProvinceSelect - - A ``Select`` widget that uses a list of Canadian provinces and territories as - its choices. - -Chile (``cl``) -============== - -.. class:: cl.forms.CLRutField - - A form field that validates input as a Chilean national identification number - ('Rol Unico Tributario' or RUT). The valid format is XX.XXX.XXX-X. - -.. class:: cl.forms.CLRegionSelect - - A ``Select`` widget that uses a list of Chilean regions (Regiones) as its - choices. - -China (``cn``) -============== - -.. versionadded:: 1.4 - -.. class:: cn.forms.CNProvinceSelect - - A ``Select`` widget that uses a list of Chinese regions as its choices. - -.. class:: cn.forms.CNPostCodeField - - A form field that validates input as a Chinese post code. - Valid formats are XXXXXX where X is digit. - -.. class:: cn.forms.CNIDCardField - - A form field that validates input as a Chinese Identification Card Number. - Both 1st and 2nd generation ID Card Number are validated. - -.. class:: cn.forms.CNPhoneNumberField - - A form field that validates input as a Chinese phone number. - Valid formats are 0XX-XXXXXXXX, composed of 3 or 4 digits of region code - and 7 or 8 digits of phone number. - -.. class:: cn.forms.CNCellNumberField - - A form field that validates input as a Chinese mobile phone number. - Valid formats are like 1XXXXXXXXXX, where X is digit. - The second digit could only be 3, 5 and 8. - -Colombia (``co``) -================= - -.. versionadded:: 1.4 - -.. class:: co.forms.CoDepartmentSelect - - A ``Select`` widget that uses a list of Colombian departments - as its choices. - -Croatia (``hr``) -================ - -.. versionadded:: 1.4 +For documentation on a given country's localflavor helpers, see its README +file. -.. class:: hr.forms.HRCountySelect +.. _ISO 3166 country code: http://www.iso.org/iso/country_codes.htm - A ``Select`` widget that uses a list of counties of Croatia as its choices. - -.. class:: hr.forms.HRPhoneNumberPrefixSelect - - A ``Select`` widget that uses a list of phone number prefixes of Croatia as - its choices. - -.. class:: hr.forms.HRLicensePlatePrefixSelect - - A ``Select`` widget that uses a list of vehicle license plate prefixes of - Croatia as its choices. - -.. class:: hr.forms.HRPhoneNumberField - - A form field that validates input as a phone number of Croatia. - A valid format is a country code or a leading zero, area code prefix, 6 or 7 - digit number; e.g. +385XXXXXXXX or 0XXXXXXXX - Validates fixed, mobile and FGSM numbers. Normalizes to a full number with - country code (+385 prefix). - -.. class:: hr.forms.HRLicensePlateField - - A form field that validates input as a vehicle license plate of Croatia. - Normalizes to the specific format XX YYYY-XX where X is a letter and Y a - digit. There can be three or four digits. - Suffix is constructed from the shared letters of the Croatian and English - alphabets. - It is used for standardized license plates only. Special cases like license - plates for oldtimers, temporary license plates, government institution - license plates and customized license plates are not covered by this field. - -.. class:: hr.forms.HRPostalCodeField - - A form field that validates input as a postal code of Croatia. - It consists of exactly five digits ranging from 10000 to 59999 inclusive. - -.. class:: hr.forms.HROIBField - - A form field that validates input as a Personal Identification Number (OIB) - of Croatia. - It consists of exactly eleven digits. - -.. class:: hr.forms.HRJMBGField - - A form field that validates input as a Unique Master Citizen Number (JMBG). - The number is still in use in Croatia, but it is being replaced by OIB. - This field works for other ex-Yugoslavia countries as well where the JMBG is - still in use. - The area segment of the JMBG is not validated because the citizens might - have emigrated to another ex-Yugoslavia country. - The number consists of exactly thirteen digits. - -.. class:: hr.forms.HRJMBAGField - - A form field that validates input as a Unique Master Academic Citizen Number - (JMBAG) of Croatia. - This number is used by college students and professors in Croatia. - The number consists of exactly nineteen digits. - -Czech (``cz``) +How to migrate ============== -.. class:: cz.forms.CZPostalCodeField - - A form field that validates input as a Czech postal code. Valid formats - are XXXXX or XXX XX, where X is a digit. - -.. class:: cz.forms.CZBirthNumberField - - A form field that validates input as a Czech Birth Number. - A valid number must be in format XXXXXX/XXXX (slash is optional). - -.. class:: cz.forms.CZICNumberField - - A form field that validates input as a Czech IC number field. - -.. class:: cz.forms.CZRegionSelect - - A ``Select`` widget that uses a list of Czech regions as its choices. - -Ecuador (``ec``) -================ - -.. versionadded:: 1.4 - -.. class:: ec.forms.EcProvinceSelect - - A ``Select`` widget that uses a list of Ecuatorian provinces as - its choices. - -Finland (``fi``) -================ - -.. class:: fi.forms.FISocialSecurityNumber - - A form field that validates input as a Finnish social security number. - -.. class:: fi.forms.FIZipCodeField - - A form field that validates input as a Finnish zip code. Valid codes - consist of five digits. - -.. class:: fi.forms.FIMunicipalitySelect - - A ``Select`` widget that uses a list of Finnish municipalities as its - choices. - -France (``fr``) -=============== - -.. class:: fr.forms.FRPhoneNumberField - - A form field that validates input as a French local phone number. The - correct format is 0X XX XX XX XX. 0X.XX.XX.XX.XX and 0XXXXXXXXX validate - but are corrected to 0X XX XX XX XX. - -.. class:: fr.forms.FRZipCodeField - - A form field that validates input as a French zip code. Valid codes - consist of five digits. - -.. class:: fr.forms.FRDepartmentSelect - - A ``Select`` widget that uses a list of French departments as its choices. - -Germany (``de``) -================ - -.. class:: de.forms.DEIdentityCardNumberField - - A form field that validates input as a German identity card number - (Personalausweis_). Valid numbers have the format - XXXXXXXXXXX-XXXXXXX-XXXXXXX-X, with no group consisting entirely of zeroes. - -.. _Personalausweis: http://de.wikipedia.org/wiki/Personalausweis - -.. class:: de.forms.DEZipCodeField - - A form field that validates input as a German zip code. Valid codes - consist of five digits. - -.. class:: de.forms.DEStateSelect - - A ``Select`` widget that uses a list of German states as its choices. - -Hong Kong (``hk``) -================== - -.. class:: hk.forms.HKPhoneNumberField - - A form field that validates input as a Hong Kong phone number. - - -The Netherlands (``nl``) -======================== - -.. class:: nl.forms.NLPhoneNumberField - - A form field that validates input as a Dutch telephone number. - -.. class:: nl.forms.NLSofiNumberField - - A form field that validates input as a Dutch social security number - (SoFI/BSN). - -.. class:: nl.forms.NLZipCodeField - - A form field that validates input as a Dutch zip code. - -.. class:: nl.forms.NLProvinceSelect +If you've used the old ``django.contrib.localflavor`` package, follow these two +easy steps to update your code: - A ``Select`` widget that uses a list of Dutch provinces as its list of - choices. +1. Install the appropriate third-party ``django-localflavor-*`` package(s). + Go to https://github.com/django/ and find the package for your country. -Iceland (``is_``) -================= +2. Change your app's import statements to reference the new packages. -.. class:: is_.forms.ISIdNumberField + For example, change this:: - A form field that validates input as an Icelandic identification number - (kennitala). The format is XXXXXX-XXXX. + from django.contrib.localflavor.fr.forms import FRPhoneNumberField -.. class:: is_.forms.ISPhoneNumberField + ...to this:: - A form field that validates input as an Icelandtic phone number (seven - digits with an optional hyphen or space after the first three digits). + from django_localflavor_fr.forms import FRPhoneNumberField -.. class:: is_.forms.ISPostalCodeSelect +The code in the new packages is the same (it was copied directly from Django), +so you don't have to worry about backwards compatibility in terms of +functionality. Only the imports have changed. - A ``Select`` widget that uses a list of Icelandic postal codes as its - choices. - -India (``in_``) -=============== - -.. class:: in_.forms.INStateField - - A form field that validates input as an Indian state/territory name or - abbreviation. Input is normalized to the standard two-letter vehicle - registration abbreviation for the given state or territory. - -.. class:: in_.forms.INZipCodeField - - A form field that validates input as an Indian zip code, with the - format XXXXXXX. - -.. class:: in_.forms.INStateSelect - - A ``Select`` widget that uses a list of Indian states/territories as its - choices. - -.. versionadded:: 1.4 - -.. class:: in_.forms.INPhoneNumberField - - A form field that validates that the data is a valid Indian phone number, - including the STD code. It's normalised to 0XXX-XXXXXXX or 0XXX XXXXXXX - format. The first string is the STD code which is a '0' followed by 2-4 - digits. The second string is 8 digits if the STD code is 3 digits, 7 - digits if the STD code is 4 digits and 6 digits if the STD code is 5 - digits. The second string will start with numbers between 1 and 6. The - separator is either a space or a hyphen. - -Ireland (``ie``) -================ - -.. class:: ie.forms.IECountySelect - - A ``Select`` widget that uses a list of Irish Counties as its choices. - -Indonesia (``id``) +Deprecation policy ================== -.. class:: id.forms.IDPostCodeField - - A form field that validates input as an Indonesian post code field. - -.. class:: id.forms.IDProvinceSelect - - A ``Select`` widget that uses a list of Indonesian provinces as its choices. - -.. versionchanged:: 1.3 - The province "Nanggroe Aceh Darussalam (NAD)" has been removed - from the province list in favor of the new official designation - "Aceh (ACE)". - -.. class:: id.forms.IDPhoneNumberField - - A form field that validates input as an Indonesian telephone number. - -.. class:: id.forms.IDLicensePlatePrefixSelect - - A ``Select`` widget that uses a list of Indonesian license plate - prefix code as its choices. - -.. class:: id.forms.IDLicensePlateField - - A form field that validates input as an Indonesian vehicle license plate. - -.. class:: id.forms.IDNationalIdentityNumberField - - A form field that validates input as an Indonesian national identity - number (`NIK`_/KTP). The output will be in the format of - 'XX.XXXX.DDMMYY.XXXX'. Dots or spaces can be used in the input to break - down the numbers. - -.. _NIK: http://en.wikipedia.org/wiki/Indonesian_identity_card - -Israel (``il``) -=============== - -.. class:: il.forms.ILPostalCodeField - - A form field that validates its input as an Israeli five-digit postal code. - -.. class:: il.forms.ILIDNumberField - - A form field that validates its input as an `Israeli identification number`_. - The output will be in the format of a 2-9 digit number, consisting of a - 1-8 digit ID number followed by a single checksum digit, calculated using - the `Luhn algorithm`_. +In Django 1.5, importing from ``django.contrib.localflavor`` will result in a +``DeprecationWarning``. This means your code will still work, but you should +change it as soon as possible. - Input may contain an optional hyphen separating the ID number from the checksum - digit. +In Django 1.6, importing from ``django.contrib.localflavor`` will no longer +work. -.. _Israeli identification number: http://he.wikipedia.org/wiki/%D7%9E%D7%A1%D7%A4%D7%A8_%D7%96%D7%94%D7%95%D7%AA_(%D7%99%D7%A9%D7%A8%D7%90%D7%9C) -.. _Luhn algorithm: http://en.wikipedia.org/wiki/Luhn_algorithm - -Italy (``it``) -============== - -.. class:: it.forms.ITSocialSecurityNumberField - - A form field that validates input as an Italian social security number - (`codice fiscale`_). - -.. _codice fiscale: http://www.agenziaentrate.gov.it/wps/content/Nsilib/Nsi/Home/CosaDeviFare/Richiedere/Codice+fiscale+e+tessera+sanitaria/Richiesta+TS_CF/SchedaI/Informazioni+codificazione+pf/ - -.. class:: it.forms.ITVatNumberField - - A form field that validates Italian VAT numbers (partita IVA). - -.. class:: it.forms.ITZipCodeField - - A form field that validates input as an Italian zip code. Valid codes - must have five digits. - -.. class:: it.forms.ITProvinceSelect - - A ``Select`` widget that uses a list of Italian provinces as its choices. - -.. class:: it.forms.ITRegionSelect - - A ``Select`` widget that uses a list of Italian regions as its choices. - -Japan (``jp``) -============== - -.. class:: jp.forms.JPPostalCodeField - - A form field that validates input as a Japanese postcode. It accepts seven - digits, with or without a hyphen. - -.. class:: jp.forms.JPPrefectureSelect - - A ``Select`` widget that uses a list of Japanese prefectures as its choices. - -Kuwait (``kw``) -=============== - -.. class:: kw.forms.KWCivilIDNumberField - - A form field that validates input as a Kuwaiti Civil ID number. A valid - Civil ID number must obey the following rules: - - * The number consist of 12 digits. - * The birthdate of the person is a valid date. - * The calculated checksum equals to the last digit of the Civil ID. - -Macedonia (``mk``) +Supported countries =================== -.. versionadded:: 1.4 - -.. class:: mk.forms.MKIdentityCardNumberField - - A form field that validates input as a Macedonian identity card number. - Both old and new identity card numbers are supported. - - -.. class:: mk.forms.MKMunicipalitySelect - - A form ``Select`` widget that uses a list of Macedonian municipalities as - choices. - +The following countries have django-localflavor- packages. -.. class:: mk.forms.UMCNField +* Argentina: https://github.com/django/django-localflavor-ar +* Australia: https://github.com/django/django-localflavor-au +* Austria: https://github.com/django/django-localflavor-at +* Belgium: https://github.com/django/django-localflavor-be +* Brazil: https://github.com/django/django-localflavor-br +* Canada: https://github.com/django/django-localflavor-ca +* Chile: https://github.com/django/django-localflavor-cl +* China: https://github.com/django/django-localflavor-cn +* Colombia: https://github.com/django/django-localflavor-co +* Croatia: https://github.com/django/django-localflavor-cr +* Czech Republic: https://github.com/django/django-localflavor-cz +* Ecuador: https://github.com/django/django-localflavor-ec +* Finland: https://github.com/django/django-localflavor-fi +* France: https://github.com/django/django-localflavor-fr +* Germany: https://github.com/django/django-localflavor-de +* Hong Kong: https://github.com/django/django-localflavor-hk +* Iceland: https://github.com/django/django-localflavor-is +* India: https://github.com/django/django-localflavor-in +* Indonesia: https://github.com/django/django-localflavor-id +* Ireland: https://github.com/django/django-localflavor-ie +* Israel: https://github.com/django/django-localflavor-il +* Italy: https://github.com/django/django-localflavor-it +* Japan: https://github.com/django/django-localflavor-jp +* Kuwait: https://github.com/django/django-localflavor-kw +* Lithuania: https://github.com/simukis/django-localflavor-lt +* Macedonia: https://github.com/django/django-localflavor-mk +* Mexico: https://github.com/django/django-localflavor-mx +* The Netherlands: https://github.com/django/django-localflavor-nl +* Norway: https://github.com/django/django-localflavor-no +* Peru: https://github.com/django/django-localflavor-pe +* Poland: https://github.com/django/django-localflavor-pl +* Portugal: https://github.com/django/django-localflavor-pt +* Paraguay: https://github.com/django/django-localflavor-py +* Romania: https://github.com/django/django-localflavor-ro +* Russia: https://github.com/django/django-localflavor-ru +* Slovakia: https://github.com/django/django-localflavor-sk +* Slovenia: https://github.com/django/django-localflavor-si +* South Africa: https://github.com/django/django-localflavor-za +* Spain: https://github.com/django/django-localflavor-es +* Sweden: https://github.com/django/django-localflavor-se +* Switzerland: https://github.com/django/django-localflavor-ch +* Turkey: https://github.com/django/django-localflavor-tr +* United Kingdom: https://github.com/django/django-localflavor-gb +* United States of America: https://github.com/django/django-localflavor-us +* Uruguay: https://github.com/django/django-localflavor-uy - A form field that validates input as a unique master citizen - number. +django.contrib.localflavor.generic +================================== - The format of the unique master citizen number is not unique - to Macedonia. For more information see: - https://secure.wikimedia.org/wikipedia/en/wiki/Unique_Master_Citizen_Number +The ``django.contrib.localflavor.generic`` package, which hasn't been removed from +Django yet, contains useful code that is not specific to one particular country +or culture. Currently, it defines date, datetime and split datetime input +fields based on those from :doc:`forms </topics/forms/index>`, but with non-US +default formats. Here's an example of how to use them:: - A value will pass validation if it complies to the following rules: - - * Consists of exactly 13 digits - * The first 7 digits represent a valid past date in the format DDMMYYY - * The last digit of the UMCN passes a checksum test - - -.. class:: mk.models.MKIdentityCardNumberField - - A model field that forms represent as a - ``forms.MKIdentityCardNumberField`` field. - - -.. class:: mk.models.MKMunicipalityField - - A model field that forms represent as a - ``forms.MKMunicipalitySelect`` and stores the 2 character code of the - municipality in the database. - - -.. class:: mk.models.UMCNField - - A model field that forms represent as a ``forms.UMCNField`` field. - - -Mexico (``mx``) -=============== - -.. class:: mx.forms.MXZipCodeField - - .. versionadded:: 1.4 - - A form field that accepts a Mexican Zip Code. - - More info about this: List of postal codes in Mexico (zipcodes_) - -.. _zipcodes: http://en.wikipedia.org/wiki/List_of_postal_codes_in_Mexico - -.. class:: mx.forms.MXRFCField - - .. versionadded:: 1.4 - - A form field that validates a Mexican *Registro Federal de Contribuyentes* for - either **Persona física** or **Persona moral**. This field accepts RFC strings - whether or not it contains a *homoclave*. - - More info about this: Registro Federal de Contribuyentes (rfc_) - -.. _rfc: http://es.wikipedia.org/wiki/Registro_Federal_de_Contribuyentes_(M%C3%A9xico) - -.. class:: mx.forms.MXCURPField - - .. versionadded:: 1.4 - - A field that validates a Mexican *Clave Única de Registro de Población*. - - More info about this: Clave Unica de Registro de Poblacion (curp_) - -.. _curp: http://www.condusef.gob.mx/index.php/clave-unica-de-registro-de-poblacion-curp - -.. class:: mx.forms.MXStateSelect - - A ``Select`` widget that uses a list of Mexican states as its choices. - -.. class:: mx.models.MXStateField - - .. versionadded:: 1.4 - - A model field that stores the three-letter Mexican state abbreviation in the - database. - -.. class:: mx.models.MXZipCodeField - - .. versionadded:: 1.4 - - A model field that forms represent as a ``forms.MXZipCodeField`` field and - stores the five-digit Mexican zip code. - -.. class:: mx.models.MXRFCField - - .. versionadded:: 1.4 - - A model field that forms represent as a ``forms.MXRFCField`` field and - stores the value of a valid Mexican RFC. - -.. class:: mx.models.MXCURPField - - .. versionadded:: 1.4 - - A model field that forms represent as a ``forms.MXCURPField`` field and - stores the value of a valid Mexican CURP. - -Additionally, a choice tuple is provided in ``django.contrib.localflavor.mx.mx_states``, -allowing customized model and form fields, and form presentations, for subsets of -Mexican states abbreviations: - -.. data:: mx.mx_states.STATE_CHOICES - - A tuple of choices of the states abbreviations for all 31 Mexican states, - plus the `Distrito Federal`. - -Norway (``no``) -=============== - -.. class:: no.forms.NOSocialSecurityNumber - - A form field that validates input as a Norwegian social security number - (personnummer_). - -.. _personnummer: http://no.wikipedia.org/wiki/Personnummer - -.. class:: no.forms.NOZipCodeField - - A form field that validates input as a Norwegian zip code. Valid codes - have four digits. - -.. class:: no.forms.NOMunicipalitySelect - - A ``Select`` widget that uses a list of Norwegian municipalities (fylker) as - its choices. - -Paraguay (``py``) -================= - -.. versionadded:: 1.4 - -.. class:: py.forms.PyDepartmentSelect - - A ``Select`` widget with a list of Paraguayan departments as choices. - -.. class:: py.forms.PyNumberedDepartmentSelect - - A ``Select`` widget with a roman numbered list of Paraguayan departments as choices. - -Peru (``pe``) -============= - -.. class:: pe.forms.PEDNIField - - A form field that validates input as a DNI (Peruvian national identity) - number. - -.. class:: pe.forms.PERUCField - - A form field that validates input as an RUC (Registro Unico de - Contribuyentes) number. Valid RUC numbers have 11 digits. - -.. class:: pe.forms.PEDepartmentSelect - - A ``Select`` widget that uses a list of Peruvian Departments as its choices. - -Poland (``pl``) -=============== - -.. class:: pl.forms.PLPESELField - - A form field that validates input as a Polish national identification number - (PESEL_). - -.. _PESEL: http://en.wikipedia.org/wiki/PESEL - -.. versionadded:: 1.4 - -.. class:: pl.forms.PLNationalIDCardNumberField - - A form field that validates input as a Polish National ID Card number. The - valid format is AAAXXXXXX, where A is letter (A-Z), X is digit and left-most - digit is checksum digit. More information about checksum calculation algorithm - see `Polish identity card`_. - -.. _`Polish identity card`: http://en.wikipedia.org/wiki/Polish_identity_card - -.. class:: pl.forms.PLREGONField - - A form field that validates input as a Polish National Official Business - Register Number (REGON_), having either seven or nine digits. The checksum - algorithm used for REGONs is documented at - http://wipos.p.lodz.pl/zylla/ut/nip-rego.html. - -.. _REGON: http://www.stat.gov.pl/bip/regon_ENG_HTML.htm - -.. class:: pl.forms.PLPostalCodeField - - A form field that validates input as a Polish postal code. The valid format - is XX-XXX, where X is a digit. - -.. class:: pl.forms.PLNIPField - - A form field that validates input as a Polish Tax Number (NIP). Valid formats - are XXX-XXX-XX-XX, XXX-XX-XX-XXX or XXXXXXXXXX. The checksum algorithm used - for NIPs is documented at http://wipos.p.lodz.pl/zylla/ut/nip-rego.html. - -.. class:: pl.forms.PLCountySelect - - A ``Select`` widget that uses a list of Polish administrative units as its - choices. - -.. class:: pl.forms.PLProvinceSelect - - A ``Select`` widget that uses a list of Polish voivodeships (administrative - provinces) as its choices. - -Portugal (``pt``) -================= - -.. class:: pt.forms.PTZipCodeField - - A form field that validates input as a Portuguese zip code. - -.. class:: pt.forms.PTPhoneNumberField - - A form field that validates input as a Portuguese phone number. - Valid numbers have 9 digits (may include spaces) or start by 00 - or + (international). - -Romania (``ro``) -================ - -.. class:: ro.forms.ROCIFField - - A form field that validates Romanian fiscal identification codes (CIF). The - return value strips the leading RO, if given. - -.. class:: ro.forms.ROCNPField - - A form field that validates Romanian personal numeric codes (CNP). - -.. class:: ro.forms.ROCountyField - - A form field that validates its input as a Romanian county (judet) name or - abbreviation. It normalizes the input to the standard vehicle registration - abbreviation for the given county. This field will only accept names written - with diacritics; consider using ROCountySelect as an alternative. - -.. class:: ro.forms.ROCountySelect - - A ``Select`` widget that uses a list of Romanian counties (judete) as its - choices. - -.. class:: ro.forms.ROIBANField - - A form field that validates its input as a Romanian International Bank - Account Number (IBAN). The valid format is ROXX-XXXX-XXXX-XXXX-XXXX-XXXX, - with or without hyphens. - -.. class:: ro.forms.ROPhoneNumberField - - A form field that validates Romanian phone numbers, short special numbers - excluded. - -.. class:: ro.forms.ROPostalCodeField - - A form field that validates Romanian postal codes. - -Russia (``ru``) -=============== - -.. versionadded:: 1.4 - -.. class:: ru.forms.RUPostalCodeField - - Russian Postal code field. The valid format is XXXXXX, where X is any - digit and the first digit is not zero. - -.. class:: ru.forms.RUCountySelect - - A ``Select`` widget that uses a list of Russian Counties as its choices. - -.. class:: ru.forms.RURegionSelect - - A ``Select`` widget that uses a list of Russian Regions as its choices. - -.. class:: ru.forms.RUPassportNumberField - - Russian internal passport number. The valid format is XXXX XXXXXX, where X - is any digit. - -.. class:: ru.forms.RUAlienPassportNumberField - - Russian alien's passport number. The valid format is XX XXXXXXX, where X - is any digit. - -Slovakia (``sk``) -================= - -.. class:: sk.forms.SKPostalCodeField - - A form field that validates input as a Slovak postal code. Valid formats - are XXXXX or XXX XX, where X is a digit. - -.. class:: sk.forms.SKDistrictSelect - - A ``Select`` widget that uses a list of Slovak districts as its choices. - -.. class:: sk.forms.SKRegionSelect - - A ``Select`` widget that uses a list of Slovak regions as its choices. - -Slovenia (``si``) -================= - -.. class:: si.forms.SIEMSOField - - A form field that validates input as Slovenian personal identification - number and stores gender and birthday to self.info dictionary. - -.. class:: si.forms.SITaxNumberField - - A form field that validates input as a Slovenian tax number. Valid input - is SIXXXXXXXX or XXXXXXXX. - -.. class:: si.forms.SIPhoneNumberField - - A form field that validates input as a Slovenian phone number. Phone - number must contain at least local area code with optional country code. - -.. class:: si.forms.SIPostalCodeField - - A form field that provides a choice field of major Slovenian postal - codes. - -.. class:: si.forms.SIPostalCodeSelect - - A ``Select`` widget that uses a list of major Slovenian postal codes as - its choices. - - -South Africa (``za``) -===================== - -.. class:: za.forms.ZAIDField - - A form field that validates input as a South African ID number. Validation - uses the Luhn checksum and a simplistic (i.e., not entirely accurate) check - for birth date. - -.. class:: za.forms.ZAPostCodeField - - A form field that validates input as a South African postcode. Valid - postcodes must have four digits. - -Spain (``es``) -============== - -.. class:: es.forms.ESIdentityCardNumberField - - A form field that validates input as a Spanish NIF/NIE/CIF (Fiscal - Identification Number) code. - -.. class:: es.forms.ESCCCField - - A form field that validates input as a Spanish bank account number (Codigo - Cuenta Cliente or CCC). A valid CCC number has the format - EEEE-OOOO-CC-AAAAAAAAAA, where the E, O, C and A digits denote the entity, - office, checksum and account, respectively. The first checksum digit - validates the entity and office. The second checksum digit validates the - account. It is also valid to use a space as a delimiter, or to use no - delimiter. - -.. class:: es.forms.ESPhoneNumberField - - A form field that validates input as a Spanish phone number. Valid numbers - have nine digits, the first of which is 6, 8 or 9. - -.. class:: es.forms.ESPostalCodeField - - A form field that validates input as a Spanish postal code. Valid codes - have five digits, the first two being in the range 01 to 52, representing - the province. - -.. class:: es.forms.ESProvinceSelect - - A ``Select`` widget that uses a list of Spanish provinces as its choices. - -.. class:: es.forms.ESRegionSelect - - A ``Select`` widget that uses a list of Spanish regions as its choices. - -Sweden (``se``) -=============== - -.. class:: se.forms.SECountySelect - - A Select form widget that uses a list of the Swedish counties (län) as its - choices. - - The cleaned value is the official county code -- see - http://en.wikipedia.org/wiki/Counties_of_Sweden for a list. - -.. class:: se.forms.SEOrganisationNumber - - A form field that validates input as a Swedish organisation number - (organisationsnummer). - - It accepts the same input as SEPersonalIdentityField (for sole - proprietorships (enskild firma). However, co-ordination numbers are not - accepted. - - It also accepts ordinary Swedish organisation numbers with the format - NNNNNNNNNN. - - The return value will be YYYYMMDDXXXX for sole proprietors, and NNNNNNNNNN - for other organisations. - -.. class:: se.forms.SEPersonalIdentityNumber - - A form field that validates input as a Swedish personal identity number - (personnummer). - - The correct formats are YYYYMMDD-XXXX, YYYYMMDDXXXX, YYMMDD-XXXX, - YYMMDDXXXX and YYMMDD+XXXX. - - A \+ indicates that the person is older than 100 years, which will be taken - into consideration when the date is validated. - - The checksum will be calculated and checked. The birth date is checked - to be a valid date. - - By default, co-ordination numbers (samordningsnummer) will be accepted. To - only allow real personal identity numbers, pass the keyword argument - coordination_number=False to the constructor. - - The cleaned value will always have the format YYYYMMDDXXXX. - -.. class:: se.forms.SEPostalCodeField - - A form field that validates input as a Swedish postal code (postnummer). - Valid codes consist of five digits (XXXXX). The number can optionally be - formatted with a space after the third digit (XXX XX). - - The cleaned value will never contain the space. - -Switzerland (``ch``) -==================== - -.. class:: ch.forms.CHIdentityCardNumberField - - A form field that validates input as a Swiss identity card number. - A valid number must confirm to the X1234567<0 or 1234567890 format and - have the correct checksums. - -.. class:: ch.forms.CHPhoneNumberField - - A form field that validates input as a Swiss phone number. The correct - format is 0XX XXX XX XX. 0XX.XXX.XX.XX and 0XXXXXXXXX validate but are - corrected to 0XX XXX XX XX. - -.. class:: ch.forms.CHZipCodeField - - A form field that validates input as a Swiss zip code. Valid codes - consist of four digits. - -.. class:: ch.forms.CHStateSelect - - A ``Select`` widget that uses a list of Swiss states as its choices. - -Turkey (``tr``) -=============== - -.. class:: tr.forms.TRZipCodeField - - A form field that validates input as a Turkish zip code. Valid codes - consist of five digits. - -.. class:: tr.forms.TRPhoneNumberField - - A form field that validates input as a Turkish phone number. The correct - format is 0xxx xxx xxxx. +90xxx xxx xxxx and inputs without spaces also - validates. The result is normalized to xxx xxx xxxx format. - -.. class:: tr.forms.TRIdentificationNumberField - - A form field that validates input as a TR identification number. A valid - number must satisfy the following: - - * The number consist of 11 digits. - * The first digit cannot be 0. - * (sum(1st, 3rd, 5th, 7th, 9th)*7 - sum(2nd,4th,6th,8th)) % 10) must be - equal to the 10th digit. - * (sum(1st to 10th) % 10) must be equal to the 11th digit. - -.. class:: tr.forms.TRProvinceSelect - - A ``select`` widget that uses a list of Turkish provinces as its choices. - -United Kingdom (``gb``) -======================= - -.. class:: gb.forms.GBPostcodeField - - A form field that validates input as a UK postcode. The regular - expression used is sourced from the schema for British Standard BS7666 - address types at http://www.cabinetoffice.gov.uk/media/291293/bs7666-v2-0.xml. - -.. class:: gb.forms.GBCountySelect - - A ``Select`` widget that uses a list of UK counties/regions as its choices. - -.. class:: gb.forms.GBNationSelect - - A ``Select`` widget that uses a list of UK nations as its choices. - -United States of America (``us``) -================================= - -.. class:: us.forms.USPhoneNumberField - - A form field that validates input as a U.S. phone number. - -.. class:: us.forms.USSocialSecurityNumberField - - A form field that validates input as a U.S. Social Security Number (SSN). - A valid SSN must obey the following rules: - - * Format of XXX-XX-XXXX - * No group of digits consisting entirely of zeroes - * Leading group of digits cannot be 666 - * Number not in promotional block 987-65-4320 through 987-65-4329 - * Number not one known to be invalid due to widespread promotional - use or distribution (e.g., the Woolworth's number or the 1962 - promotional number) - -.. class:: us.forms.USStateField - - A form field that validates input as a U.S. state name or abbreviation. It - normalizes the input to the standard two-letter postal service abbreviation - for the given state. - -.. class:: us.forms.USZipCodeField - - A form field that validates input as a U.S. ZIP code. Valid formats are - XXXXX or XXXXX-XXXX. - -.. class:: us.forms.USStateSelect - - A form ``Select`` widget that uses a list of U.S. states/territories as its - choices. - -.. class:: us.forms.USPSSelect - - A form ``Select`` widget that uses a list of U.S Postal Service - state, territory and country abbreviations as its choices. - -.. class:: us.models.PhoneNumberField - - A :class:`CharField` that checks that the value is a valid U.S.A.-style phone - number (in the format ``XXX-XXX-XXXX``). - -.. class:: us.models.USStateField - - A model field that forms represent as a ``forms.USStateField`` field and - stores the two-letter U.S. state abbreviation in the database. - -.. class:: us.models.USPostalCodeField - - A model field that forms represent as a ``forms.USPSSelect`` field - and stores the two-letter U.S Postal Service abbreviation in the - database. - -Additionally, a variety of choice tuples are provided in -``django.contrib.localflavor.us.us_states``, allowing customized model -and form fields, and form presentations, for subsets of U.S states, -territories and U.S Postal Service abbreviations: - -.. data:: us.us_states.CONTIGUOUS_STATES - - A tuple of choices of the postal abbreviations for the - contiguous or "lower 48" states (i.e., all except Alaska and - Hawaii), plus the District of Columbia. - -.. data:: us.us_states.US_STATES - - A tuple of choices of the postal abbreviations for all - 50 U.S. states, plus the District of Columbia. - -.. data:: us.us_states.US_TERRITORIES - - A tuple of choices of the postal abbreviations for U.S - territories: American Samoa, Guam, the Northern Mariana Islands, - Puerto Rico and the U.S. Virgin Islands. - -.. data:: us.us_states.ARMED_FORCES_STATES - - A tuple of choices of the postal abbreviations of the three U.S - military postal "states": Armed Forces Americas, Armed Forces - Europe and Armed Forces Pacific. - -.. data:: us.us_states.COFA_STATES - - A tuple of choices of the postal abbreviations of the three - independent nations which, under the Compact of Free Association, - are served by the U.S. Postal Service: the Federated States of - Micronesia, the Marshall Islands and Palau. - -.. data:: us.us_states.OBSOLETE_STATES - - A tuple of choices of obsolete U.S Postal Service state - abbreviations: the former abbreviation for the Northern Mariana - Islands, plus the Panama Canal Zone, the Philippines and the - former Pacific trust territories. - -.. data:: us.us_states.STATE_CHOICES - - A tuple of choices of all postal abbreviations corresponding to U.S states or - territories, and the District of Columbia.. - -.. data:: us.us_states.USPS_CHOICES - - A tuple of choices of all postal abbreviations recognized by the - U.S Postal Service (including all states and territories, the - District of Columbia, armed forces "states" and independent - nations serviced by USPS). - -Uruguay (``uy``) -================ - -.. class:: uy.forms.UYCIField + from django import forms + from django.contrib.localflavor import generic - A field that validates Uruguayan 'Cedula de identidad' (CI) numbers. + class MyForm(forms.Form): + my_date_field = generic.forms.DateField() -.. class:: uy.forms.UYDepartamentSelect +Internationalization of localflavor +=================================== - A ``Select`` widget that uses a list of Uruguayan departments as its - choices. +Localflavor has its own catalog of translations, in the directory +``django/contrib/localflavor/locale``, and it's not loaded automatically like +Django's general catalog in ``django/conf/locale``. If you want localflavor's +texts to be translated, like form fields error messages, you must include +:mod:`django.contrib.localflavor` in the :setting:`INSTALLED_APPS` setting, so +the internationalization system can find the catalog, as explained in +:ref:`how-django-discovers-translations`. diff --git a/docs/ref/contrib/sitemaps.txt b/docs/ref/contrib/sitemaps.txt index 2393a4a9a3..ef6c64dc61 100644 --- a/docs/ref/contrib/sitemaps.txt +++ b/docs/ref/contrib/sitemaps.txt @@ -330,8 +330,6 @@ with a caching decorator -- you must name your sitemap view and pass Template customization ====================== -.. versionadded:: 1.3 - If you wish to use a different template for each sitemap or sitemap index available on your site, you may specify it by passing a ``template_name`` parameter to the ``sitemap`` and ``index`` views via the URLconf:: diff --git a/docs/ref/contrib/sites.txt b/docs/ref/contrib/sites.txt index 8fc434ba9b..790e003453 100644 --- a/docs/ref/contrib/sites.txt +++ b/docs/ref/contrib/sites.txt @@ -80,11 +80,11 @@ This accomplishes several things quite nicely: The view code that displays a given story just checks to make sure the requested story is on the current site. It looks something like this:: - from django.conf import settings + from django.contrib.sites.models import get_current_site def article_detail(request, article_id): try: - a = Article.objects.get(id=article_id, sites__id__exact=settings.SITE_ID) + a = Article.objects.get(id=article_id, sites__id__exact=get_current_site(request).id) except Article.DoesNotExist: raise Http404 # ... @@ -131,53 +131,36 @@ For example:: # Do something else. Of course, it's ugly to hard-code the site IDs like that. This sort of -hard-coding is best for hackish fixes that you need done quickly. A slightly +hard-coding is best for hackish fixes that you need done quickly. The cleaner way of accomplishing the same thing is to check the current site's domain:: - from django.conf import settings - from django.contrib.sites.models import Site + from django.contrib.sites.models import get_current_site def my_view(request): - current_site = Site.objects.get(id=settings.SITE_ID) + current_site = get_current_site(request) if current_site.domain == 'foo.com': # Do something else: # Do something else. -The idiom of retrieving the :class:`~django.contrib.sites.models.Site` object -for the value of :setting:`settings.SITE_ID <SITE_ID>` is quite common, so -the :class:`~django.contrib.sites.models.Site` model's manager has a -``get_current()`` method. This example is equivalent to the previous one:: +This has also the advantage of checking if the sites framework is installed, and +return a :class:`RequestSite` instance if it is not. + +If you don't have access to the request object, you can use the +``get_current()`` method of the :class:`~django.contrib.sites.models.Site` +model's manager. You should then ensure that your settings file does contain +the :setting:`SITE_ID` setting. This example is equivalent to the previous one:: from django.contrib.sites.models import Site - def my_view(request): + def my_function_without_request(): current_site = Site.objects.get_current() if current_site.domain == 'foo.com': # Do something else: # Do something else. -.. versionchanged:: 1.3 - -For code which relies on getting the current domain but cannot be certain -that the sites framework will be installed for any given project, there is a -utility function :func:`~django.contrib.sites.models.get_current_site` that -takes a request object as an argument and returns either a Site instance (if -the sites framework is installed) or a RequestSite instance (if it is not). -This allows loose coupling with the sites framework and provides a usable -fallback for cases where it is not installed. - -.. versionadded:: 1.3 - -.. function:: get_current_site(request) - - Checks if contrib.sites is installed and returns either the current - :class:`~django.contrib.sites.models.Site` object or a - :class:`~django.contrib.sites.models.RequestSite` object based on - the request. - Getting the current domain for display -------------------------------------- @@ -196,14 +179,14 @@ current site's :attr:`~django.contrib.sites.models.Site.name` and Here's an example of what the form-handling view looks like:: - from django.contrib.sites.models import Site + from django.contrib.sites.models import get_current_site from django.core.mail import send_mail def register_for_newsletter(request): # Check form values, etc., and subscribe the user. # ... - current_site = Site.objects.get_current() + current_site = get_current_site(request) send_mail('Thanks for subscribing to %s alerts' % current_site.name, 'Thanks for your subscription. We appreciate it.\n\n-The %s team.' % current_site.name, 'editor@%s' % current_site.domain, @@ -374,19 +357,19 @@ Here's how Django uses the sites framework: * In the :mod:`redirects framework <django.contrib.redirects>`, each redirect object is associated with a particular site. When Django searches - for a redirect, it takes into account the current :setting:`SITE_ID`. + for a redirect, it takes into account the current site. * In the comments framework, each comment is associated with a particular site. When a comment is posted, its - :class:`~django.contrib.sites.models.Site` is set to the current - :setting:`SITE_ID`, and when comments are listed via the appropriate - template tag, only the comments for the current site are displayed. + :class:`~django.contrib.sites.models.Site` is set to the current site, + and when comments are listed via the appropriate template tag, only the + comments for the current site are displayed. * In the :mod:`flatpages framework <django.contrib.flatpages>`, each flatpage is associated with a particular site. When a flatpage is created, you specify its :class:`~django.contrib.sites.models.Site`, and the :class:`~django.contrib.flatpages.middleware.FlatpageFallbackMiddleware` - checks the current :setting:`SITE_ID` in retrieving flatpages to display. + checks the current site in retrieving flatpages to display. * In the :mod:`syndication framework <django.contrib.syndication>`, the templates for ``title`` and ``description`` automatically have access to a @@ -437,7 +420,7 @@ fallback when the database-backed sites framework is not available. Sets the ``name`` and ``domain`` attributes to the value of :meth:`~django.http.HttpRequest.get_host`. - + A :class:`~django.contrib.sites.models.RequestSite` object has a similar interface to a normal :class:`~django.contrib.sites.models.Site` object, except diff --git a/docs/ref/contrib/staticfiles.txt b/docs/ref/contrib/staticfiles.txt index cbe8ad54b8..3a74797145 100644 --- a/docs/ref/contrib/staticfiles.txt +++ b/docs/ref/contrib/staticfiles.txt @@ -5,8 +5,6 @@ The staticfiles app .. module:: django.contrib.staticfiles :synopsis: An app for handling static files. -.. versionadded:: 1.3 - ``django.contrib.staticfiles`` collects static files from each of your applications (and any other places you specify) into a single location that can easily be served in production. diff --git a/docs/ref/contrib/syndication.txt b/docs/ref/contrib/syndication.txt index 5653397748..27b8fc0875 100644 --- a/docs/ref/contrib/syndication.txt +++ b/docs/ref/contrib/syndication.txt @@ -455,7 +455,7 @@ This example illustrates all possible attributes and methods for a author_name = 'Sally Smith' # Hard-coded author name. - # AUTHOR E-MAIL --One of the following three is optional. The framework + # AUTHOR EMAIL --One of the following three is optional. The framework # looks for them in this order. def author_email(self, obj): @@ -635,7 +635,7 @@ This example illustrates all possible attributes and methods for a item_author_name = 'Sally Smith' # Hard-coded author name. - # ITEM AUTHOR E-MAIL --One of the following three is optional. The + # ITEM AUTHOR EMAIL --One of the following three is optional. The # framework looks for them in this order. # # If you specify this, you must specify item_author_name. diff --git a/docs/ref/databases.txt b/docs/ref/databases.txt index 3e256e9d9e..3a52f838e7 100644 --- a/docs/ref/databases.txt +++ b/docs/ref/databases.txt @@ -158,6 +158,16 @@ Since MySQL 5.5.5, the default storage engine is InnoDB_. This engine is fully transactional and supports foreign key references. It's probably the best choice at this point. +If you upgrade an existing project to MySQL 5.5.5 and subsequently add some +tables, ensure that your tables are using the same storage engine (i.e. MyISAM +vs. InnoDB). Specifically, if tables that have a ``ForeignKey`` between them +use different storage engines, you may see an error like the following when +running ``syncdb``:: + + _mysql_exceptions.OperationalError: ( + 1005, "Can't create table '\\db_name\\.#sql-4a8_ab' (errno: 150)" + ) + .. versionchanged:: 1.4 In previous versions of Django, fixtures with forward references (i.e. diff --git a/docs/ref/django-admin.txt b/docs/ref/django-admin.txt index 5ff7ecba2c..7fa7539985 100644 --- a/docs/ref/django-admin.txt +++ b/docs/ref/django-admin.txt @@ -176,8 +176,6 @@ records to dump. If you're using a :ref:`custom manager <custom-managers>` as the default manager and it filters some of the available records, not all of the objects will be dumped. -.. versionadded:: 1.3 - The :djadminopt:`--all` option may be provided to specify that ``dumpdata`` should use Django's base manager, dumping records which might otherwise be filtered or modified by a custom manager. @@ -195,18 +193,10 @@ easy for humans to read, so you can use the ``--indent`` option to pretty-print the output with a number of indentation spaces. The :djadminopt:`--exclude` option may be provided to prevent specific -applications from being dumped. - -.. versionadded:: 1.3 - -The :djadminopt:`--exclude` option may also be provided to prevent specific -models (specified as in the form of ``appname.ModelName``) from being dumped. - -In addition to specifying application names, you can provide a list of -individual models, in the form of ``appname.Model``. If you specify a model -name to ``dumpdata``, the dumped output will be restricted to that model, -rather than the entire application. You can also mix application names and -model names. +applications or models (specified as in the form of ``appname.ModelName``) from +being dumped. If you specify a model name to ``dumpdata``, the dumped output +will be restricted to that model, rather than the entire application. You can +also mix application names and model names. The :djadminopt:`--database` option can be used to specify the database from which data will be dumped. @@ -299,6 +289,11 @@ Searches for and loads the contents of the named fixture into the database. The :djadminopt:`--database` option can be used to specify the database onto which the data will be loaded. +.. versionadded:: 1.5 + +The :djadminopt:`--ignorenonexistent` option can be used to ignore fields that +may have been removed from models since the fixture was originally generated. + What's a "fixture"? ~~~~~~~~~~~~~~~~~~~ @@ -463,8 +458,6 @@ Use the ``--no-default-ignore`` option to disable the default values of .. django-admin-option:: --no-wrap -.. versionadded:: 1.3 - Use the ``--no-wrap`` option to disable breaking long message lines into several lines in language files. @@ -640,18 +633,14 @@ machines on your network. To make your development server viewable to other machines on the network, use its own IP address (e.g. ``192.168.2.1``) or ``0.0.0.0`` or ``::`` (with IPv6 enabled). -.. versionchanged:: 1.3 - You can provide an IPv6 address surrounded by brackets (e.g. ``[200a::1]:8000``). This will automatically enable IPv6 support. A hostname containing ASCII-only characters can also be used. -.. versionchanged:: 1.3 - If the :doc:`staticfiles</ref/contrib/staticfiles>` contrib app is enabled (default in new projects) the :djadmin:`runserver` command will be overriden -with an own :djadmin:`runserver<staticfiles-runserver>` command. +with its own :ref:`runserver<staticfiles-runserver>` command. .. django-admin-option:: --noreload @@ -674,8 +663,6 @@ development server. .. django-admin-option:: --ipv6, -6 -.. versionadded:: 1.3 - Use the ``--ipv6`` (or shorter ``-6``) option to tell Django to use IPv6 for the development server. This changes the default IP address from ``127.0.0.1`` to ``::1``. @@ -1113,8 +1100,6 @@ To run on 1.2.3.4:7000 with a ``test`` fixture:: django-admin.py testserver --addrport 1.2.3.4:7000 test -.. versionadded:: 1.3 - The :djadminopt:`--noinput` option may be provided to suppress all user prompts. diff --git a/docs/ref/files/storage.txt b/docs/ref/files/storage.txt index b3f8909847..f9bcf9b61e 100644 --- a/docs/ref/files/storage.txt +++ b/docs/ref/files/storage.txt @@ -18,7 +18,7 @@ Django provides two convenient ways to access the current storage class: .. function:: get_storage_class([import_path=None]) Returns a class or module which implements the storage API. - + When called without the ``import_path`` parameter ``get_storage_class`` will return the current default storage system as defined by :setting:`DEFAULT_FILE_STORAGE`. If ``import_path`` is provided, @@ -35,9 +35,9 @@ The FileSystemStorage Class basic file storage on a local filesystem. It inherits from :class:`~django.core.files.storage.Storage` and provides implementations for all the public methods thereof. - + .. note:: - + The :class:`FileSystemStorage.delete` method will not raise raise an exception if the given file name does not exist. @@ -53,16 +53,12 @@ The Storage Class .. method:: accessed_time(name) - .. versionadded:: 1.3 - Returns a ``datetime`` object containing the last accessed time of the file. For storage systems that aren't able to return the last accessed time this will raise ``NotImplementedError`` instead. .. method:: created_time(name) - .. versionadded:: 1.3 - Returns a ``datetime`` object containing the creation time of the file. For storage systems that aren't able to return the creation time this will raise ``NotImplementedError`` instead. @@ -100,8 +96,6 @@ The Storage Class .. method:: modified_time(name) - .. versionadded:: 1.3 - Returns a ``datetime`` object containing the last modified time. For storage systems that aren't able to return the last modified time, this will raise ``NotImplementedError`` instead. diff --git a/docs/ref/forms/api.txt b/docs/ref/forms/api.txt index 777d73e015..dffef314b7 100644 --- a/docs/ref/forms/api.txt +++ b/docs/ref/forms/api.txt @@ -105,7 +105,7 @@ Access the :attr:`~Form.errors` attribute to get a dictionary of error messages:: >>> f.errors - {'sender': [u'Enter a valid e-mail address.'], 'subject': [u'This field is required.']} + {'sender': [u'Enter a valid email address.'], 'subject': [u'This field is required.']} In this dictionary, the keys are the field names, and the values are lists of Unicode strings representing the error messages. The error messages are stored @@ -538,18 +538,18 @@ method you're using:: >>> print(f.as_table()) <tr><th>Subject:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="subject" maxlength="100" /></td></tr> <tr><th>Message:</th><td><input type="text" name="message" value="Hi there" /></td></tr> - <tr><th>Sender:</th><td><ul class="errorlist"><li>Enter a valid e-mail address.</li></ul><input type="text" name="sender" value="invalid email address" /></td></tr> + <tr><th>Sender:</th><td><ul class="errorlist"><li>Enter a valid email address.</li></ul><input type="text" name="sender" value="invalid email address" /></td></tr> <tr><th>Cc myself:</th><td><input checked="checked" type="checkbox" name="cc_myself" /></td></tr> >>> print(f.as_ul()) <li><ul class="errorlist"><li>This field is required.</li></ul>Subject: <input type="text" name="subject" maxlength="100" /></li> <li>Message: <input type="text" name="message" value="Hi there" /></li> - <li><ul class="errorlist"><li>Enter a valid e-mail address.</li></ul>Sender: <input type="text" name="sender" value="invalid email address" /></li> + <li><ul class="errorlist"><li>Enter a valid email address.</li></ul>Sender: <input type="text" name="sender" value="invalid email address" /></li> <li>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></li> >>> print(f.as_p()) <p><ul class="errorlist"><li>This field is required.</li></ul></p> <p>Subject: <input type="text" name="subject" maxlength="100" /></p> <p>Message: <input type="text" name="message" value="Hi there" /></p> - <p><ul class="errorlist"><li>Enter a valid e-mail address.</li></ul></p> + <p><ul class="errorlist"><li>Enter a valid email address.</li></ul></p> <p>Sender: <input type="text" name="sender" value="invalid email address" /></p> <p>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></p> @@ -572,7 +572,7 @@ pass that in at construction time:: <div class="errorlist"><div class="error">This field is required.</div></div> <p>Subject: <input type="text" name="subject" maxlength="100" /></p> <p>Message: <input type="text" name="message" value="Hi there" /></p> - <div class="errorlist"><div class="error">Enter a valid e-mail address.</div></div> + <div class="errorlist"><div class="error">Enter a valid email address.</div></div> <p>Sender: <input type="text" name="sender" value="invalid email address" /></p> <p>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></p> @@ -658,8 +658,6 @@ those classes as an argument:: .. method:: BoundField.value() - .. versionadded:: 1.3 - Use this method to render the raw value of this field as it would be rendered by a ``Widget``:: diff --git a/docs/ref/forms/fields.txt b/docs/ref/forms/fields.txt index 7c06bf97ee..7c8d509031 100644 --- a/docs/ref/forms/fields.txt +++ b/docs/ref/forms/fields.txt @@ -28,7 +28,7 @@ exception or returns the clean value:: >>> f.clean('invalid email address') Traceback (most recent call last): ... - ValidationError: [u'Enter a valid e-mail address.'] + ValidationError: [u'Enter a valid email address.'] Core field arguments -------------------- @@ -405,7 +405,7 @@ For each field, we describe the default widget used if you don't specify Additionally, if you specify :setting:`USE_L10N=False<USE_L10N>` in your settings, the following will also be included in the default input formats:: - '%b %m %d', # 'Oct 25 2006' + '%b %d %Y', # 'Oct 25 2006' '%b %d, %Y', # 'Oct 25, 2006' '%d %b %Y', # '25 Oct 2006' '%d %b, %Y', # '25 Oct, 2006' @@ -414,6 +414,8 @@ For each field, we describe the default widget used if you don't specify '%d %B %Y', # '25 October 2006' '%d %B, %Y', # '25 October, 2006' + See also :ref:`format localization <format-localization>`. + ``DateTimeField`` ~~~~~~~~~~~~~~~~~ @@ -445,6 +447,8 @@ For each field, we describe the default widget used if you don't specify '%m/%d/%y %H:%M', # '10/25/06 14:30' '%m/%d/%y', # '10/25/06' + See also :ref:`format localization <format-localization>`. + ``DecimalField`` ~~~~~~~~~~~~~~~~ @@ -704,8 +708,6 @@ For each field, we describe the default widget used if you don't specify ``TypedMultipleChoiceField`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 1.3 - .. class:: TypedMultipleChoiceField(**kwargs) Just like a :class:`MultipleChoiceField`, except :class:`TypedMultipleChoiceField` @@ -999,13 +1001,17 @@ objects (in the case of ``ModelMultipleChoiceField``) into the .. class:: ModelMultipleChoiceField(**kwargs) * Default widget: ``SelectMultiple`` - * Empty value: ``[]`` (an empty list) - * Normalizes to: A list of model instances. + * Empty value: An empty ``QuerySet`` (self.queryset.none()) + * Normalizes to: A ``QuerySet`` of model instances. * Validates that every id in the given list of values exists in the queryset. * Error message keys: ``required``, ``list``, ``invalid_choice``, ``invalid_pk_value`` + .. versionchanged:: 1.5 + The empty and normalized values were changed to be consistently + ``QuerySets`` instead of ``[]`` and ``QuerySet`` respectively. + Allows the selection of one or more model objects, suitable for representing a many-to-many relation. As with :class:`ModelChoiceField`, you can use ``label_from_instance`` to customize the object diff --git a/docs/ref/forms/validation.txt b/docs/ref/forms/validation.txt index 1af32da875..e89bce748f 100644 --- a/docs/ref/forms/validation.txt +++ b/docs/ref/forms/validation.txt @@ -185,7 +185,7 @@ a look at Django's ``EmailField``:: class EmailField(CharField): default_error_messages = { - 'invalid': _('Enter a valid e-mail address.'), + 'invalid': _('Enter a valid email address.'), } default_validators = [validators.validate_email] @@ -198,7 +198,7 @@ on field definition so:: is equivalent to:: email = forms.CharField(validators=[validators.validate_email], - error_messages={'invalid': _('Enter a valid e-mail address.')}) + error_messages={'invalid': _('Enter a valid email address.')}) Form field default cleaning diff --git a/docs/ref/forms/widgets.txt b/docs/ref/forms/widgets.txt index 4724cbdec2..3c458930fa 100644 --- a/docs/ref/forms/widgets.txt +++ b/docs/ref/forms/widgets.txt @@ -294,11 +294,6 @@ These widgets make use of the HTML elements ``input`` and ``textarea``. Determines whether the widget will have a value filled in when the form is re-displayed after a validation error (default is ``False``). - .. versionchanged:: 1.3 - The default value for - :attr:`~PasswordInput.render_value` was - changed from ``True`` to ``False`` - ``HiddenInput`` ~~~~~~~~~~~~~~~ @@ -532,8 +527,6 @@ File upload widgets .. class:: ClearableFileInput - .. versionadded:: 1.3 - File upload input: ``<input type='file' ...>``, with an additional checkbox input to clear the field's value, if the field is not required and has initial data. diff --git a/docs/ref/index.txt b/docs/ref/index.txt index 01a8ab22d1..e1959d44a6 100644 --- a/docs/ref/index.txt +++ b/docs/ref/index.txt @@ -6,7 +6,7 @@ API Reference :maxdepth: 1 authbackends - class-based-views/index + class-based-views/index clickjacking contrib/index databases @@ -22,5 +22,7 @@ API Reference signals templates/index unicode + urlresolvers + urls utils validators diff --git a/docs/ref/middleware.txt b/docs/ref/middleware.txt index a6ea9a6c41..b542aee6e2 100644 --- a/docs/ref/middleware.txt +++ b/docs/ref/middleware.txt @@ -93,8 +93,8 @@ GZip middleware Compresses content for browsers that understand GZip compression (all modern browsers). -It is suggested to place this first in the middleware list, so that the -compression of the response content is the last thing that happens. +This middleware should be placed before any other middleware that need to +read or write the response body so that compression happens afterward. It will NOT compress content if any of the following are true: @@ -203,9 +203,9 @@ Transaction middleware .. class:: TransactionMiddleware -Binds commit and rollback to the request/response phase. If a view function -runs successfully, a commit is done. If it fails with an exception, a rollback -is done. +Binds commit and rollback of the default database to the request/response +phase. If a view function runs successfully, a commit is done. If it fails with +an exception, a rollback is done. The order of this middleware in the stack is important: middleware modules running outside of it run with commit-on-save - the default Django behavior. diff --git a/docs/ref/models/fields.txt b/docs/ref/models/fields.txt index 8b3c31f029..809d56eaf5 100644 --- a/docs/ref/models/fields.txt +++ b/docs/ref/models/fields.txt @@ -668,6 +668,11 @@ the field. Note: This method will close the file if it happens to be open when The optional ``save`` argument controls whether or not the instance is saved after the file has been deleted. Defaults to ``True``. +Note that when a model is deleted, related files are not deleted. If you need +to cleanup orphaned files, you'll need to handle it yourself (for instance, +with a custom management command that can be run manually or scheduled to run +periodically via e.g. cron). + ``FilePathField`` ----------------- @@ -966,6 +971,12 @@ need to use:: This sort of reference can be useful when resolving circular import dependencies between two applications. +A database index is automatically created on the ``ForeignKey``. You can +disable this by setting :attr:`~Field.db_index` to ``False``. You may want to +avoid the overhead of an index if you are creating a foreign key for +consistency rather than joins, or if you will be creating an alternative index +like a partial or multiple column index. + Database Representation ~~~~~~~~~~~~~~~~~~~~~~~ @@ -1023,8 +1034,6 @@ define the details of how the relation works. The field on the related object that the relation is to. By default, Django uses the primary key of the related object. -.. versionadded:: 1.3 - .. attribute:: ForeignKey.on_delete When an object referenced by a :class:`ForeignKey` is deleted, Django by @@ -1081,6 +1090,9 @@ the model is related. This works exactly the same as it does for :class:`ForeignKey`, including all the options regarding :ref:`recursive <recursive-relationships>` and :ref:`lazy <lazy-relationships>` relationships. +Related objects can be added, removed, or created with the field's +:class:`~django.db.models.fields.related.RelatedManager`. + Database Representation ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/ref/models/instances.txt b/docs/ref/models/instances.txt index 2fdc87df8c..1ba41148b0 100644 --- a/docs/ref/models/instances.txt +++ b/docs/ref/models/instances.txt @@ -387,10 +387,11 @@ perform an update on all fields. Specifying ``update_fields`` will force an update. When saving a model fetched through deferred model loading -(:meth:`~Model.only()` or :meth:`~Model.defer()`) only the fields loaded from -the DB will get updated. In effect there is an automatic ``update_fields`` in -this case. If you assign or change any deferred field value, these fields will -be added to the updated fields. +(:meth:`~django.db.models.query.QuerySet.only()` or +:meth:`~django.db.models.query.QuerySet.defer()`) only the fields loaded +from the DB will get updated. In effect there is an automatic +``update_fields`` in this case. If you assign or change any deferred field +value, the field will be added to the updated fields. Deleting objects ================ @@ -493,12 +494,16 @@ defined. If it makes sense for your model's instances to each have a unique URL, you should define ``get_absolute_url()``. It's good practice to use ``get_absolute_url()`` in templates, instead of -hard-coding your objects' URLs. For example, this template code is bad:: +hard-coding your objects' URLs. For example, this template code is bad: + +.. code-block:: html+django <!-- BAD template code. Avoid! --> <a href="/people/{{ object.id }}/">{{ object.name }}</a> -This template code is much better:: +This template code is much better: + +.. code-block:: html+django <a href="{{ object.get_absolute_url }}">{{ object.name }}</a> @@ -534,7 +539,9 @@ pattern name) and a list of position or keyword arguments and uses the URLconf patterns to construct the correct, full URL. It returns a string for the correct URL, with all parameters substituted in the correct positions. -The ``permalink`` decorator is a Python-level equivalent to the :ttag:`url` template tag and a high-level wrapper for the :func:`django.core.urlresolvers.reverse()` function. +The ``permalink`` decorator is a Python-level equivalent to the :ttag:`url` +template tag and a high-level wrapper for the +:func:`django.core.urlresolvers.reverse()` function. An example should make it clear how to use ``permalink()``. Suppose your URLconf contains a line such as:: diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt index 8ec7cfc791..7138cd0e74 100644 --- a/docs/ref/models/querysets.txt +++ b/docs/ref/models/querysets.txt @@ -505,15 +505,8 @@ followed (optionally) by any output-affecting methods (such as ``values()``), but it doesn't really matter. This is your chance to really flaunt your individualism. -.. versionchanged:: 1.3 - -The ``values()`` method previously did not return anything for -:class:`~django.db.models.ManyToManyField` attributes and would raise an error -if you tried to pass this type of field to it. - -This restriction has been lifted, and you can now also refer to fields on -related models with reverse relations through ``OneToOneField``, ``ForeignKey`` -and ``ManyToManyField`` attributes:: +You can also refer to fields on related models with reverse relations through +``OneToOneField``, ``ForeignKey`` and ``ManyToManyField`` attributes:: Blog.objects.values('name', 'entry__headline') [{'name': 'My blog', 'entry__headline': 'An entry'}, @@ -1463,6 +1456,16 @@ evaluated will force it to evaluate again, repeating the query. Also, use of ``iterator()`` causes previous ``prefetch_related()`` calls to be ignored since these two optimizations do not make sense together. +.. warning:: + + Some Python database drivers like ``psycopg2`` perform caching if using + client side cursors (instantiated with ``connection.cursor()`` and what + Django's ORM uses). Using ``iterator()`` does not affect caching at the + database driver level. To disable this caching, look at `server side + cursors`_. + +.. _server side cursors: http://initd.org/psycopg/docs/usage.html#server-side-cursors + latest ~~~~~~ @@ -1571,7 +1574,8 @@ update .. method:: update(**kwargs) Performs an SQL update query for the specified fields, and returns -the number of rows affected. +the number of rows matched (which may not be equal to the number of rows +updated if some rows already have the new value). For example, to turn comments off for all blog entries published in 2010, you could do this:: @@ -1631,7 +1635,7 @@ does not call any ``save()`` methods on your models, nor does it emit the :attr:`~django.db.models.signals.post_save` signals (which are a consequence of calling :meth:`Model.save() <~django.db.models.Model.save()>`). If you want to update a bunch of records for a model that has a custom -:meth:`~django.db.models.Model.save()`` method, loop over them and call +:meth:`~django.db.models.Model.save()` method, loop over them and call :meth:`~django.db.models.Model.save()`, like this:: for e in Entry.objects.filter(pub_date__year=2010): @@ -1664,10 +1668,9 @@ For example:: # This will delete all Blogs and all of their Entry objects. blogs.delete() -.. versionadded:: 1.3 - This cascade behavior is customizable via the - :attr:`~django.db.models.ForeignKey.on_delete` argument to the - :class:`~django.db.models.ForeignKey`. +This cascade behavior is customizable via the +:attr:`~django.db.models.ForeignKey.on_delete` argument to the +:class:`~django.db.models.ForeignKey`. The ``delete()`` method does a bulk delete and does not call any ``delete()`` methods on your models. It does, however, emit the @@ -1675,6 +1678,21 @@ methods on your models. It does, however, emit the :data:`~django.db.models.signals.post_delete` signals for all deleted objects (including cascaded deletions). +.. versionadded:: 1.5 + Allow fast-path deletion of objects + +Django needs to fetch objects into memory to send signals and handle cascades. +However, if there are no cascades and no signals, then Django may take a +fast-path and delete objects without fetching into memory. For large +deletes this can result in significantly reduced memory usage. The amount of +executed queries can be reduced, too. + +ForeignKeys which are set to :attr:`~django.db.models.ForeignKey.on_delete` +DO_NOTHING do not prevent taking the fast-path in deletion. + +Note that the queries generated in object deletion is an implementation +detail subject to change. + .. _field-lookups: Field lookups diff --git a/docs/ref/request-response.txt b/docs/ref/request-response.txt index 21e99de10d..c3ba99168d 100644 --- a/docs/ref/request-response.txt +++ b/docs/ref/request-response.txt @@ -16,7 +16,8 @@ passing the :class:`HttpRequest` as the first argument to the view function. Each view is responsible for returning an :class:`HttpResponse` object. This document explains the APIs for :class:`HttpRequest` and -:class:`HttpResponse` objects. +:class:`HttpResponse` objects, which are defined in the :mod:`django.http` +module. HttpRequest objects =================== @@ -42,8 +43,6 @@ All attributes should be considered read-only, unless stated otherwise below. data in different ways than conventional HTML forms: binary images, XML payload etc. For processing conventional form data, use ``HttpRequest.POST``. - .. versionadded:: 1.3 - You can also read from an HttpRequest using a file-like interface. See :meth:`HttpRequest.read()`. @@ -93,8 +92,14 @@ All attributes should be considered read-only, unless stated otherwise below. .. attribute:: HttpRequest.POST - A dictionary-like object containing all given HTTP POST parameters. See the - :class:`QueryDict` documentation below. + A dictionary-like object containing all given HTTP POST parameters, + providing that the request contains form data. See the + :class:`QueryDict` documentation below. If you need to access raw or + non-form data posted in the request, access this through the + :attr:`HttpRequest.body` attribute instead. + + .. versionchanged:: 1.5 + Before Django 1.5, HttpRequest.POST contained non-form data. It's possible that a request can come in via POST with an empty ``POST`` dictionary -- if, say, a form is requested via the POST HTTP method but @@ -192,6 +197,17 @@ All attributes should be considered read-only, unless stated otherwise below. URLconf for the current request, overriding the :setting:`ROOT_URLCONF` setting. See :ref:`how-django-processes-a-request` for details. +.. attribute:: HttpRequest.resolver_match + + .. versionadded:: 1.5 + + An instance of :class:`~django.core.urlresolvers.ResolverMatch` representing + the resolved url. This attribute is only set after url resolving took place, + which means it's available in all views but not in middleware methods which + are executed before url resolving takes place (like ``process_request``, you + can use ``process_view`` instead). + + Methods ------- @@ -305,8 +321,6 @@ Methods .. method:: HttpRequest.xreadlines() .. method:: HttpRequest.__iter__() - .. versionadded:: 1.3 - Methods implementing a file-like interface for reading from an HttpRequest instance. This makes it possible to consume an incoming request in a streaming fashion. A common use-case would be to process a @@ -509,9 +523,6 @@ In addition, ``QueryDict`` has the following methods: >>> q.urlencode() 'a=2&b=3&b=5' - .. versionchanged:: 1.3 - The ``safe`` parameter was added. - Optionally, urlencode can be passed characters which do not require encoding. For example:: @@ -555,13 +566,28 @@ file-like object:: Passing iterators ~~~~~~~~~~~~~~~~~ -Finally, you can pass ``HttpResponse`` an iterator rather than passing it -hard-coded strings. If you use this technique, follow these guidelines: +Finally, you can pass ``HttpResponse`` an iterator rather than strings. If you +use this technique, the iterator should return strings. + +Passing an iterator as content to :class:`HttpResponse` creates a +streaming response if (and only if) no middleware accesses the +:attr:`HttpResponse.content` attribute before the response is returned. + +.. versionchanged:: 1.5 + +This technique is fragile and was deprecated in Django 1.5. If you need the +response to be streamed from the iterator to the client, you should use the +:class:`StreamingHttpResponse` class instead. -* The iterator should return strings. -* If an :class:`HttpResponse` has been initialized with an iterator as its - content, you can't use the :class:`HttpResponse` instance as a file-like - object. Doing so will raise ``Exception``. +As of Django 1.7, when :class:`HttpResponse` is instantiated with an +iterator, it will consume it immediately, store the response content as a +string, and discard the iterator. + +.. versionchanged:: 1.5 + +You can now use :class:`HttpResponse` as a file-like object even if it was +instantiated with an iterator. Django will consume and save the content of +the iterator on first access. Setting headers ~~~~~~~~~~~~~~~ @@ -586,7 +612,7 @@ To tell the browser to treat the response as a file attachment, use the this is how you might return a Microsoft Excel spreadsheet:: >>> response = HttpResponse(my_data, content_type='application/vnd.ms-excel') - >>> response['Content-Disposition'] = 'attachment; filename=foo.xls' + >>> response['Content-Disposition'] = 'attachment; filename="foo.xls"' There's nothing Django-specific about the ``Content-Disposition`` header, but it's easy to forget the syntax, so we've included it here. @@ -603,6 +629,13 @@ Attributes The `HTTP Status code`_ for the response. +.. attribute:: HttpResponse.streaming + + This is always ``False``. + + This attribute exists so middleware can treat streaming responses + differently from regular responses. + Methods ------- @@ -646,17 +679,7 @@ Methods Returns ``True`` or ``False`` based on a case-insensitive check for a header with the given name. -.. method:: HttpResponse.set_cookie(key, value='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=True) - - .. versionchanged:: 1.3 - - The possibility of specifying a ``datetime.datetime`` object in - ``expires``, and the auto-calculation of ``max_age`` in such case - was added. The ``httponly`` argument was also added. - - .. versionchanged:: 1.4 - - The default value for httponly was changed from ``False`` to ``True``. +.. method:: HttpResponse.set_cookie(key, value='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=False) Sets a cookie. The parameters are the same as in the :class:`Cookie.Morsel` object in the Python standard library. @@ -780,3 +803,60 @@ types of HTTP responses. Like ``HttpResponse``, these subclasses live in method, Django will treat it as emulating a :class:`~django.template.response.SimpleTemplateResponse`, and the ``render`` method must itself return a valid response object. + +StreamingHttpResponse objects +============================= + +.. versionadded:: 1.5 + +.. class:: StreamingHttpResponse + +The :class:`StreamingHttpResponse` class is used to stream a response from +Django to the browser. You might want to do this if generating the response +takes too long or uses too much memory. For instance, it's useful for +generating large CSV files. + +.. admonition:: Performance considerations + + Django is designed for short-lived requests. Streaming responses will tie + a worker process and keep a database connection idle in transaction for + the entire duration of the response. This may result in poor performance. + + Generally speaking, you should perform expensive tasks outside of the + request-response cycle, rather than resorting to a streamed response. + +The :class:`StreamingHttpResponse` is not a subclass of :class:`HttpResponse`, +because it features a slightly different API. However, it is almost identical, +with the following notable differences: + +* It should be given an iterator that yields strings as content. + +* You cannot access its content, except by iterating the response object + itself. This should only occur when the response is returned to the client. + +* It has no ``content`` attribute. Instead, it has a + :attr:`~StreamingHttpResponse.streaming_content` attribute. + +* You cannot use the file-like object ``tell()`` or ``write()`` methods. + Doing so will raise an exception. + +:class:`StreamingHttpResponse` should only be used in situations where it is +absolutely required that the whole content isn't iterated before transferring +the data to the client. Because the content can't be accessed, many +middlewares can't function normally. For example the ``ETag`` and ``Content- +Length`` headers can't be generated for streaming responses. + +Attributes +---------- + +.. attribute:: StreamingHttpResponse.streaming_content + + An iterator of strings representing the content. + +.. attribute:: HttpResponse.status_code + + The `HTTP Status code`_ for the response. + +.. attribute:: HttpResponse.streaming + + This is always ``True``. diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt index 16d067172d..a909c12665 100644 --- a/docs/ref/settings.txt +++ b/docs/ref/settings.txt @@ -110,23 +110,20 @@ A tuple of authentication backend classes (as strings) to use when attempting to authenticate a user. See the :doc:`authentication backends documentation </ref/authbackends>` for details. -.. setting:: AUTH_PROFILE_MODULE +.. setting:: AUTH_USER_MODEL -AUTH_PROFILE_MODULE -------------------- +AUTH_USER_MODEL +--------------- -Default: Not defined +Default: 'auth.User' -The site-specific user profile model used by this site. See -:ref:`auth-profiles`. +The model to use to represent a User. See :ref:`auth-custom-user`. .. setting:: CACHES CACHES ------ -.. versionadded:: 1.3 - Default:: { @@ -167,12 +164,6 @@ backend class (i.e. ``mypackage.backends.whatever.WhateverCache``). Writing a whole new cache backend from scratch is left as an exercise to the reader; see the other backends for examples. -.. note:: - Prior to Django 1.3, you could use a URI based version of the backend - name to reference the built-in cache backends (e.g., you could use - ``'db://tablename'`` to refer to the database backend). This format has - been deprecated, and will be removed in Django 1.5. - .. setting:: CACHES-KEY_FUNCTION KEY_FUNCTION @@ -534,8 +525,6 @@ Only supported for the ``mysql`` backend (see the `MySQL manual`_ for details). TEST_DEPENDENCIES ~~~~~~~~~~~~~~~~~ -.. versionadded:: 1.3 - Default: ``['default']``, for all databases other than ``default``, which has no dependencies. @@ -1262,8 +1251,6 @@ the ``locale`` directory (i.e. ``'/path/to/locale'``). LOGGING ------- -.. versionadded:: 1.3 - Default: A logging configuration dictionary. A data structure containing configuration information. The contents of @@ -1278,8 +1265,6 @@ email log handler; all other log messages are given to a NullHandler. LOGGING_CONFIG -------------- -.. versionadded:: 1.3 - Default: ``'django.utils.log.dictConfig'`` A path to a callable that will be used to configure logging in the @@ -1371,13 +1356,11 @@ MEDIA_URL Default: ``''`` (Empty string) URL that handles the media served from :setting:`MEDIA_ROOT`, used -for :doc:`managing stored files </topics/files>`. +for :doc:`managing stored files </topics/files>`. It must end in a slash if set +to a non-empty value. Example: ``"http://media.example.com/"`` -.. versionchanged:: 1.3 - It must end in a slash if set to a non-empty value. - MESSAGE_LEVEL ------------- @@ -1896,10 +1879,6 @@ A tuple of callables that are used to populate the context in ``RequestContext`` These callables take a request object as their argument and return a dictionary of items to be merged into the context. -.. versionadded:: 1.3 - The ``django.core.context_processors.static`` context processor - was added in this release. - .. versionadded:: 1.4 The ``django.core.context_processors.tz`` context processor was added in this release. @@ -2160,8 +2139,6 @@ See also :setting:`TIME_ZONE`, :setting:`USE_I18N` and :setting:`USE_L10N`. USE_X_FORWARDED_HOST -------------------- -.. versionadded:: 1.3.1 - Default: ``False`` A boolean that specifies whether to use the X-Forwarded-Host header in @@ -2231,6 +2208,22 @@ ADMIN_MEDIA_PREFIX integration. See the :doc:`Django 1.4 release notes</releases/1.4>` for more information. +.. setting:: AUTH_PROFILE_MODULE + +AUTH_PROFILE_MODULE +------------------- + +.. deprecated:: 1.5 + With the introduction of :ref:`custom User models <auth-custom-user>`, + the use of :setting:`AUTH_PROFILE_MODULE` to define a single profile + model is no longer supported. See the + :doc:`Django 1.5 release notes</releases/1.5>` for more information. + +Default: Not defined + +The site-specific user profile model used by this site. See +:ref:`auth-profiles`. + .. setting:: IGNORABLE_404_ENDS IGNORABLE_404_ENDS diff --git a/docs/ref/signals.txt b/docs/ref/signals.txt index b2f2e85abc..0db540370d 100644 --- a/docs/ref/signals.txt +++ b/docs/ref/signals.txt @@ -46,7 +46,7 @@ pre_init .. ^^^^^^^ this :module: hack keeps Sphinx from prepending the module. -Whenever you instantiate a Django model,, this signal is sent at the beginning +Whenever you instantiate a Django model, this signal is sent at the beginning of the model's :meth:`~django.db.models.Model.__init__` method. Arguments sent with this signal: @@ -118,8 +118,6 @@ Arguments sent with this signal: records in the database as the database might not be in a consistent state yet. -.. versionadded:: 1.3 - ``using`` The database alias being used. @@ -155,8 +153,6 @@ Arguments sent with this signal: records in the database as the database might not be in a consistent state yet. -.. versionadded:: 1.3 - ``using`` The database alias being used. @@ -183,8 +179,6 @@ Arguments sent with this signal: ``instance`` The actual instance being deleted. -.. versionadded:: 1.3 - ``using`` The database alias being used. @@ -209,8 +203,6 @@ Arguments sent with this signal: Note that the object will no longer be in the database, so be very careful what you do with this instance. -.. versionadded:: 1.3 - ``using`` The database alias being used. @@ -271,8 +263,6 @@ Arguments sent with this signal: For the ``pre_clear`` and ``post_clear`` actions, this is ``None``. -.. versionadded:: 1.3 - ``using`` The database alias being used. @@ -287,13 +277,22 @@ like this:: # ... toppings = models.ManyToManyField(Topping) -If we would do something like this: +If we connected a handler like this:: + + def toppings_changed(sender, **kwargs): + # Do something + pass + + m2m_changed.connect(toppings_changed, sender=Pizza.toppings.through) + +and then did something like this:: >>> p = Pizza.object.create(...) >>> t = Topping.objects.create(...) >>> p.toppings.add(t) -the arguments sent to a :data:`m2m_changed` handler would be: +the arguments sent to a :data:`m2m_changed` handler (``topppings_changed`` in +the example above) would be: ============== ============================================================ Argument Value diff --git a/docs/ref/template-response.txt b/docs/ref/template-response.txt index 9e09077adc..d9b7130362 100644 --- a/docs/ref/template-response.txt +++ b/docs/ref/template-response.txt @@ -2,8 +2,6 @@ TemplateResponse and SimpleTemplateResponse =========================================== -.. versionadded:: 1.3 - .. module:: django.template.response :synopsis: Classes dealing with lazy-rendered HTTP responses. diff --git a/docs/ref/templates/api.txt b/docs/ref/templates/api.txt index 48bd346788..db57d2de96 100644 --- a/docs/ref/templates/api.txt +++ b/docs/ref/templates/api.txt @@ -160,11 +160,6 @@ it. Example:: >>> t.render(Context({"person": PersonClass2})) "My name is Samantha." -.. versionchanged:: 1.3 - Previously, only variables that originated with an attribute lookup would - be called by the template system. This change was made for consistency - across lookup types. - Callable variables are slightly more complex than variables which only require straight lookups. Here are some things to keep in mind: @@ -438,7 +433,7 @@ django.contrib.auth.context_processors.auth ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If :setting:`TEMPLATE_CONTEXT_PROCESSORS` contains this processor, every -``RequestContext`` will contain these three variables: +``RequestContext`` will contain these variables: * ``user`` -- An ``auth.User`` instance representing the currently logged-in user (or an ``AnonymousUser`` instance, if the client isn't @@ -448,11 +443,6 @@ If :setting:`TEMPLATE_CONTEXT_PROCESSORS` contains this processor, every ``django.contrib.auth.context_processors.PermWrapper``, representing the permissions that the currently logged-in user has. -.. versionchanged:: 1.3 - Prior to version 1.3, ``PermWrapper`` was located in - ``django.contrib.auth.context_processors``. - - django.core.context_processors.debug ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -491,8 +481,6 @@ django.core.context_processors.static .. function:: django.core.context_processors.static -.. versionadded:: 1.3 - If :setting:`TEMPLATE_CONTEXT_PROCESSORS` contains this processor, every ``RequestContext`` will contain a variable ``STATIC_URL``, providing the value of the :setting:`STATIC_URL` setting. diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt index 072eebf69f..3b8d058fb4 100644 --- a/docs/ref/templates/builtins.txt +++ b/docs/ref/templates/builtins.txt @@ -156,8 +156,6 @@ In this syntax, each value gets interpreted as a literal string, and there's no way to specify variable values. Or literal commas. Or spaces. Did we mention you shouldn't use this syntax in any new projects? -.. versionadded:: 1.3 - By default, when you use the ``as`` keyword with the cycle tag, the usage of ``{% cycle %}`` that declares the cycle will itself output the first value in the cycle. This could be a problem if you want to @@ -676,9 +674,6 @@ including it. This example produces the output ``"Hello, John"``: {{ greeting }}, {{ person|default:"friend" }}! -.. versionchanged:: 1.3 - Additional context and exclusive context. - You can pass additional context to the template using keyword arguments:: {% include "name_snippet.html" with person="Jane" greeting="Hello" %} @@ -710,8 +705,6 @@ registered in ``somelibrary`` and ``otherlibrary`` located in package {% load somelibrary package.otherlibrary %} -.. versionchanged:: 1.3 - You can also selectively load individual filters or tags from a library, using the ``from`` argument. In this example, the template tags/filters named ``foo`` and ``bar`` will be loaded from ``somelibrary``:: @@ -1004,7 +997,7 @@ refer to the name of the pattern in the ``url`` tag instead of using the path to the view. Note that if the URL you're reversing doesn't exist, you'll get an -:exc:`^django.core.urlresolvers.NoReverseMatch` exception raised, which will +:exc:`~django.core.urlresolvers.NoReverseMatch` exception raised, which will cause your site to display an error page. If you'd like to retrieve a URL without displaying it, you can use a slightly @@ -1076,9 +1069,6 @@ which is rounded up to 88). with ^^^^ -.. versionchanged:: 1.3 - New keyword argument format and multiple variable assignments. - Caches a complex variable under a simpler name. This is useful when accessing an "expensive" method (e.g., one that hits the database) multiple times. @@ -1261,7 +1251,7 @@ S English ordinal suffix for day of the ``'st'``, ``'nd'``, month, 2 characters. t Number of days in the given month. ``28`` to ``31`` T Time zone of this machine. ``'EST'``, ``'MDT'`` -u Microseconds. ``0`` to ``999999`` +u Microseconds. ``000000`` to ``999999`` U Seconds since the Unix Epoch (January 1 1970 00:00:00 UTC). w Day of the week, digits without ``'0'`` (Sunday) to ``'6'`` (Saturday) @@ -2126,8 +2116,6 @@ For example:: If ``value`` is ``"http://www.example.org/foo?a=b&c=d"``, the output will be ``"http%3A//www.example.org/foo%3Fa%3Db%26c%3Dd"``. -.. versionadded:: 1.3 - An optional argument containing the characters which should not be escaped can be provided. diff --git a/docs/ref/urlresolvers.txt b/docs/ref/urlresolvers.txt new file mode 100644 index 0000000000..1bb33c7ca1 --- /dev/null +++ b/docs/ref/urlresolvers.txt @@ -0,0 +1,202 @@ +============================================== +``django.core.urlresolvers`` utility functions +============================================== + +.. module:: django.core.urlresolvers + +reverse() +--------- + +If you need to use something similar to the :ttag:`url` template tag in +your code, Django provides the following function: + +.. 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 +:ref:`URL pattern name <naming-url-patterns>`. Normally, you won't need to +worry about the ``urlconf`` parameter and will only pass in the positional and +keyword arguments to use in the URL matching. For example:: + + from django.core.urlresolvers import reverse + + def myview(request): + return HttpResponseRedirect(reverse('arch-summary', args=[1945])) + +The ``reverse()`` function can reverse a large variety of regular expression +patterns for URLs, but not every possible one. The main restriction at the +moment is that the pattern cannot contain alternative choices using the +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. + +The ``current_app`` argument allows you to provide a hint to the resolver +indicating the application to which the currently executing view belongs. +This ``current_app`` argument is used as a hint to resolve application +namespaces into URLs on specific application instances, according to the +:ref:`namespaced URL resolution strategy <topics-http-reversing-url-namespaces>`. + +You can use ``kwargs`` instead of ``args``. For example:: + + >>> reverse('admin:app_list', kwargs={'app_label': 'auth'}) + '/admin/auth/' + +``args`` and ``kwargs`` cannot be passed to ``reverse()`` at the same time. + +.. admonition:: Make sure your views are all correct. + + As part of working out which URL names map to which patterns, the + ``reverse()`` function has to import all of your URLconf files and examine + the name of each view. This involves importing each view function. If + there are *any* errors whilst importing any of your view functions, it + will cause ``reverse()`` to raise an error, even if that view function is + not the one you are trying to reverse. + + Make sure that any views you reference in your URLconf files exist and can + be imported correctly. Do not include lines that reference views you + haven't written yet, because those views will not be importable. + +.. note:: + + The string returned by ``reverse()`` is already + :ref:`urlquoted <uri-and-iri-handling>`. For example:: + + >>> reverse('cities', args=[u'Orléans']) + '.../Orl%C3%A9ans/' + + Applying further encoding (such as :meth:`~django.utils.http.urlquote` or + ``urllib.quote``) to the output of ``reverse()`` may produce undesirable + results. + +reverse_lazy() +-------------- + +.. versionadded:: 1.4 + +A lazily evaluated version of `reverse()`_. + +.. function:: reverse_lazy(viewname, [urlconf=None, args=None, kwargs=None, current_app=None]) + +It is useful for when you need to use a URL reversal before your project's +URLConf is loaded. Some common cases where this function is necessary are: + +* providing a reversed URL as the ``url`` attribute of a generic class-based + view. + +* providing a reversed URL to a decorator (such as the ``login_url`` argument + for the :func:`django.contrib.auth.decorators.permission_required` + decorator). + +* providing a reversed URL as a default value for a parameter in a function's + signature. + +resolve() +--------- + +The ``resolve()`` function can be used for resolving URL paths to the +corresponding view functions. It has the following signature: + +.. function:: resolve(path, urlconf=None) + +``path`` is the URL path you want to resolve. As with +:func:`~django.core.urlresolvers.reverse`, you don't need to +worry about the ``urlconf`` parameter. The function returns a +:class:`ResolverMatch` object that allows you +to access various meta-data about the resolved URL. + +If the URL does not resolve, the function raises an +:class:`~django.http.Http404` exception. + +.. class:: ResolverMatch + + .. attribute:: ResolverMatch.func + + The view function that would be used to serve the URL + + .. attribute:: ResolverMatch.args + + The arguments that would be passed to the view function, as + parsed from the URL. + + .. attribute:: ResolverMatch.kwargs + + The keyword arguments that would be passed to the view + function, as parsed from the URL. + + .. attribute:: ResolverMatch.url_name + + The name of the URL pattern that matches the URL. + + .. attribute:: ResolverMatch.app_name + + The application namespace for the URL pattern that matches the + URL. + + .. attribute:: ResolverMatch.namespace + + The instance namespace for the URL pattern that matches the + URL. + + .. attribute:: ResolverMatch.namespaces + + The list of individual namespace components in the full + instance namespace for the URL pattern that matches the URL. + i.e., if the namespace is ``foo:bar``, then namespaces will be + ``['foo', 'bar']``. + +A :class:`ResolverMatch` object can then be interrogated to provide +information about the URL pattern that matches a URL:: + + # Resolve a URL + match = resolve('/some/path/') + # Print the URL pattern that matches the URL + print(match.url_name) + +A :class:`ResolverMatch` object can also be assigned to a triple:: + + func, args, kwargs = resolve('/some/path/') + +One possible use of :func:`~django.core.urlresolvers.resolve` would be to test +whether a view would raise a ``Http404`` error before redirecting to it:: + + from urlparse import urlparse + from django.core.urlresolvers import resolve + from django.http import HttpResponseRedirect, Http404 + + def myview(request): + next = request.META.get('HTTP_REFERER', None) or '/' + response = HttpResponseRedirect(next) + + # modify the request and response as required, e.g. change locale + # and set corresponding locale cookie + + view, args, kwargs = resolve(urlparse(next)[2]) + kwargs['request'] = request + try: + view(*args, **kwargs) + except Http404: + return HttpResponseRedirect('/') + return response + + +permalink() +----------- + +The :func:`~django.db.models.permalink` decorator is useful for writing short +methods that return a full URL path. For example, a model's +``get_absolute_url()`` method. See :func:`django.db.models.permalink` for more. + +get_script_prefix() +------------------- + +.. function:: get_script_prefix() + +Normally, you should always use :func:`~django.core.urlresolvers.reverse` or +:func:`~django.db.models.permalink` to define URLs within your application. +However, if your application constructs part of the URL hierarchy itself, you +may occasionally need to generate URLs. In that case, you need to be able to +find the base URL of the Django project within its Web server +(normally, :func:`~django.core.urlresolvers.reverse` takes care of this for +you). In that case, you can call ``get_script_prefix()``, which will return the +script prefix portion of the URL for your Django project. If your Django +project is at the root of its Web server, this is always ``"/"``. diff --git a/docs/ref/urls.txt b/docs/ref/urls.txt new file mode 100644 index 0000000000..b9a0199984 --- /dev/null +++ b/docs/ref/urls.txt @@ -0,0 +1,156 @@ +====================================== +``django.conf.urls`` utility functions +====================================== + +.. module:: django.conf.urls + +.. versionchanged:: 1.4 + Starting with Django 1.4 functions ``patterns``, ``url``, ``include`` plus + the ``handler*`` symbols described below live in the ``django.conf.urls`` + module. + + Until Django 1.3 they were located in ``django.conf.urls.defaults``. You + still can import them from there but it will be removed in Django 1.6. + +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 +:ref:`The view prefix <urlpatterns-view-prefix>`. + +The remaining arguments should be tuples in this format:: + + (regular expression, Python callback function [, optional_dictionary [, optional_name]]) + +The ``optional_dictionary`` and ``optional_name`` parameters are described in +:ref:`Passing extra options to view functions <views-extra-options>`. + +.. note:: + Because `patterns()` is a function call, it accepts a maximum of 255 + arguments (URL patterns, in this case). This is a limit for all Python + function calls. This is rarely a problem in practice, because you'll + typically structure your URL patterns modularly by using `include()` + sections. However, on the off-chance you do hit the 255-argument limit, + realize that `patterns()` returns a Python list, so you can split up the + construction of the list. + + :: + + urlpatterns = patterns('', + ... + ) + urlpatterns += patterns('', + ... + ) + + Python lists have unlimited size, so there's no limit to how many URL + patterns you can construct. The only limit is that you can only create 254 + at a time (the 255th argument is the initial prefix argument). + +url() +----- + +.. 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:: + + urlpatterns = patterns('', + url(r'^index/$', index_view, name="main-view"), + ... + ) + +This function takes five arguments, most of which are optional:: + + url(regex, view, kwargs=None, name=None, prefix='') + +See :ref:`Naming URL patterns <naming-url-patterns>` for why the ``name`` +parameter is useful. + +The ``prefix`` parameter has the same meaning as the first argument to +``patterns()`` and is only relevant when you're passing a string as the +``view`` parameter. + +include() +--------- + +.. function:: include(module[, namespace=None, app_name=None]) + include(pattern_list) + include((pattern_list, app_namespace, instance_namespace)) + + A function that takes a full Python import path to another URLconf module + that should be "included" in this place. Optionally, the :term:`application + namespace` and :term:`instance namespace` where the entries will be included + into can also be specified. + + ``include()`` also accepts as an argument either an iterable that returns + URL patterns or a 3-tuple containing such iterable plus the names of the + application and instance namespaces. + + :arg module: URLconf module (or module name) + :type module: Module or string + :arg namespace: Instance namespace for the URL entries being included + :type namespace: string + :arg app_name: Application namespace for the URL entries being included + :type app_name: string + :arg pattern_list: Iterable of URL entries as returned by :func:`patterns` + :arg app_namespace: Application namespace for the URL entries being included + :type app_namespace: string + :arg instance_namespace: Instance namespace for the URL entries being included + :type instance_namespace: string + +See :ref:`including-other-urlconfs` and :ref:`namespaces-and-include`. + +handler403 +---------- + +.. data:: handler403 + +A callable, or a string representing the full Python import path to the view +that should be called if the user doesn't have the permissions required to +access a resource. + +By default, this is ``'django.views.defaults.permission_denied'``. That default +value should suffice. + +See the documentation about :ref:`the 403 (HTTP Forbidden) view +<http_forbidden_view>` for more information. + +.. versionadded:: 1.4 + ``handler403`` is new in Django 1.4. + +handler404 +---------- + +.. data:: handler404 + +A callable, or a string representing the full Python import path to the view +that should be called if none of the URL patterns match. + +By default, this is ``'django.views.defaults.page_not_found'``. That default +value should suffice. + +See the documentation about :ref:`the 404 (HTTP Not Found) view +<http_not_found_view>` for more information. + +handler500 +---------- + +.. data:: handler500 + +A callable, or 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. + +By default, this is ``'django.views.defaults.server_error'``. That default +value should suffice. + +See the documentation about :ref:`the 500 (HTTP Internal Server Error) view +<http_internal_server_error_view>` for more information. + diff --git a/docs/ref/utils.txt b/docs/ref/utils.txt index de19578cac..bd3898172a 100644 --- a/docs/ref/utils.txt +++ b/docs/ref/utils.txt @@ -170,6 +170,37 @@ The functions defined in this module share the following properties: ``tzinfo`` attribute is a :class:`~django.utils.tzinfo.FixedOffset` instance. +``django.utils.decorators`` +=========================== + +.. module:: django.utils.decorators + :synopsis: Functions that help with creating decorators for views. + +.. function:: method_decorator(decorator) + + Converts a function decorator into a method decorator. See :ref:`decorating + class based views<decorating-class-based-views>` for example usage. + +.. function:: decorator_from_middleware(middleware_class) + + Given a middleware class, returns a view decorator. This lets you use + middleware functionality on a per-view basis. The middleware is created + with no params passed. + +.. function:: decorator_from_middleware_with_args(middleware_class) + + Like ``decorator_from_middleware``, but returns a function + that accepts the arguments to be passed to the middleware_class. + For example, the :func:`~django.views.decorators.cache.cache_page` + decorator is created from the + :class:`~django.middleware.cache.CacheMiddleware` like this:: + + cache_page = decorator_from_middleware_with_args(CacheMiddleware) + + @cache_page(3600) + def my_view(request): + pass + ``django.utils.encoding`` ========================= diff --git a/docs/releases/1.4.2.txt b/docs/releases/1.4.2.txt index 6f2e9aca2e..07eec39764 100644 --- a/docs/releases/1.4.2.txt +++ b/docs/releases/1.4.2.txt @@ -2,13 +2,54 @@ Django 1.4.2 release notes ========================== -*TO BE RELEASED* +*October 17, 2012* This is the second security release in the Django 1.4 series. +Host header poisoning +--------------------- + +Some parts of Django -- independent of end-user-written applications -- make +use of full URLs, including domain name, which are generated from the HTTP Host +header. Some attacks against this are beyond Django's ability to control, and +require the web server to be properly configured; Django's documentation has +for some time contained notes advising users on such configuration. + +Django's own built-in parsing of the Host header is, however, still vulnerable, +as was reported to us recently. The Host header parsing in Django 1.3.3 and +Django 1.4.1 -- specifically, django.http.HttpRequest.get_host() -- was +incorrectly handling username/password information in the header. Thus, for +example, the following Host header would be accepted by Django when running on +"validsite.com":: + + Host: validsite.com:random@evilsite.com + +Using this, an attacker can cause parts of Django -- particularly the +password-reset mechanism -- to generate and display arbitrary URLs to users. + +To remedy this, the parsing in HttpRequest.get_host() is being modified; Host +headers which contain potentially dangerous content (such as username/password +pairs) now raise the exception django.core.exceptions.SuspiciousOperation + +Details of this issue were initially posted online as a `security advisory`_. + +.. _security advisory: https://www.djangoproject.com/weblog/2012/oct/17/security/ + Backwards incompatible changes ============================== * The newly introduced :class:`~django.db.models.GenericIPAddressField` constructor arguments have been adapted to match those of all other model fields. The first two keyword arguments are now verbose_name and name. + +Other bugfixes and changes +========================== + +* Subclass HTMLParser only for appropriate Python versions (#18239). +* Added batch_size argument to qs.bulk_create() (#17788). +* Fixed a small regression in the admin filters where wrongly formatted dates passed as url parameters caused an unhandled ValidationError (#18530). +* Fixed an endless loop bug when accessing permissions in templates (#18979) +* Fixed some Python 2.5 compatibility issues +* Fixed an issue with quoted filenames in Content-Disposition header (#19006) +* Made the context option in ``trans`` and ``blocktrans`` tags accept literals wrapped in single quotes (#18881). +* Numerous documentation improvements and fixes. diff --git a/docs/releases/1.5-alpha-1.txt b/docs/releases/1.5-alpha-1.txt new file mode 100644 index 0000000000..8f027c6859 --- /dev/null +++ b/docs/releases/1.5-alpha-1.txt @@ -0,0 +1,631 @@ +============================================ +Django 1.5 release notes - UNDER DEVELOPMENT +============================================ + +October 25, 2012. + +Welcome to Django 1.5 alpha! + +This is the first in a series of preview/development releases leading up to the +eventual release of Django 1.5, scheduled for December 2012. This release is +primarily targeted at developers who are interested in trying out new features +and testing the Django codebase to help identify and resolve bugs prior to the +final 1.5 release. + +As such, this release is *not* intended for production use, and any such use +is discouraged. + +In particular, we need the community's help to test Django 1.5's new `Python 3 +support`_ -- not just to report bugs on Python 3, but also regressions on Python +2. While Django is very conservative with regards to backwards compatibility, +mistakes are always possible, and it's likely that the Python 3 refactoring work +introduced some regressions. + +Django 1.5 alpha includes various `new features`_ and some minor `backwards +incompatible changes`_. There are also some features that have been dropped, +which are detailed in :doc:`our deprecation plan </internals/deprecation>`, +and we've `begun the deprecation process for some features`_. + +.. _`new features`: `What's new in Django 1.5`_ +.. _`backwards incompatible changes`: `Backwards incompatible changes in 1.5`_ +.. _`begun the deprecation process for some features`: `Features deprecated in 1.5`_ + +Overview +======== + +The biggest new feature in Django 1.5 is the `configurable User model`_. Before +Django 1.5, applications that wanted to use Django's auth framework +(:mod:`django.contrib.auth`) were forced to use Django's definition of a "user". +In Django 1.5, you can now swap out the ``User`` model for one that you write +yourself. This could be a simple extension to the existing ``User`` model -- for +example, you could add a Twitter or Facebook ID field -- or you could completely +replace the ``User`` with one totally customized for your site. + +Django 1.5 is also the first release with `Python 3 support`_! We're labeling +this support "experimental" because we don't yet consider it production-ready, +but everything's in place for you to start porting your apps to Python 3. +Our next release, Django 1.6, will support Python 3 without reservations. + +Other notable new features in Django 1.5 include: + +* `Support for saving a subset of model's fields`_ - + :meth:`Model.save() <django.db.models.Model.save()>` now accepts an + ``update_fields`` argument, letting you specify which fields are + written back to the databse when you call ``save()``. This can help + in high-concurrancy operations, and can improve performance. + +* Better `support for streaming responses <#explicit-streaming-responses>`_ via + the new :class:`~django.http.StreamingHttpResponse` response class. + +* `GeoDjango`_ now supports PostGIS 2.0. + +* ... and more; `see below <#what-s-new-in-django-1-5>`_. + +Wherever possible we try to introduce new features in a backwards-compatible +manner per :doc:`our API stability policy </misc/api-stability>` policy. +However, as with previous releases, Django 1.5 ships with some minor +`backwards incompatible changes`_; people upgrading from previous versions +of Django should read that list carefully. + +One deprecated feature worth noting is the shift to "new-style" :ttag:`url` tag. +Prior to Django 1.3, syntax like ``{% url myview %}`` was interpreted +incorrectly (Django considered ``"myview"`` to be a literal name of a view, not +a template variable named ``myview``). Django 1.3 and above introduced the +``{% load url from future %}`` syntax to bring in the corrected behavior where +``myview`` was seen as a variable. + +The upshot of this is that if you are not using ``{% load url from future %}`` +in your templates, you'll need to change tags like ``{% url myview %}`` to +``{% url "myview" %}``. If you *were* using ``{% load url from future %}`` you +can simply remove that line under Django 1.5 + +Python compatibility +==================== + +Django 1.5 requires Python 2.6.5 or above, though we **highly recommended** +Python 2.7.3 or above. Support for Python 2.5 and below as been dropped. + +This change should affect only a small number of Django users, as most +operating-system vendors today are shipping Python 2.6 or newer as their default +version. If you're still using Python 2.5, however, you'll need to stick to +Django 1.4 until you can upgrade your Python version. Per :doc:`our support +policy </internals/release-process>`, Django 1.4 will continue to receive +security support until the release of Django 1.6. + +Django 1.5 does not run on a Jython final release, because Jython's latest +release doesn't currently support Python 2.6. However, Jython currently does +offer an alpha release featuring 2.7 support, and Django 1.5 supports that alpha +release. + +Python 3 support +~~~~~~~~~~~~~~~~ + +Django 1.5 introduces support for Python 3 - specifically, Python +3.2 and above. This comes in the form of a **single** codebase; you don't +need to install a different version of Django on Python 3. This means that +you can write application targeted for just Python 2, just Python 3, or single +applications that support both platforms. + +However, we're labling this support "experimental" for now: although it's +receved extensive testing via our automated test suite, it's recieved very +little real-world testing. We've done our best to eliminate bugs, but we can't +be sure we covered all possible uses of Django. Further, Django's more than a +web framework; it's an ecosystem of pluggable components. At this point, very +few third-party applications have been ported to Python 3, so it's unliukely +that a real-world application will have all its dependecies satisfied under +Python 3. + +Thus, we're recommending that Django 1.5 not be used in production under Python +3. Instead, use this oportunity to begin :doc:`porting applications to Python 3 +</topics/python3>`. If you're an author of a pluggable component, we encourage you +to start porting now. + +We plan to offer first-class, production-ready support for Python 3 in our next +release, Django 1.6. + +What's new in Django 1.5 +======================== + +Configurable User model +~~~~~~~~~~~~~~~~~~~~~~~ + +In Django 1.5, you can now use your own model as the store for user-related +data. If your project needs a username with more than 30 characters, or if +you want to store usernames in a format other than first name/last name, or +you want to put custom profile information onto your User object, you can +now do so. + +If you have a third-party reusable application that references the User model, +you may need to make some changes to the way you reference User instances. You +should also document any specific features of the User model that your +application relies upon. + +See the :ref:`documentation on custom User models <auth-custom-user>` for +more details. + +Support for saving a subset of model's fields +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The method :meth:`Model.save() <django.db.models.Model.save()>` has a new +keyword argument ``update_fields``. By using this argument it is possible to +save only a select list of model's fields. This can be useful for performance +reasons or when trying to avoid overwriting concurrent changes. + +Deferred instances (those loaded by .only() or .defer()) will automatically +save just the loaded fields. If any field is set manually after load, that +field will also get updated on save. + +See the :meth:`Model.save() <django.db.models.Model.save()>` documentation for +more details. + +Caching of related model instances +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When traversing relations, the ORM will avoid re-fetching objects that were +previously loaded. For example, with the tutorial's models:: + + >>> first_poll = Poll.objects.all()[0] + >>> first_choice = first_poll.choice_set.all()[0] + >>> first_choice.poll is first_poll + True + +In Django 1.5, the third line no longer triggers a new SQL query to fetch +``first_choice.poll``; it was set by the second line. + +For one-to-one relationships, both sides can be cached. For many-to-one +relationships, only the single side of the relationship can be cached. This +is particularly helpful in combination with ``prefetch_related``. + +Explicit support for streaming responses +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Before Django 1.5, it was possible to create a streaming response by passing +an iterator to :class:`~django.http.HttpResponse`. But this was unreliable: +any middleware that accessed the :attr:`~django.http.HttpResponse.content` +attribute would consume the iterator prematurely. + +You can now explicitly generate a streaming response with the new +:class:`~django.http.StreamingHttpResponse` class. This class exposes a +:class:`~django.http.StreamingHttpResponse.streaming_content` attribute which +is an iterator. + +Since :class:`~django.http.StreamingHttpResponse` does not have a ``content`` +attribute, middleware that needs access to the response content must test for +streaming responses and behave accordingly. See :ref:`response-middleware` for +more information. + +``{% verbatim %}`` template tag +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To make it easier to deal with javascript templates which collide with Django's +syntax, you can now use the :ttag:`verbatim` block tag to avoid parsing the +tag's content. + +Retrieval of ``ContentType`` instances associated with proxy models +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The methods :meth:`ContentTypeManager.get_for_model() <django.contrib.contenttypes.models.ContentTypeManager.get_for_model()>` +and :meth:`ContentTypeManager.get_for_models() <django.contrib.contenttypes.models.ContentTypeManager.get_for_models()>` +have a new keyword argument – respectively ``for_concrete_model`` and ``for_concrete_models``. +By passing ``False`` using this argument it is now possible to retreive the +:class:`ContentType <django.contrib.contenttypes.models.ContentType>` +associated with proxy models. + +New ``view`` variable in class-based views context +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In all :doc:`generic class-based views </topics/class-based-views/index>` +(or any class-based view inheriting from ``ContextMixin``), the context dictionary +contains a ``view`` variable that points to the ``View`` instance. + +GeoDjango +~~~~~~~~~ + +* :class:`~django.contrib.gis.geos.LineString` and + :class:`~django.contrib.gis.geos.MultiLineString` GEOS objects now support the + :meth:`~django.contrib.gis.geos.GEOSGeometry.interpolate()` and + :meth:`~django.contrib.gis.geos.GEOSGeometry.project()` methods + (so-called linear referencing). + +* The wkb and hex properties of `GEOSGeometry` objects preserve the Z dimension. + +* Support for PostGIS 2.0 has been added and support for GDAL < 1.5 has been + dropped. + +Minor features +~~~~~~~~~~~~~~ + +Django 1.5 also includes several smaller improvements worth noting: + +* The template engine now interprets ``True``, ``False`` and ``None`` as the + corresponding Python objects. + +* :mod:`django.utils.timezone` provides a helper for converting aware + datetimes between time zones. See :func:`~django.utils.timezone.localtime`. + +* The generic views support OPTIONS requests. + +* Management commands do not raise ``SystemExit`` any more when called by code + from :ref:`call_command <call-command>`. Any exception raised by the command + (mostly :ref:`CommandError <ref-command-exceptions>`) is propagated. + +* The dumpdata management command outputs one row at a time, preventing + out-of-memory errors when dumping large datasets. + +* In the localflavor for Canada, "pq" was added to the acceptable codes for + Quebec. It's an old abbreviation. + +* The :ref:`receiver <connecting-receiver-functions>` decorator is now able to + connect to more than one signal by supplying a list of signals. + +* In the admin, you can now filter users by groups which they are members of. + +* :meth:`QuerySet.bulk_create() + <django.db.models.query.QuerySet.bulk_create>` now has a batch_size + argument. By default the batch_size is unlimited except for SQLite where + single batch is limited so that 999 parameters per query isn't exceeded. + +* The :setting:`LOGIN_URL` and :setting:`LOGIN_REDIRECT_URL` settings now also + accept view function names and + :ref:`named URL patterns <naming-url-patterns>`. This allows you to reduce + configuration duplication. More information can be found in the + :func:`~django.contrib.auth.decorators.login_required` documentation. + +* Django now provides a mod_wsgi :doc:`auth handler + </howto/deployment/wsgi/apache-auth>`. + +* The :meth:`QuerySet.delete() <django.db.models.query.QuerySet.delete>` + and :meth:`Model.delete() <django.db.models.Model.delete()>` can now take + fast-path in some cases. The fast-path allows for less queries and less + objects fetched into memory. See :meth:`QuerySet.delete() + <django.db.models.query.QuerySet.delete>` for details. + +* An instance of :class:`~django.core.urlresolvers.ResolverMatch` is stored on + the request as ``resolver_match``. + +* By default, all logging messages reaching the `django` logger when + :setting:`DEBUG` is `True` are sent to the console (unless you redefine the + logger in your :setting:`LOGGING` setting). + +* When using :class:`~django.template.RequestContext`, it is now possible to + look up permissions by using ``{% if 'someapp.someperm' in perms %}`` + in templates. + +* It's not required any more to have ``404.html`` and ``500.html`` templates in + the root templates directory. Django will output some basic error messages for + both situations when those templates are not found. Of course, it's still + recommended as good practice to provide those templates in order to present + pretty error pages to the user. + +* :mod:`django.contrib.auth` provides a new signal that is emitted + whenever a user fails to login successfully. See + :data:`~django.contrib.auth.signals.user_login_failed` + +* The loaddata management command now supports an `ignorenonexistent` option to + ignore data for fields that no longer exist. + +* :meth:`~django.test.SimpleTestCase.assertXMLEqual` and + :meth:`~django.test.SimpleTestCase.assertXMLNotEqual` new assertions allow + you to test equality for XML content at a semantic level, without caring for + syntax differences (spaces, attribute order, etc.). + +Backwards incompatible changes in 1.5 +===================================== + +.. warning:: + + In addition to the changes outlined in this section, be sure to review the + :doc:`deprecation plan </internals/deprecation>` for any features that + have been removed. If you haven't updated your code within the + deprecation timeline for a given feature, its removal may appear as a + backwards incompatible change. + +Context in year archive class-based views +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For consistency with the other date-based generic views, +:class:`~django.views.generic.dates.YearArchiveView` now passes ``year`` in +the context as a :class:`datetime.date` rather than a string. If you are +using ``{{ year }}`` in your templates, you must replace it with ``{{ +year|date:"Y" }}``. + +``next_year`` and ``previous_year`` were also added in the context. They are +calculated according to ``allow_empty`` and ``allow_future``. + +Context in year and month archive class-based views +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:class:`~django.views.generic.dates.YearArchiveView` and +:class:`~django.views.generic.dates.MonthArchiveView` were documented to +provide a ``date_list`` sorted in ascending order in the context, like their +function-based predecessors, but it actually was in descending order. In 1.5, +the documented order was restored. You may want to add (or remove) the +``reversed`` keyword when you're iterating on ``date_list`` in a template:: + + {% for date in date_list reversed %} + +:class:`~django.views.generic.dates.ArchiveIndexView` still provides a +``date_list`` in descending order. + +Context in TemplateView +~~~~~~~~~~~~~~~~~~~~~~~ + +For consistency with the design of the other generic views, +:class:`~django.views.generic.base.TemplateView` no longer passes a ``params`` +dictionary into the context, instead passing the variables from the URLconf +directly into the context. + +Non-form data in HTTP requests +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:attr:`request.POST <django.http.HttpRequest.POST>` will no longer include data +posted via HTTP requests with non form-specific content-types in the header. +In prior versions, data posted with content-types other than +``multipart/form-data`` or ``application/x-www-form-urlencoded`` would still +end up represented in the :attr:`request.POST <django.http.HttpRequest.POST>` +attribute. Developers wishing to access the raw POST data for these cases, +should use the :attr:`request.body <django.http.HttpRequest.body>` attribute +instead. + +OPTIONS, PUT and DELETE requests in the test client +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Unlike GET and POST, these HTTP methods aren't implemented by web browsers. +Rather, they're used in APIs, which transfer data in various formats such as +JSON or XML. Since such requests may contain arbitrary data, Django doesn't +attempt to decode their body. + +However, the test client used to build a query string for OPTIONS and DELETE +requests like for GET, and a request body for PUT requests like for POST. This +encoding was arbitrary and inconsistent with Django's behavior when it +receives the requests, so it was removed in Django 1.5. + +If you were using the ``data`` parameter in an OPTIONS or a DELETE request, +you must convert it to a query string and append it to the ``path`` parameter. + +If you were using the ``data`` parameter in a PUT request without a +``content_type``, you must encode your data before passing it to the test +client and set the ``content_type`` argument. + +System version of :mod:`simplejson` no longer used +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As explained below, Django 1.5 deprecates +:mod:`django.utils.simplejson` in favor of Python 2.6's built-in :mod:`json` +module. In theory, this change is harmless. Unfortunately, because of +incompatibilities between versions of :mod:`simplejson`, it may trigger errors +in some circumstances. + +JSON-related features in Django 1.4 always used :mod:`django.utils.simplejson`. +This module was actually: + +- A system version of :mod:`simplejson`, if one was available (ie. ``import + simplejson`` works), if it was more recent than Django's built-in copy or it + had the C speedups, or +- The :mod:`json` module from the standard library, if it was available (ie. + Python 2.6 or greater), or +- A built-in copy of version 2.0.7 of :mod:`simplejson`. + +In Django 1.5, those features use Python's :mod:`json` module, which is based +on version 2.0.9 of :mod:`simplejson`. + +There are no known incompatibilities between Django's copy of version 2.0.7 and +Python's copy of version 2.0.9. However, there are some incompatibilities +between other versions of :mod:`simplejson`: + +- While the :mod:`simplejson` API is documented as always returning unicode + strings, the optional C implementation can return a byte string. This was + fixed in Python 2.7. +- :class:`simplejson.JSONEncoder` gained a ``namedtuple_as_object`` keyword + argument in version 2.2. + +More information on these incompatibilities is available in `ticket #18023`_. + +The net result is that, if you have installed :mod:`simplejson` and your code +uses Django's serialization internals directly -- for instance +:class:`django.core.serializers.json.DjangoJSONEncoder`, the switch from +:mod:`simplejson` to :mod:`json` could break your code. (In general, changes to +internals aren't documented; we're making an exception here.) + +At this point, the maintainers of Django believe that using :mod:`json` from +the standard library offers the strongest guarantee of backwards-compatibility. +They recommend to use it from now on. + +.. _ticket #18023: https://code.djangoproject.com/ticket/18023#comment:10 + +String types of hasher method parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you have written a :ref:`custom password hasher <auth_password_storage>`, +your ``encode()``, ``verify()`` or ``safe_summary()`` methods should accept +Unicode parameters (``password``, ``salt`` or ``encoded``). If any of the +hashing methods need byte strings, you can use the +:func:`~django.utils.encoding.force_bytes` utility to encode the strings. + +Validation of previous_page_number and next_page_number +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When using :doc:`object pagination </topics/pagination>`, +the ``previous_page_number()`` and ``next_page_number()`` methods of the +:class:`~django.core.paginator.Page` object did not check if the returned +number was inside the existing page range. +It does check it now and raises an :exc:`InvalidPage` exception when the number +is either too low or too high. + +Behavior of autocommit database option on PostgreSQL changed +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +PostgreSQL's autocommit option didn't work as advertised previously. It did +work for single transaction block, but after the first block was left the +autocommit behavior was never restored. This bug is now fixed in 1.5. While +this is only a bug fix, it is worth checking your applications behavior if +you are using PostgreSQL together with the autocommit option. + +Session not saved on 500 responses +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Django's session middleware will skip saving the session data if the +response's status code is 500. + +Email checks on failed admin login +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Prior to Django 1.5, if you attempted to log into the admin interface and +mistakenly used your email address instead of your username, the admin +interface would provide a warning advising that your email address was +not your username. In Django 1.5, the introduction of +:ref:`custom User models <auth-custom-user>` has required the removal of this +warning. This doesn't change the login behavior of the admin site; it only +affects the warning message that is displayed under one particular mode of +login failure. + +Changes in tests execution +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some changes have been introduced in the execution of tests that might be +backward-incompatible for some testing setups: + +Database flushing in ``django.test.TransactionTestCase`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Previously, the test database was truncated *before* each test run in a +:class:`~django.test.TransactionTestCase`. + +In order to be able to run unit tests in any order and to make sure they are +always isolated from each other, :class:`~django.test.TransactionTestCase` will +now reset the database *after* each test run instead. + +No more implict DB sequences reset +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:class:`~django.test.TransactionTestCase` tests used to reset primary key +sequences automatically together with the database flushing actions described +above. + +This has been changed so no sequences are implicitly reset. This can cause +:class:`~django.test.TransactionTestCase` tests that depend on hard-coded +primary key values to break. + +The new :attr:`~django.test.TransactionTestCase.reset_sequences` attribute can +be used to force the old behavior for :class:`~django.test.TransactionTestCase` +that might need it. + +Ordering of tests +^^^^^^^^^^^^^^^^^ + +In order to make sure all ``TestCase`` code starts with a clean database, +tests are now executed in the following order: + +* First, all unittests (including :class:`unittest.TestCase`, + :class:`~django.test.SimpleTestCase`, :class:`~django.test.TestCase` and + :class:`~django.test.TransactionTestCase`) are run with no particular ordering + guaranteed nor enforced among them. + +* Then any other tests (e.g. doctests) that may alter the database without + restoring it to its original state are run. + +This should not cause any problems unless you have existing doctests which +assume a :class:`~django.test.TransactionTestCase` executed earlier left some +database state behind or unit tests that rely on some form of state being +preserved after the execution of other tests. Such tests are already very +fragile, and must now be changed to be able to run independently. + +`cleaned_data` dictionary kept for invalid forms +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :attr:`~django.forms.Form.cleaned_data` dictionary is now always present +after form validation. When the form doesn't validate, it contains only the +fields that passed validation. You should test the success of the validation +with the :meth:`~django.forms.Form.is_valid()` method and not with the +presence or absence of the :attr:`~django.forms.Form.cleaned_data` attribute +on the form. + +Miscellaneous +~~~~~~~~~~~~~ + +* :class:`django.forms.ModelMultipleChoiceField` now returns an empty + ``QuerySet`` as the empty value instead of an empty list. + +* :func:`~django.utils.http.int_to_base36` properly raises a :exc:`TypeError` + instead of :exc:`ValueError` for non-integer inputs. + +* The ``slugify`` template filter is now available as a standard python + function at :func:`django.utils.text.slugify`. Similarly, ``remove_tags`` is + available at :func:`django.utils.html.remove_tags`. + +* Uploaded files are no longer created as executable by default. If you need + them to be executeable change :setting:`FILE_UPLOAD_PERMISSIONS` to your + needs. The new default value is `0666` (octal) and the current umask value + is first masked out. + +* The :ref:`F() expressions <query-expressions>` supported bitwise operators by + ``&`` and ``|``. These operators are now available using ``.bitand()`` and + ``.bitor()`` instead. The removal of ``&`` and ``|`` was done to be consistent with + :ref:`Q() expressions <complex-lookups-with-q>` and ``QuerySet`` combining where + the operators are used as boolean AND and OR operators. + +* The :ttag:`csrf_token` template tag is no longer enclosed in a div. If you need + HTML validation against pre-HTML5 Strict DTDs, you should add a div around it + in your pages. + +Features deprecated in 1.5 +========================== + +:setting:`AUTH_PROFILE_MODULE` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +With the introduction of :ref:`custom User models <auth-custom-user>`, there is +no longer any need for a built-in mechanism to store user profile data. + +You can still define user profiles models that have a one-to-one relation with +the User model - in fact, for many applications needing to associate data with +a User account, this will be an appropriate design pattern to follow. However, +the :setting:`AUTH_PROFILE_MODULE` setting, and the +:meth:`~django.contrib.auth.models.User.get_profile()` method for accessing +the user profile model, should not be used any longer. + +Streaming behavior of :class:`HttpResponse` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Django 1.5 deprecates the ability to stream a response by passing an iterator +to :class:`~django.http.HttpResponse`. If you rely on this behavior, switch to +:class:`~django.http.StreamingHttpResponse`. See above for more details. + +In Django 1.7 and above, the iterator will be consumed immediately by +:class:`~django.http.HttpResponse`. + +``django.utils.simplejson`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Since Django 1.5 drops support for Python 2.5, we can now rely on the +:mod:`json` module being available in Python's standard library, so we've +removed our own copy of :mod:`simplejson`. You should now import :mod:`json` +instead :mod:`django.utils.simplejson`. + +Unfortunately, this change might have unwanted side-effects, because of +incompatibilities between versions of :mod:`simplejson` -- see the backwards- +incompatible changes section. If you rely on features added to :mod:`simplejson` +after it became Python's :mod:`json`, you should import :mod:`simplejson` +explicitly. + +``django.utils.encoding.StrAndUnicode`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :class:`~django.utils.encoding.StrAndUnicode` mix-in has been deprecated. +Define a ``__str__`` method and apply the +:func:`~django.utils.encoding.python_2_unicode_compatible` decorator instead. + +``django.utils.itercompat.product`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :func:`~django.utils.itercompat.product` function has been deprecated. Use +the built-in :func:`itertools.product` instead. + + +``django.utils.markup`` +~~~~~~~~~~~~~~~~~~~~~~~ + +The markup contrib module has been deprecated and will follow an accelerated +deprecation schedule. Direct use of python markup libraries or 3rd party tag +libraries is preferred to Django maintaining this functionality in the +framework. diff --git a/docs/releases/1.5.txt b/docs/releases/1.5.txt index 6420239f47..a0ce3cc7a4 100644 --- a/docs/releases/1.5.txt +++ b/docs/releases/1.5.txt @@ -2,6 +2,8 @@ Django 1.5 release notes - UNDER DEVELOPMENT ============================================ +Welcome to Django 1.5! + These release notes cover the `new features`_, as well as some `backwards incompatible changes`_ you'll want to be aware of when upgrading from Django 1.4 or older versions. We've also dropped some @@ -13,27 +15,119 @@ features`_. .. _`backwards incompatible changes`: `Backwards incompatible changes in 1.5`_ .. _`begun the deprecation process for some features`: `Features deprecated in 1.5`_ +Overview +======== + +The biggest new feature in Django 1.5 is the `configurable User model`_. Before +Django 1.5, applications that wanted to use Django's auth framework +(:mod:`django.contrib.auth`) were forced to use Django's definition of a "user". +In Django 1.5, you can now swap out the ``User`` model for one that you write +yourself. This could be a simple extension to the existing ``User`` model -- for +example, you could add a Twitter or Facebook ID field -- or you could completely +replace the ``User`` with one totally customized for your site. + +Django 1.5 is also the first release with `Python 3 support`_! We're labeling +this support "experimental" because we don't yet consider it production-ready, +but everything's in place for you to start porting your apps to Python 3. +Our next release, Django 1.6, will support Python 3 without reservations. + +Other notable new features in Django 1.5 include: + +* `Support for saving a subset of model's fields`_ - + :meth:`Model.save() <django.db.models.Model.save()>` now accepts an + ``update_fields`` argument, letting you specify which fields are + written back to the database when you call ``save()``. This can help + in high-concurrency operations, and can improve performance. + +* Better `support for streaming responses <#explicit-streaming-responses>`_ via + the new :class:`~django.http.StreamingHttpResponse` response class. + +* `GeoDjango`_ now supports PostGIS 2.0. + +* ... and more; `see below <#what-s-new-in-django-1-5>`_. + +Wherever possible we try to introduce new features in a backwards-compatible +manner per :doc:`our API stability policy </misc/api-stability>` policy. +However, as with previous releases, Django 1.5 ships with some minor +`backwards incompatible changes`_; people upgrading from previous versions +of Django should read that list carefully. + +One deprecated feature worth noting is the shift to "new-style" :ttag:`url` tag. +Prior to Django 1.3, syntax like ``{% url myview %}`` was interpreted +incorrectly (Django considered ``"myview"`` to be a literal name of a view, not +a template variable named ``myview``). Django 1.3 and above introduced the +``{% load url from future %}`` syntax to bring in the corrected behavior where +``myview`` was seen as a variable. + +The upshot of this is that if you are not using ``{% load url from future %}`` +in your templates, you'll need to change tags like ``{% url myview %}`` to +``{% url "myview" %}``. If you *were* using ``{% load url from future %}`` you +can simply remove that line under Django 1.5 + Python compatibility ==================== -Django 1.5 has dropped support for Python 2.5. Python 2.6.5 is now the minimum -required Python version. Django is tested and supported on Python 2.6 and -2.7. +Django 1.5 requires Python 2.6.5 or above, though we **highly recommended** +Python 2.7.3 or above. Support for Python 2.5 and below as been dropped. This change should affect only a small number of Django users, as most operating-system vendors today are shipping Python 2.6 or newer as their default version. If you're still using Python 2.5, however, you'll need to stick to -Django 1.4 until you can upgrade your Python version. Per :doc:`our support policy -</internals/release-process>`, Django 1.4 will continue to receive security -support until the release of Django 1.6. +Django 1.4 until you can upgrade your Python version. Per :doc:`our support +policy </internals/release-process>`, Django 1.4 will continue to receive +security support until the release of Django 1.6. + +Django 1.5 does not run on a Jython final release, because Jython's latest +release doesn't currently support Python 2.6. However, Jython currently does +offer an alpha release featuring 2.7 support, and Django 1.5 supports that alpha +release. + +Python 3 support +~~~~~~~~~~~~~~~~ -Django 1.5 does not run on a Jython final release, because Jython's latest release -doesn't currently support Python 2.6. However, Jython currently does offer an alpha -release featuring 2.7 support. +Django 1.5 introduces support for Python 3 - specifically, Python +3.2 and above. This comes in the form of a **single** codebase; you don't +need to install a different version of Django on Python 3. This means that +you can write application targeted for just Python 2, just Python 3, or single +applications that support both platforms. + +However, we're labeling this support "experimental" for now: although it's +received extensive testing via our automated test suite, it's received very +little real-world testing. We've done our best to eliminate bugs, but we can't +be sure we covered all possible uses of Django. Further, Django's more than a +web framework; it's an ecosystem of pluggable components. At this point, very +few third-party applications have been ported to Python 3, so it's unlikely +that a real-world application will have all its dependencies satisfied under +Python 3. + +Thus, we're recommending that Django 1.5 not be used in production under Python +3. Instead, use this opportunity to begin :doc:`porting applications to Python 3 +</topics/python3>`. If you're an author of a pluggable component, we encourage you +to start porting now. + +We plan to offer first-class, production-ready support for Python 3 in our next +release, Django 1.6. What's new in Django 1.5 ======================== +Configurable User model +~~~~~~~~~~~~~~~~~~~~~~~ + +In Django 1.5, you can now use your own model as the store for user-related +data. If your project needs a username with more than 30 characters, or if +you want to store user's names in a format other than first name/last name, +or you want to put custom profile information onto your User object, you can +now do so. + +If you have a third-party reusable application that references the User model, +you may need to make some changes to the way you reference User instances. You +should also document any specific features of the User model that your +application relies upon. + +See the :ref:`documentation on custom User models <auth-custom-user>` for +more details. + Support for saving a subset of model's fields ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -67,6 +161,26 @@ For one-to-one relationships, both sides can be cached. For many-to-one relationships, only the single side of the relationship can be cached. This is particularly helpful in combination with ``prefetch_related``. +.. _explicit-streaming-responses: + +Explicit support for streaming responses +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Before Django 1.5, it was possible to create a streaming response by passing +an iterator to :class:`~django.http.HttpResponse`. But this was unreliable: +any middleware that accessed the :attr:`~django.http.HttpResponse.content` +attribute would consume the iterator prematurely. + +You can now explicitly generate a streaming response with the new +:class:`~django.http.StreamingHttpResponse` class. This class exposes a +:class:`~django.http.StreamingHttpResponse.streaming_content` attribute which +is an iterator. + +Since :class:`~django.http.StreamingHttpResponse` does not have a ``content`` +attribute, middleware that needs access to the response content must test for +streaming responses and behave accordingly. See :ref:`response-middleware` for +more information. + ``{% verbatim %}`` template tag ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -80,16 +194,31 @@ Retrieval of ``ContentType`` instances associated with proxy models The methods :meth:`ContentTypeManager.get_for_model() <django.contrib.contenttypes.models.ContentTypeManager.get_for_model()>` and :meth:`ContentTypeManager.get_for_models() <django.contrib.contenttypes.models.ContentTypeManager.get_for_models()>` have a new keyword argument – respectively ``for_concrete_model`` and ``for_concrete_models``. -By passing ``False`` using this argument it is now possible to retreive the +By passing ``False`` using this argument it is now possible to retrieve the :class:`ContentType <django.contrib.contenttypes.models.ContentType>` associated with proxy models. New ``view`` variable in class-based views context ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + In all :doc:`generic class-based views </topics/class-based-views/index>` (or any class-based view inheriting from ``ContextMixin``), the context dictionary contains a ``view`` variable that points to the ``View`` instance. +GeoDjango +~~~~~~~~~ + +* :class:`~django.contrib.gis.geos.LineString` and + :class:`~django.contrib.gis.geos.MultiLineString` GEOS objects now support the + :meth:`~django.contrib.gis.geos.GEOSGeometry.interpolate()` and + :meth:`~django.contrib.gis.geos.GEOSGeometry.project()` methods + (so-called linear referencing). + +* The wkb and hex properties of `GEOSGeometry` objects preserve the Z dimension. + +* Support for PostGIS 2.0 has been added and support for GDAL < 1.5 has been + dropped. + Minor features ~~~~~~~~~~~~~~ @@ -116,6 +245,8 @@ Django 1.5 also includes several smaller improvements worth noting: * The :ref:`receiver <connecting-receiver-functions>` decorator is now able to connect to more than one signal by supplying a list of signals. +* In the admin, you can now filter users by groups which they are members of. + * :meth:`QuerySet.bulk_create() <django.db.models.query.QuerySet.bulk_create>` now has a batch_size argument. By default the batch_size is unlimited except for SQLite where @@ -127,6 +258,44 @@ Django 1.5 also includes several smaller improvements worth noting: configuration duplication. More information can be found in the :func:`~django.contrib.auth.decorators.login_required` documentation. +* Django now provides a mod_wsgi :doc:`auth handler + </howto/deployment/wsgi/apache-auth>`. + +* The :meth:`QuerySet.delete() <django.db.models.query.QuerySet.delete>` + and :meth:`Model.delete() <django.db.models.Model.delete()>` can now take + fast-path in some cases. The fast-path allows for less queries and less + objects fetched into memory. See :meth:`QuerySet.delete() + <django.db.models.query.QuerySet.delete>` for details. + +* An instance of :class:`~django.core.urlresolvers.ResolverMatch` is stored on + the request as ``resolver_match``. + +* By default, all logging messages reaching the `django` logger when + :setting:`DEBUG` is `True` are sent to the console (unless you redefine the + logger in your :setting:`LOGGING` setting). + +* When using :class:`~django.template.RequestContext`, it is now possible to + look up permissions by using ``{% if 'someapp.someperm' in perms %}`` + in templates. + +* It's not required any more to have ``404.html`` and ``500.html`` templates in + the root templates directory. Django will output some basic error messages for + both situations when those templates are not found. Of course, it's still + recommended as good practice to provide those templates in order to present + pretty error pages to the user. + +* :mod:`django.contrib.auth` provides a new signal that is emitted + whenever a user fails to login successfully. See + :data:`~django.contrib.auth.signals.user_login_failed` + +* The loaddata management command now supports an `ignorenonexistent` option to + ignore data for fields that no longer exist. + +* :meth:`~django.test.SimpleTestCase.assertXMLEqual` and + :meth:`~django.test.SimpleTestCase.assertXMLNotEqual` new assertions allow + you to test equality for XML content at a semantic level, without caring for + syntax differences (spaces, attribute order, etc.). + Backwards incompatible changes in 1.5 ===================================== @@ -150,6 +319,21 @@ year|date:"Y" }}``. ``next_year`` and ``previous_year`` were also added in the context. They are calculated according to ``allow_empty`` and ``allow_future``. +Context in year and month archive class-based views +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:class:`~django.views.generic.dates.YearArchiveView` and +:class:`~django.views.generic.dates.MonthArchiveView` were documented to +provide a ``date_list`` sorted in ascending order in the context, like their +function-based predecessors, but it actually was in descending order. In 1.5, +the documented order was restored. You may want to add (or remove) the +``reversed`` keyword when you're iterating on ``date_list`` in a template:: + + {% for date in date_list reversed %} + +:class:`~django.views.generic.dates.ArchiveIndexView` still provides a +``date_list`` in descending order. + Context in TemplateView ~~~~~~~~~~~~~~~~~~~~~~~ @@ -158,6 +342,18 @@ For consistency with the design of the other generic views, dictionary into the context, instead passing the variables from the URLconf directly into the context. +Non-form data in HTTP requests +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:attr:`request.POST <django.http.HttpRequest.POST>` will no longer include data +posted via HTTP requests with non form-specific content-types in the header. +In prior versions, data posted with content-types other than +``multipart/form-data`` or ``application/x-www-form-urlencoded`` would still +end up represented in the :attr:`request.POST <django.http.HttpRequest.POST>` +attribute. Developers wishing to access the raw POST data for these cases, +should use the :attr:`request.body <django.http.HttpRequest.body>` attribute +instead. + OPTIONS, PUT and DELETE requests in the test client ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -260,6 +456,18 @@ Session not saved on 500 responses Django's session middleware will skip saving the session data if the response's status code is 500. +Email checks on failed admin login +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Prior to Django 1.5, if you attempted to log into the admin interface and +mistakenly used your email address instead of your username, the admin +interface would provide a warning advising that your email address was +not your username. In Django 1.5, the introduction of +:ref:`custom User models <auth-custom-user>` has required the removal of this +warning. This doesn't change the login behavior of the admin site; it only +affects the warning message that is displayed under one particular mode of +login failure. + Changes in tests execution ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -276,8 +484,8 @@ In order to be able to run unit tests in any order and to make sure they are always isolated from each other, :class:`~django.test.TransactionTestCase` will now reset the database *after* each test run instead. -No more implict DB sequences reset -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +No more implicit DB sequences reset +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :class:`~django.test.TransactionTestCase` tests used to reset primary key sequences automatically together with the database flushing actions described @@ -324,7 +532,8 @@ on the form. Miscellaneous ~~~~~~~~~~~~~ -* GeoDjango dropped support for GDAL < 1.5 +* :class:`django.forms.ModelMultipleChoiceField` now returns an empty + ``QuerySet`` as the empty value instead of an empty list. * :func:`~django.utils.http.int_to_base36` properly raises a :exc:`TypeError` instead of :exc:`ValueError` for non-integer inputs. @@ -333,11 +542,50 @@ Miscellaneous function at :func:`django.utils.text.slugify`. Similarly, ``remove_tags`` is available at :func:`django.utils.html.remove_tags`. +* Uploaded files are no longer created as executable by default. If you need + them to be executable change :setting:`FILE_UPLOAD_PERMISSIONS` to your + needs. The new default value is `0666` (octal) and the current umask value + is first masked out. + +* The :ref:`F() expressions <query-expressions>` supported bitwise operators by + ``&`` and ``|``. These operators are now available using ``.bitand()`` and + ``.bitor()`` instead. The removal of ``&`` and ``|`` was done to be consistent with + :ref:`Q() expressions <complex-lookups-with-q>` and ``QuerySet`` combining where + the operators are used as boolean AND and OR operators. + +* The :ttag:`csrf_token` template tag is no longer enclosed in a div. If you need + HTML validation against pre-HTML5 Strict DTDs, you should add a div around it + in your pages. + Features deprecated in 1.5 ========================== .. _simplejson-deprecation: +:setting:`AUTH_PROFILE_MODULE` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +With the introduction of :ref:`custom User models <auth-custom-user>`, there is +no longer any need for a built-in mechanism to store user profile data. + +You can still define user profiles models that have a one-to-one relation with +the User model - in fact, for many applications needing to associate data with +a User account, this will be an appropriate design pattern to follow. However, +the :setting:`AUTH_PROFILE_MODULE` setting, and the +:meth:`~django.contrib.auth.models.User.get_profile()` method for accessing +the user profile model, should not be used any longer. + +Streaming behavior of :class:`HttpResponse` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Django 1.5 deprecates the ability to stream a response by passing an iterator +to :class:`~django.http.HttpResponse`. If you rely on this behavior, switch to +:class:`~django.http.StreamingHttpResponse`. See +:ref:`explicit-streaming-responses` above. + +In Django 1.7 and above, the iterator will be consumed immediately by +:class:`~django.http.HttpResponse`. + ``django.utils.simplejson`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -352,12 +600,6 @@ incompatibilities between versions of :mod:`simplejson` -- see the If you rely on features added to :mod:`simplejson` after it became Python's :mod:`json`, you should import :mod:`simplejson` explicitly. -``itercompat.product`` -~~~~~~~~~~~~~~~~~~~~~~ - -The :func:`~django.utils.itercompat.product` function has been deprecated. Use -the built-in :func:`itertools.product` instead. - ``django.utils.encoding.StrAndUnicode`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -365,6 +607,13 @@ The :class:`~django.utils.encoding.StrAndUnicode` mix-in has been deprecated. Define a ``__str__`` method and apply the :func:`~django.utils.encoding.python_2_unicode_compatible` decorator instead. +``django.utils.itercompat.product`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :func:`~django.utils.itercompat.product` function has been deprecated. Use +the built-in :func:`itertools.product` instead. + + ``django.utils.markup`` ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/releases/index.txt b/docs/releases/index.txt index 2329d1effa..6df9821f56 100644 --- a/docs/releases/index.txt +++ b/docs/releases/index.txt @@ -28,7 +28,7 @@ Final releases .. toctree:: :maxdepth: 1 - .. 1.4.2 (uncomment on release) + 1.4.2 1.4.1 1.4 @@ -92,6 +92,7 @@ notes. .. toctree:: :maxdepth: 1 + 1.5-alpha-1 1.4-beta-1 1.4-alpha-1 1.3-beta-1 diff --git a/docs/topics/auth.txt b/docs/topics/auth.txt index ef03d5479c..41159984f6 100644 --- a/docs/topics/auth.txt +++ b/docs/topics/auth.txt @@ -149,6 +149,12 @@ Methods :class:`~django.contrib.auth.models.User` objects have the following custom methods: + .. method:: models.User.get_username() + + Returns the username for the user. Since the User model can be swapped + out, you should use this method instead of referencing the username + attribute directly. + .. method:: models.User.is_anonymous() Always returns ``False``. This is a way of differentiating @@ -250,6 +256,12 @@ Methods .. method:: models.User.get_profile() + .. deprecated:: 1.5 + With the introduction of :ref:`custom User models <auth-custom-user>`, + the use of :setting:`AUTH_PROFILE_MODULE` to define a single profile + model is no longer supported. See the + :doc:`Django 1.5 release notes</releases/1.5>` for more information. + Returns a site-specific profile for this user. Raises :exc:`django.contrib.auth.models.SiteProfileNotAvailable` if the current site doesn't allow profiles, or @@ -582,6 +594,12 @@ correct path and environment for you. Storing additional information about users ------------------------------------------ +.. deprecated:: 1.5 + With the introduction of :ref:`custom User models <auth-custom-user>`, + the use of :setting:`AUTH_PROFILE_MODULE` to define a single profile + model is no longer supported. See the + :doc:`Django 1.5 release notes</releases/1.5>` for more information. + If you'd like to store additional information related to your users, Django provides a method to specify a site-specific related model -- termed a "user profile" -- for this purpose. @@ -860,19 +878,18 @@ How to log a user out Login and logout signals ------------------------ -.. versionadded:: 1.3 - The auth framework uses two :doc:`signals </topics/signals>` that can be used for notification when a user logs in or out. .. data:: django.contrib.auth.signals.user_logged_in + :module: Sent when a user logs in successfully. Arguments sent with this signal: ``sender`` - As above: the class of the user that just logged in. + The class of the user that just logged in. ``request`` The current :class:`~django.http.HttpRequest` instance. @@ -881,6 +898,7 @@ Arguments sent with this signal: The user instance that just logged in. .. data:: django.contrib.auth.signals.user_logged_out + :module: Sent when the logout method is called. @@ -895,6 +913,21 @@ Sent when the logout method is called. The user instance that just logged out or ``None`` if the user was not authenticated. +.. data:: django.contrib.auth.signals.user_login_failed + :module: +.. versionadded:: 1.5 + +Sent when the user failed to login successfully + +``sender`` + The name of the module used for authentication. + +``credentials`` + A dictonary of keyword arguments containing the user credentials that were + passed to :func:`~django.contrib.auth.authenticate()` or your own custom + authentication backend. Credentials matching a set of 'sensitive' patterns, + (including password) will not be sent in the clear as part of the signal. + Limiting access to logged-in users ---------------------------------- @@ -960,8 +993,6 @@ The login_required decorator context variable which stores the redirect path will use the value of ``redirect_field_name`` as its key rather than ``"next"`` (the default). - .. versionadded:: 1.3 - :func:`~django.contrib.auth.decorators.login_required` also takes an optional ``login_url`` parameter. Example:: @@ -1189,9 +1220,6 @@ includes a few other useful built-in views located in that can be used to reset the password, and sending that link to the user's registered email address. - .. versionchanged:: 1.3 - The ``from_email`` argument was added. - .. versionchanged:: 1.4 Users flagged with an unusable password (see :meth:`~django.contrib.auth.models.User.set_unusable_password()` @@ -1352,6 +1380,9 @@ Helper functions URL to redirect to after log out. Overrides ``next`` if the given ``GET`` parameter is passed. + +.. _built-in-auth-forms: + Built-in forms -------------- @@ -1672,10 +1703,6 @@ The currently logged-in user's permissions are stored in the template variable :class:`django.contrib.auth.context_processors.PermWrapper`, which is a template-friendly proxy of permissions. -.. versionchanged:: 1.3 - Prior to version 1.3, ``PermWrapper`` was located in - ``django.core.context_processors``. - In the ``{{ perms }}`` object, single-attribute lookup is a proxy to :meth:`User.has_module_perms <django.contrib.auth.models.User.has_module_perms>`. This example would display ``True`` if the logged-in user had any permissions @@ -1706,6 +1733,20 @@ Thus, you can check permissions in template ``{% if %}`` statements: <p>You don't have permission to do anything in the foo app.</p> {% endif %} +.. versionadded:: 1.5 + Permission lookup by "if in". + +It is possible to also look permissions up by ``{% if in %}`` statements. +For example: + +.. code-block:: html+django + + {% if 'foo' in perms %} + {% if 'foo.can_vote' in perms %} + <p>In lookup works, too.</p> + {% endif %} + {% endif %} + Groups ====== @@ -1746,6 +1787,533 @@ Fields group.permissions.remove(permission, permission, ...) group.permissions.clear() +.. _auth-custom-user: + +Customizing the User model +========================== + +.. versionadded:: 1.5 + +Some kinds of projects may have authentication requirements for which Django's +built-in :class:`~django.contrib.auth.models.User` model is not always +appropriate. For instance, on some sites it makes more sense to use an email +address as your identification token instead of a username. + +Django allows you to override the default User model by providing a value for +the :setting:`AUTH_USER_MODEL` setting that references a custom model:: + + AUTH_USER_MODEL = 'myapp.MyUser' + +This dotted pair describes the name of the Django app, and the name of the Django +model that you wish to use as your User model. + +.. admonition:: Warning + + Changing :setting:`AUTH_USER_MODEL` has a big effect on your database + structure. It changes the tables that are available, and it will affect the + construction of foreign keys and many-to-many relationships. If you intend + to set :setting:`AUTH_USER_MODEL`, you should set it before running + ``manage.py syncdb`` for the first time. + + If you have an existing project and you want to migrate to using a custom + User model, you may need to look into using a migration tool like South_ + to ease the transition. + +.. _South: http://south.aeracode.org + +Referencing the User model +-------------------------- + +If you reference :class:`~django.contrib.auth.models.User` directly (for +example, by referring to it in a foreign key), your code will not work in +projects where the :setting:`AUTH_USER_MODEL` setting has been changed to a +different User model. + +Instead of referring to :class:`~django.contrib.auth.models.User` directly, +you should reference the user model using +:func:`django.contrib.auth.get_user_model()`. This method will return the +currently active User model -- the custom User model if one is specified, or +:class:`~django.contrib.auth.User` otherwise. + +When you define a foreign key or many-to-many relations to the User model, +you should specify the custom model using the :setting:`AUTH_USER_MODEL` +setting. For example:: + + from django.conf import settings + from django.db import models + + class Article(models.Model) + author = models.ForeignKey(settings.AUTH_USER_MODEL) + +Specifying a custom User model +------------------------------ + +.. admonition:: Model design considerations + + Think carefully before handling information not directly related to + authentication in your custom User Model. + + It may be better to store app-specific user information in a model + that has a relation with the User model. That allows each app to specify + its own user data requirements without risking conflicts with other + apps. On the other hand, queries to retrieve this related information + will involve a database join, which may have an effect on performance. + +Django expects your custom User model to meet some minimum requirements. + +1. Your model must have a single unique field that can be used for + identification purposes. This can be a username, an email address, + or any other unique attribute. + +2. Your model must provide a way to address the user in a "short" and + "long" form. The most common interpretation of this would be to use + the user's given name as the "short" identifier, and the user's full + name as the "long" identifier. However, there are no constraints on + what these two methods return - if you want, they can return exactly + the same value. + +The easiest way to construct a compliant custom User model is to inherit from +:class:`~django.contrib.auth.models.AbstractBaseUser`. +:class:`~django.contrib.auth.models.AbstractBaseUser` provides the core +implementation of a `User` model, including hashed passwords and tokenized +password resets. You must then provide some key implementation details: + +.. class:: models.CustomUser + + .. attribute:: User.USERNAME_FIELD + + A string describing the name of the field on the User model that is + used as the unique identifier. This will usually be a username of + some kind, but it can also be an email address, or any other unique + identifier. In the following example, the field `identifier` is used + as the identifying field:: + + class MyUser(AbstractBaseUser): + identfier = models.CharField(max_length=40, unique=True, db_index=True) + ... + USERNAME_FIELD = 'identifier' + + .. attribute:: User.REQUIRED_FIELDS + + A list of the field names that *must* be provided when creating + a user. For example, here is the partial definition for a User model + that defines two required fields - a date of birth and height:: + + class MyUser(AbstractBaseUser): + ... + date_of_birth = models.DateField() + height = models.FloatField() + ... + REQUIRED_FIELDS = ['date_of_birth', 'height'] + + .. note:: + + ``REQUIRED_FIELDS`` must contain all required fields on your User + model, but should *not* contain the ``USERNAME_FIELD``. + + .. method:: User.get_full_name(): + + A longer formal identifier for the user. A common interpretation + would be the full name name of the user, but it can be any string that + identifies the user. + + .. method:: User.get_short_name(): + + A short, informal identifier for the user. A common interpretation + would be the first name of the user, but it can be any string that + identifies the user in an informal way. It may also return the same + value as :meth:`django.contrib.auth.User.get_full_name()`. + +The following methods are available on any subclass of +:class:`~django.contrib.auth.models.AbstractBaseUser`: + +.. class:: models.AbstractBaseUser + + .. method:: models.AbstractBaseUser.get_username() + + Returns the value of the field nominated by ``USERNAME_FIELD``. + + .. method:: models.AbstractBaseUser.is_anonymous() + + Always returns ``False``. This is a way of differentiating + from :class:`~django.contrib.auth.models.AnonymousUser` objects. + Generally, you should prefer using + :meth:`~django.contrib.auth.models.AbstractBaseUser.is_authenticated()` to this + method. + + .. method:: models.AbstractBaseUser.is_authenticated() + + Always returns ``True``. This is a way to tell if the user has been + authenticated. This does not imply any permissions, and doesn't check + if the user is active - it only indicates that the user has provided a + valid username and password. + + .. method:: models.AbstractBaseUser.set_password(raw_password) + + Sets the user's password to the given raw string, taking care of the + password hashing. Doesn't save the + :class:`~django.contrib.auth.models.AbstractBaseUser` object. + + .. method:: models.AbstractBaseUser.check_password(raw_password) + + Returns ``True`` if the given raw string is the correct password for + the user. (This takes care of the password hashing in making the + comparison.) + + .. method:: models.AbstractBaseUser.set_unusable_password() + + Marks the user as having no password set. This isn't the same as + having a blank string for a password. + :meth:`~django.contrib.auth.models.AbstractBaseUser.check_password()` for this user + will never return ``True``. Doesn't save the + :class:`~django.contrib.auth.models.AbstractBaseUser` object. + + You may need this if authentication for your application takes place + against an existing external source such as an LDAP directory. + + .. method:: models.AbstractBaseUser.has_usable_password() + + Returns ``False`` if + :meth:`~django.contrib.auth.models.AbstractBaseUser.set_unusable_password()` has + been called for this user. + + +You should also define a custom manager for your User model. If your User +model defines `username` and `email` fields the same as Django's default User, +you can just install Django's +:class:`~django.contrib.auth.models.UserManager`; however, if your User model +defines different fields, you will need to define a custom manager that +extends :class:`~django.contrib.auth.models.BaseUserManager` providing two +additional methods: + +.. class:: models.CustomUserManager + + .. method:: models.CustomUserManager.create_user(*username_field*, password=None, **other_fields) + + The prototype of `create_user()` should accept the username field, + plus all required fields as arguments. For example, if your user model + uses `email` as the username field, and has `date_of_birth` as a required + fields, then create_user should be defined as:: + + def create_user(self, email, date_of_birth, password=None): + # create user here + + .. method:: models.CustomUserManager.create_superuser(*username_field*, password, **other_fields) + + The prototype of `create_user()` should accept the username field, + plus all required fields as arguments. For example, if your user model + uses `email` as the username field, and has `date_of_birth` as a required + fields, then create_superuser should be defined as:: + + def create_superuser(self, email, date_of_birth, password): + # create superuser here + + Unlike `create_user()`, `create_superuser()` *must* require the caller + to provider a password. + +:class:`~django.contrib.auth.models.BaseUserManager` provides the following +utility methods: + +.. class:: models.BaseUserManager + + .. method:: models.BaseUserManager.normalize_email(email) + + A classmethod that normalizes email addresses by lowercasing + the domain portion of the email address. + + .. method:: models.BaseUserManager.get_by_natural_key(username) + + Retrieves a user instance using the contents of the field + nominated by ``USERNAME_FIELD``. + + .. method:: models.BaseUserManager.make_random_password(length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789') + + Returns a random password with the given length and given string of + allowed characters. (Note that the default value of ``allowed_chars`` + doesn't contain letters that can cause user confusion, including: + + * ``i``, ``l``, ``I``, and ``1`` (lowercase letter i, lowercase + letter L, uppercase letter i, and the number one) + * ``o``, ``O``, and ``0`` (uppercase letter o, lowercase letter o, + and zero) + +Extending Django's default User +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you're entirely happy with Django's :class:`~django.contrib.auth.models.User` +model and you just want to add some additional profile information, you can +simply subclass :class:`~django.contrib.auth.models.AbstractUser` and add your +custom profile fields. + +Custom users and the built-in auth forms +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As you may expect, built-in Django's :ref:`forms <built-in-auth-forms>` +and :ref:`views <other-built-in-views>` make certain assumptions about +the user model that they are working with. + +If your user model doesn't follow the same assumptions, it may be necessary to define +a replacement form, and pass that form in as part of the configuration of the +auth views. + +* :class:`~django.contrib.auth.forms.UserCreationForm` + + Depends on the :class:`~django.contrib.auth.models.User` model. + Must be re-written for any custom user model. + +* :class:`~django.contrib.auth.forms.UserChangeForm` + + Depends on the :class:`~django.contrib.auth.models.User` model. + Must be re-written for any custom user model. + +* :class:`~django.contrib.auth.forms.AuthenticationForm` + + Works with any subclass of :class:`~django.contrib.auth.models.AbstractBaseUser`, + and will adapt to use the field defined in `USERNAME_FIELD`. + +* :class:`~django.contrib.auth.forms.PasswordResetForm` + + Assumes that the user model has an integer primary key, has a field named + `email` that can be used to identify the user, and a boolean field + named `is_active` to prevent password resets for inactive users. + +* :class:`~django.contrib.auth.forms.SetPasswordForm` + + Works with any subclass of :class:`~django.contrib.auth.models.AbstractBaseUser` + +* :class:`~django.contrib.auth.forms.PasswordChangeForm` + + Works with any subclass of :class:`~django.contrib.auth.models.AbstractBaseUser` + +* :class:`~django.contrib.auth.forms.AdminPasswordChangeForm` + + Works with any subclass of :class:`~django.contrib.auth.models.AbstractBaseUser` + + +Custom users and django.contrib.admin +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you want your custom User model to also work with Admin, your User model must +define some additional attributes and methods. These methods allow the admin to +control access of the User to admin content: + +.. attribute:: User.is_staff + + Returns True if the user is allowed to have access to the admin site. + +.. attribute:: User.is_active + + Returns True if the user account is currently active. + +.. method:: User.has_perm(perm, obj=None): + + Returns True if the user has the named permission. If `obj` is + provided, the permission needs to be checked against a specific object + instance. + +.. method:: User.has_module_perms(app_label): + + Returns True if the user has permission to access models in + the given app. + +You will also need to register your custom User model with the admin. If +your custom User model extends :class:`~django.contrib.auth.models.AbstractUser`, +you can use Django's existing :class:`~django.contrib.auth.admin.UserAdmin` +class. However, if your User model extends +:class:`~django.contrib.auth.models.AbstractBaseUser`, you'll need to define +a custom ModelAdmin class. It may be possible to subclass the default +:class:`~django.contrib.auth.admin.UserAdmin`; however, you'll need to +override any of the definitions that refer to fields on +:class:`~django.contrib.auth.models.AbstractUser` that aren't on your +custom User class. + +Custom users and Proxy models +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +One limitation of custom User models is that installing a custom User model +will break any proxy model extending :class:`~django.contrib.auth.models.User`. +Proxy models must be based on a concrete base class; by defining a custom User +model, you remove the ability of Django to reliably identify the base class. + +If your project uses proxy models, you must either modify the proxy to extend +the User model that is currently in use in your project, or merge your proxy's +behavior into your User subclass. + +A full example +-------------- + +Here is an example of an admin-compliant custom user app. This user model uses +an email address as the username, and has a required date of birth; it +provides no permission checking, beyond a simple `admin` flag on the user +account. This model would be compatible with all the built-in auth forms and +views, except for the User creation forms. + +This code would all live in a ``models.py`` file for a custom +authentication app:: + + from django.db import models + from django.contrib.auth.models import ( + BaseUserManager, AbstractBaseUser + ) + + + class MyUserManager(BaseUserManager): + def create_user(self, email, date_of_birth, password=None): + """ + Creates and saves a User with the given email, date of + birth and password. + """ + if not email: + raise ValueError('Users must have an email address') + + user = self.model( + email=MyUserManager.normalize_email(email), + date_of_birth=date_of_birth, + ) + + user.set_password(password) + user.save(using=self._db) + return user + + def create_superuser(self, email, date_of_birth, password): + """ + Creates and saves a superuser with the given email, date of + birth and password. + """ + user = self.create_user(email, + password=password, + date_of_birth=date_of_birth + ) + user.is_admin = True + user.save(using=self._db) + return user + + + class MyUser(AbstractBaseUser): + email = models.EmailField( + verbose_name='email address', + max_length=255, + unique=True, + db_index=True, + ) + date_of_birth = models.DateField() + is_active = models.BooleanField(default=True) + is_admin = models.BooleanField(default=False) + + objects = MyUserManager() + + USERNAME_FIELD = 'email' + REQUIRED_FIELDS = ['date_of_birth'] + + def get_full_name(self): + # The user is identified by their email address + return self.email + + def get_short_name(self): + # The user is identified by their email address + return self.email + + def __unicode__(self): + return self.email + + def has_perm(self, perm, obj=None): + "Does the user have a specific permission?" + # Simplest possible answer: Yes, always + return True + + def has_module_perms(self, app_label): + "Does the user have permissions to view the app `app_label`?" + # Simplest possible answer: Yes, always + return True + + @property + def is_staff(self): + "Is the user a member of staff?" + # Simplest possible answer: All admins are staff + return self.is_admin + +Then, to register this custom User model with Django's admin, the following +code would be required in the app's ``admin.py`` file:: + + from django import forms + from django.contrib import admin + from django.contrib.auth.models import Group + from django.contrib.auth.admin import UserAdmin + from django.contrib.auth.forms import ReadOnlyPasswordHashField + + from customauth.models import MyUser + + + class UserCreationForm(forms.ModelForm): + """A form for creating new users. Includes all the required + fields, plus a repeated password.""" + password1 = forms.CharField(label='Password', widget=forms.PasswordInput) + password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput) + + class Meta: + model = MyUser + fields = ('email', 'date_of_birth') + + def clean_password2(self): + # Check that the two password entries match + password1 = self.cleaned_data.get("password1") + password2 = self.cleaned_data.get("password2") + if password1 and password2 and password1 != password2: + raise forms.ValidationError("Passwords don't match") + return password2 + + def save(self, commit=True): + # Save the provided password in hashed format + user = super(UserCreationForm, self).save(commit=False) + user.set_password(self.cleaned_data["password1"]) + if commit: + user.save() + return user + + + class UserChangeForm(forms.ModelForm): + """A form for updateing users. Includes all the fields on + the user, but replaces the password field with admin's + pasword hash display field. + """ + password = ReadOnlyPasswordHashField() + + class Meta: + model = MyUser + + + class MyUserAdmin(UserAdmin): + # The forms to add and change user instances + form = UserChangeForm + add_form = UserCreationForm + + # The fields to be used in displaying the User model. + # These override the definitions on the base UserAdmin + # that reference specific fields on auth.User. + list_display = ('email', 'date_of_birth', 'is_admin') + list_filter = ('is_admin',) + fieldsets = ( + (None, {'fields': ('email', 'password')}), + ('Personal info', {'fields': ('date_of_birth',)}), + ('Permissions', {'fields': ('is_admin',)}), + ('Important dates', {'fields': ('last_login',)}), + ) + add_fieldsets = ( + (None, { + 'classes': ('wide',), + 'fields': ('email', 'date_of_birth', 'password1', 'password2')} + ), + ) + search_fields = ('email',) + ordering = ('email',) + filter_horizontal = () + + # Now register the new UserAdmin... + admin.site.register(MyUser, MyUserAdmin) + # ... and, since we're not using Django's builtin permissions, + # unregister the Group model from admin. + admin.site.unregister(Group) + .. _authentication-backends: Other authentication sources @@ -1951,8 +2519,6 @@ for example, to control anonymous access. Authorization for inactive users ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. versionchanged:: 1.3 - An inactive user is a one that is authenticated but has its attribute ``is_active`` set to ``False``. However this does not mean they are not authorized to do anything. For example they are allowed to activate their diff --git a/docs/topics/cache.txt b/docs/topics/cache.txt index f13238e342..2f95c33dd5 100644 --- a/docs/topics/cache.txt +++ b/docs/topics/cache.txt @@ -51,13 +51,6 @@ Your cache preference goes in the :setting:`CACHES` setting in your settings file. Here's an explanation of all available values for :setting:`CACHES`. -.. versionchanged:: 1.3 - The settings used to configure caching changed in Django 1.3. In - Django 1.2 and earlier, you used a single string-based - :setting:`CACHE_BACKEND` setting to configure caches. This has - been replaced with the new dictionary-based :setting:`CACHES` - setting. - .. _memcached: Memcached @@ -83,9 +76,6 @@ two most common are `python-memcached`_ and `pylibmc`_. .. _`python-memcached`: ftp://ftp.tummy.com/pub/python-memcached/ .. _`pylibmc`: http://sendapatch.se/projects/pylibmc/ -.. versionchanged:: 1.3 - Support for ``pylibmc`` was added. - To use Memcached with Django: * Set :setting:`BACKEND <CACHES-BACKEND>` to @@ -296,7 +286,7 @@ cache is multi-process and thread-safe. To use it, set The cache :setting:`LOCATION <CACHES-LOCATION>` is used to identify individual memory stores. If you only have one locmem cache, you can omit the -:setting:`LOCATION <CACHES-LOCATION>`; however, if you have more that one local +:setting:`LOCATION <CACHES-LOCATION>`; however, if you have more than one local memory cache, you will need to assign a name to at least one of them in order to keep them separate. @@ -673,12 +663,27 @@ dictionaries, lists of model objects, and so forth. (Most common Python objects can be pickled; refer to the Python documentation for more information about pickling.) +Accessing the cache +------------------- + The cache module, ``django.core.cache``, has a ``cache`` object that's automatically created from the ``'default'`` entry in the :setting:`CACHES` setting:: >>> from django.core.cache import cache +If you have multiple caches defined in :setting:`CACHES`, then you can use +:func:`django.core.cache.get_cache` to retrieve a cache object for any key:: + + >>> from django.core.cache import get_cache + >>> cache = get_cache('alternate') + +If the named key does not exist, :exc:`InvalidCacheBackendError` will be raised. + + +Basic usage +----------- + The basic interface is ``set(key, value, timeout)`` and ``get(key)``:: >>> cache.set('my_key', 'hello, world!', 30) @@ -686,7 +691,7 @@ The basic interface is ``set(key, value, timeout)`` and ``get(key)``:: 'hello, world!' The ``timeout`` argument is optional and defaults to the ``timeout`` -argument of the ``'default'`` backend in :setting:`CACHES` setting +argument of the appropriate backend in the :setting:`CACHES` setting (explained above). It's the number of seconds the value should be stored in the cache. @@ -785,8 +790,6 @@ nonexistent cache key.:: Cache key prefixing ------------------- -.. versionadded:: 1.3 - If you are sharing a cache instance between servers, or between your production and development environments, it's possible for data cached by one server to be used by another server. If the format of cached @@ -807,8 +810,6 @@ collisions in cache values. Cache versioning ---------------- -.. versionadded:: 1.3 - When you change running code that uses cached values, you may need to purge any existing cached values. The easiest way to do this is to flush the entire cache, but this can lead to the loss of cache values @@ -856,8 +857,6 @@ keys unaffected. Continuing our previous example:: Cache key transformation ------------------------ -.. versionadded:: 1.3 - As described in the previous two sections, the cache key provided by a user is not used verbatim -- it is combined with the cache prefix and key version to provide a final cache key. By default, the three parts @@ -878,8 +877,6 @@ be used instead of the default key combining function. Cache key warnings ------------------ -.. versionadded:: 1.3 - Memcached, the most commonly-used production cache backend, does not allow cache keys longer than 250 characters or containing whitespace or control characters, and using such keys will cause an exception. To encourage @@ -966,10 +963,6 @@ mechanism should take into account when building its cache key. For example, if the contents of a Web page depend on a user's language preference, the page is said to "vary on language." -.. versionchanged:: 1.3 - In Django 1.3 the full request path -- including the query -- is used - to create the cache keys, instead of only the path component in Django 1.2. - By default, Django's cache system creates its cache keys using the requested path and query -- e.g., ``"/stories/2005/?order_by=author"``. This means every request to that URL will use the same cached version, regardless of user-agent diff --git a/docs/topics/class-based-views/generic-display.txt b/docs/topics/class-based-views/generic-display.txt index 0d4cb6244d..10279c0f63 100644 --- a/docs/topics/class-based-views/generic-display.txt +++ b/docs/topics/class-based-views/generic-display.txt @@ -4,11 +4,6 @@ Class-based generic views ========================= -.. note:: - Prior to Django 1.3, generic views were implemented as functions. The - function-based implementation has been removed in favor of the - class-based approach described here. - Writing Web applications can be monotonous, because we repeat certain patterns again and again. Django tries to take away some of that monotony at the model and template layers, but Web developers also experience this boredom at the view diff --git a/docs/topics/class-based-views/generic-editing.txt b/docs/topics/class-based-views/generic-editing.txt index 23d346a32a..7bae3c692d 100644 --- a/docs/topics/class-based-views/generic-editing.txt +++ b/docs/topics/class-based-views/generic-editing.txt @@ -203,3 +203,43 @@ Note that you'll need to :ref:`decorate this view<decorating-class-based-views>` using :func:`~django.contrib.auth.decorators.login_required`, or alternatively handle unauthorised users in the :meth:`form_valid()`. + +AJAX example +------------ + +Here is a simple example showing how you might go about implementing a form that +works for AJAX requests as well as 'normal' form POSTs:: + + import json + + from django.http import HttpResponse + from django.views.generic.edit import CreateView + from django.views.generic.detail import SingleObjectTemplateResponseMixin + + class AjaxableResponseMixin(object): + """ + Mixin to add AJAX support to a form. + Must be used with an object-based FormView (e.g. CreateView) + """ + def render_to_json_response(self, context, **response_kwargs): + data = json.dumps(context) + response_kwargs['content_type'] = 'application/json' + return HttpResponse(data, **response_kwargs) + + def form_invalid(self, form): + if self.request.is_ajax(): + return self.render_to_json_response(form.errors, status=400) + else: + return super(AjaxableResponseMixin, self).form_invalid(form) + + def form_valid(self, form): + if self.request.is_ajax(): + data = { + 'pk': form.instance.pk, + } + return self.render_to_json_response(data) + else: + return super(AjaxableResponseMixin, self).form_valid(form) + + class AuthorCreate(AjaxableResponseMixin, CreateView): + model = Author diff --git a/docs/topics/class-based-views/index.txt b/docs/topics/class-based-views/index.txt index 2d3e00ab4c..a738221892 100644 --- a/docs/topics/class-based-views/index.txt +++ b/docs/topics/class-based-views/index.txt @@ -2,8 +2,6 @@ Class-based views ================= -.. versionadded:: 1.3 - A view is a callable which takes a request and returns a response. This can be more than just a function, and Django provides an example of some classes which can be used as views. These allow you diff --git a/docs/topics/class-based-views/mixins.txt b/docs/topics/class-based-views/mixins.txt index f07769fb8a..f349c23626 100644 --- a/docs/topics/class-based-views/mixins.txt +++ b/docs/topics/class-based-views/mixins.txt @@ -2,8 +2,6 @@ Using mixins with class-based views =================================== -.. versionadded:: 1.3 - .. caution:: This is an advanced topic. A working knowledge of :doc:`Django's diff --git a/docs/topics/db/models.txt b/docs/topics/db/models.txt index f29cc28332..84b4c84061 100644 --- a/docs/topics/db/models.txt +++ b/docs/topics/db/models.txt @@ -84,7 +84,9 @@ Fields The most important part of a model -- and the only required part of a model -- is the list of database fields it defines. Fields are specified by class -attributes. +attributes. Be careful not to choose field names that conflict with the +:doc:`models API </ref/models/instances>` like ``clean``, ``save``, or +``delete``. Example:: @@ -762,7 +764,7 @@ built-in model methods, adding new arguments. If you use ``*args, **kwargs`` in your method definitions, you are guaranteed that your code will automatically support those arguments when they are added. -.. admonition:: Overriding Delete +.. admonition:: Overridden model methods are not called on bulk operations Note that the :meth:`~Model.delete()` method for an object is not necessarily called when :ref:`deleting objects in bulk using a @@ -770,6 +772,13 @@ code will automatically support those arguments when they are added. gets executed, you can use :data:`~django.db.models.signals.pre_delete` and/or :data:`~django.db.models.signals.post_delete` signals. + Unfortunately, there isn't a workaround when + :meth:`creating<django.db.models.query.QuerySet.bulk_create>` or + :meth:`updating<django.db.models.query.QuerySet.update>` objects in bulk, + since none of :meth:`~Model.save()`, + :data:`~django.db.models.signals.pre_save`, and + :data:`~django.db.models.signals.post_save` are called. + Executing custom SQL -------------------- diff --git a/docs/topics/db/queries.txt b/docs/topics/db/queries.txt index 5385b2a72d..d826a39562 100644 --- a/docs/topics/db/queries.txt +++ b/docs/topics/db/queries.txt @@ -633,8 +633,6 @@ issue the query:: >>> Entry.objects.filter(authors__name=F('blog__name')) -.. versionadded:: 1.3 - For date and date/time fields, you can add or subtract a :class:`~datetime.timedelta` object. The following would return all entries that were modified more than 3 days after they were published:: @@ -642,6 +640,18 @@ that were modified more than 3 days after they were published:: >>> from datetime import timedelta >>> Entry.objects.filter(mod_date__gt=F('pub_date') + timedelta(days=3)) +.. versionadded:: 1.5 + ``.bitand()`` and ``.bitor()`` + +The ``F()`` objects now support bitwise operations by ``.bitand()`` and +``.bitor()``, for example:: + + >>> F('somefield').bitand(16) + +.. versionchanged:: 1.5 + The previously undocumented operators ``&`` and ``|`` no longer produce + bitwise operations, use ``.bitand()`` and ``.bitor()`` instead. + The pk lookup shortcut ---------------------- @@ -876,10 +886,9 @@ it. For example:: # This will delete the Blog and all of its Entry objects. b.delete() -.. versionadded:: 1.3 - This cascade behavior is customizable via the - :attr:`~django.db.models.ForeignKey.on_delete` argument to the - :class:`~django.db.models.ForeignKey`. +This cascade behavior is customizable via the +:attr:`~django.db.models.ForeignKey.on_delete` argument to the +:class:`~django.db.models.ForeignKey`. Note that :meth:`~django.db.models.query.QuerySet.delete` is the only :class:`~django.db.models.query.QuerySet` method that is not exposed on a @@ -953,7 +962,8 @@ new value to be the new model instance you want to point to. For example:: >>> Entry.objects.all().update(blog=b) The ``update()`` method is applied instantly and returns the number of rows -affected by the query. The only restriction on the +matched by the query (which may not be equal to the number of rows updated if +some rows already have the new value). The only restriction on the :class:`~django.db.models.query.QuerySet` that is updated is that it can only access one database table, the model's main table. You can filter based on related fields, but you can only update columns in the model's main diff --git a/docs/topics/db/sql.txt b/docs/topics/db/sql.txt index 19daffd464..310dcb5ae6 100644 --- a/docs/topics/db/sql.txt +++ b/docs/topics/db/sql.txt @@ -242,7 +242,7 @@ By default, the Python DB API will return results without their field names, which means you end up with a ``list`` of values, rather than a ``dict``. At a small performance cost, you can return results as a ``dict`` by using something like this:: - + def dictfetchall(cursor): "Returns all rows from a cursor as a dict" desc = cursor.description @@ -256,7 +256,7 @@ Here is an example of the difference between the two:: >>> cursor.execute("SELECT id, parent_id from test LIMIT 2"); >>> cursor.fetchall() ((54360982L, None), (54360880L, None)) - + >>> cursor.execute("SELECT id, parent_id from test LIMIT 2"); >>> dictfetchall(cursor) [{'parent_id': None, 'id': 54360982L}, {'parent_id': None, 'id': 54360880L}] @@ -273,11 +273,6 @@ transaction containing those calls is closed correctly. See :ref:`the notes on the requirements of Django's transaction handling <topics-db-transactions-requirements>` for more details. -.. versionchanged:: 1.3 - -Prior to Django 1.3, it was necessary to manually mark a transaction -as dirty using ``transaction.set_dirty()`` when using raw SQL calls. - Connections and cursors ----------------------- diff --git a/docs/topics/db/transactions.txt b/docs/topics/db/transactions.txt index 9928354664..4a52c5af35 100644 --- a/docs/topics/db/transactions.txt +++ b/docs/topics/db/transactions.txt @@ -66,9 +66,6 @@ database cursor (which is mapped to its own database connection internally). Controlling transaction management in views =========================================== -.. versionchanged:: 1.3 - Transaction management context managers are new in Django 1.3. - For most people, implicit request-based transactions work wonderfully. However, if you need more fine-grained control over how transactions are managed, you can use a set of functions in ``django.db.transaction`` to control transactions on a @@ -195,8 +192,6 @@ managers, too. Requirements for transaction handling ===================================== -.. versionadded:: 1.3 - Django requires that every transaction that is opened is closed before the completion of a request. If you are using :func:`autocommit` (the default commit mode) or :func:`commit_on_success`, this will be done diff --git a/docs/topics/email.txt b/docs/topics/email.txt index 0cc476e02c..b3d7254e7f 100644 --- a/docs/topics/email.txt +++ b/docs/topics/email.txt @@ -119,8 +119,6 @@ The "From:" header of the email will be the value of the This method exists for convenience and readability. -.. versionchanged:: 1.3 - If ``html_message`` is provided, the resulting email will be a :mimetype:`multipart/alternative` email with ``message`` as the :mimetype:`text/plain` content type and ``html_message`` as the @@ -236,9 +234,6 @@ following parameters (in the given order, if positional arguments are used). All parameters are optional and can be set at any time prior to calling the ``send()`` method. -.. versionchanged:: 1.3 - The ``cc`` argument was added. - * ``subject``: The subject line of the email. * ``body``: The body text. This should be a plain text message. diff --git a/docs/topics/forms/formsets.txt b/docs/topics/forms/formsets.txt index 2a83172e17..7c1771b758 100644 --- a/docs/topics/forms/formsets.txt +++ b/docs/topics/forms/formsets.txt @@ -35,19 +35,9 @@ display two blank forms:: >>> ArticleFormSet = formset_factory(ArticleForm, extra=2) -.. versionchanged:: 1.3 - -Prior to Django 1.3, formset instances were not iterable. To render -the formset you iterated over the ``forms`` attribute:: - - >>> formset = ArticleFormSet() - >>> for form in formset.forms: - ... print(form.as_table()) - -Iterating over ``formset.forms`` will render the forms in the order -they were created. The default formset iterator also renders the forms -in this order, but you can change this order by providing an alternate -implementation for the :meth:`__iter__()` method. +Iterating over the ``formset`` will render the forms in the order they were +created. You can change this order by providing an alternate implementation for +the :meth:`__iter__()` method. Formsets can also be indexed into, which returns the corresponding form. If you override ``__iter__``, you will need to also override ``__getitem__`` to have diff --git a/docs/topics/forms/media.txt b/docs/topics/forms/media.txt index 29a7829799..98e70e5e77 100644 --- a/docs/topics/forms/media.txt +++ b/docs/topics/forms/media.txt @@ -195,8 +195,6 @@ return values for dynamic media properties. Paths in media definitions -------------------------- -.. versionchanged:: 1.3 - Paths used to specify media can be either relative or absolute. If a path starts with ``/``, ``http://`` or ``https://``, it will be interpreted as an absolute path, and left as-is. All other paths will be prepended with the value diff --git a/docs/topics/forms/modelforms.txt b/docs/topics/forms/modelforms.txt index caff03c581..692be7cd7c 100644 --- a/docs/topics/forms/modelforms.txt +++ b/docs/topics/forms/modelforms.txt @@ -202,7 +202,7 @@ of cleaning the model you pass to the ``ModelForm`` constructor. For instance, calling ``is_valid()`` on your form will convert any date fields on your model to actual date objects. If form validation fails, only some of the updates may be applied. For this reason, you'll probably want to avoid reusing the -model instance. +model instance passed to the form, especially if validation fails. The ``save()`` method diff --git a/docs/topics/http/middleware.txt b/docs/topics/http/middleware.txt index fe92bc59a9..c27e7e8690 100644 --- a/docs/topics/http/middleware.txt +++ b/docs/topics/http/middleware.txt @@ -117,8 +117,6 @@ middleware is always called on every response. ``process_template_response`` ----------------------------- -.. versionadded:: 1.3 - .. method:: process_template_response(self, request, response) ``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is a @@ -166,6 +164,23 @@ an earlier middleware method returned an :class:`~django.http.HttpResponse` classes are applied in reverse order, from the bottom up. This means classes defined at the end of :setting:`MIDDLEWARE_CLASSES` will be run first. +.. versionchanged:: 1.5 + ``response`` may also be an :class:`~django.http.StreamingHttpResponse` + object. + +Unlike :class:`~django.http.HttpResponse`, +:class:`~django.http.StreamingHttpResponse` does not have a ``content`` +attribute. As a result, middleware can no longer assume that all responses +will have a ``content`` attribute. If they need access to the content, they +must test for streaming responses and adjust their behavior accordingly:: + + if response.streaming: + response.streaming_content = wrap_streaming_content(response.streaming_content) + else: + response.content = wrap_content(response.content) + +``streaming_content`` should be assumed to be too large to hold in memory. +Middleware may wrap it in a new generator, but must not consume it. .. _exception-middleware: diff --git a/docs/topics/http/sessions.txt b/docs/topics/http/sessions.txt index 1f55293413..15f9f7feba 100644 --- a/docs/topics/http/sessions.txt +++ b/docs/topics/http/sessions.txt @@ -524,6 +524,9 @@ consistently by all browsers. However, when it is honored, it can be a useful way to mitigate the risk of client side script accessing the protected cookie data. +.. versionchanged:: 1.4 + The default value of the setting was changed from ``False`` to ``True``. + .. _HTTPOnly: https://www.owasp.org/index.php/HTTPOnly SESSION_COOKIE_NAME diff --git a/docs/topics/http/shortcuts.txt b/docs/topics/http/shortcuts.txt index 10be353e80..0dc38b1459 100644 --- a/docs/topics/http/shortcuts.txt +++ b/docs/topics/http/shortcuts.txt @@ -17,8 +17,6 @@ introduce controlled coupling for convenience's sake. .. function:: render(request, template_name[, dictionary][, context_instance][, content_type][, status][, current_app]) - .. versionadded:: 1.3 - Combines a given template with a given context dictionary and returns an :class:`~django.http.HttpResponse` object with that rendered text. diff --git a/docs/topics/http/urls.txt b/docs/topics/http/urls.txt index 4503bbd6ef..e178df2af2 100644 --- a/docs/topics/http/urls.txt +++ b/docs/topics/http/urls.txt @@ -2,8 +2,6 @@ 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. @@ -55,7 +53,8 @@ algorithm the system follows to determine which Python code to execute: 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 + view, which is a simple Python function (or a :doc:`class based view + </topics/class-based-views/index>`). The view gets passed an :class:`~django.http.HttpRequest` as its first argument and any values captured in the regex as remaining arguments. @@ -159,7 +158,8 @@ vs. non-named groups in a regular expression: 2. Otherwise, it will pass all non-named arguments as positional arguments. -In both cases, any extra keyword arguments that have been given as per `Passing extra options to view functions`_ (below) will also be passed to the view. +In both cases, any extra keyword arguments that have been given as per `Passing +extra options to view functions`_ (below) will also be passed to the view. What the URLconf searches against ================================= @@ -214,7 +214,6 @@ Performance Each regular expression in a ``urlpatterns`` is compiled the first time it's accessed. This makes the system blazingly fast. - Syntax of the urlpatterns variable ================================== @@ -222,154 +221,35 @@ Syntax of the urlpatterns variable :func:`django.conf.urls.patterns`. Always use ``patterns()`` to create the ``urlpatterns`` variable. -``django.conf.urls`` utility functions -====================================== - -.. module:: django.conf.urls - -.. deprecated:: 1.4 - Starting with Django 1.4 functions ``patterns``, ``url``, ``include`` plus - the ``handler*`` symbols described below live in the ``django.conf.urls`` - module. - - Until Django 1.3 they were located in ``django.conf.urls.defaults``. You - still can import them from there but it will be removed in Django 1.6. - -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 remaining arguments should be tuples in this format:: - - (regular expression, Python callback function [, optional_dictionary [, optional_name]]) - -The ``optional_dictionary`` and ``optional_name`` parameters are described in -`Passing extra options to view functions`_ below. - -.. note:: - Because `patterns()` is a function call, it accepts a maximum of 255 - arguments (URL patterns, in this case). This is a limit for all Python - function calls. This is rarely a problem in practice, because you'll - typically structure your URL patterns modularly by using `include()` - sections. However, on the off-chance you do hit the 255-argument limit, - realize that `patterns()` returns a Python list, so you can split up the - construction of the list. - - :: - - urlpatterns = patterns('', - ... - ) - urlpatterns += patterns('', - ... - ) - - Python lists have unlimited size, so there's no limit to how many URL - patterns you can construct. The only limit is that you can only create 254 - at a time (the 255th argument is the initial prefix argument). - -url ---- - -.. 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:: - - urlpatterns = patterns('', - url(r'^index/$', index_view, name="main-view"), - ... - ) - -This function takes five arguments, most of which are optional:: - - url(regex, view, kwargs=None, name=None, prefix='') - -See `Naming URL patterns`_ for why the ``name`` parameter is useful. - -The ``prefix`` parameter has the same meaning as the first argument to -``patterns()`` and is only relevant when you're passing a string as the -``view`` parameter. - -include -------- - -.. function:: include(<module or pattern_list>) - -A function that takes a full Python import path to another URLconf module that -should be "included" in this place. - -:func:`include` also accepts as an argument an iterable that returns URL -patterns. - -See `Including other URLconfs`_ below. - Error handling ============== When Django can't find a regex matching the requested URL, or when an -exception is raised, Django will invoke an error-handling view. The -views to use for these cases are specified by three variables which can -be set in your root URLconf. Setting these variables in any other -URLconf will have no effect. +exception is raised, Django will invoke an error-handling view. -See the documentation on :ref:`customizing error views -<customizing-error-views>` for more details. +The views to use for these cases are specified by three variables. Their +default values should suffice for most projects, but further customization is +possible by assigning values to them. -handler403 ----------- +See the documentation on :ref:`customizing error views +<customizing-error-views>` for the full details. -.. data:: handler403 +Such values can be set in your root URLconf. Setting these variables in any +other URLconf will have no effect. -A callable, or a string representing the full Python import path to the view -that should be called if the user doesn't have the permissions required to -access a resource. +Values must be callables, or strings representing the full Python import path +to the view that should be called to handle the error condition at hand. -By default, this is ``'django.views.defaults.permission_denied'``. That default -value should suffice. +The variables are: -See the documentation about :ref:`the 403 (HTTP Forbidden) view -<http_forbidden_view>` for more information. +* ``handler404`` -- See :data:`django.conf.urls.handler404`. +* ``handler500`` -- See :data:`django.conf.urls.handler500`. +* ``handler403`` -- See :data:`django.conf.urls.handler403`. .. versionadded:: 1.4 ``handler403`` is new in Django 1.4. -handler404 ----------- - -.. data:: handler404 - -A callable, or a string representing the full Python import path to the view -that should be called if none of the URL patterns match. - -By default, this is ``'django.views.defaults.page_not_found'``. That default -value should suffice. - -See the documentation about :ref:`the 404 (HTTP Not Found) view -<http_not_found_view>` for more information. - -handler500 ----------- - -.. data:: handler500 - -A callable, or 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. - -By default, this is ``'django.views.defaults.server_error'``. That default -value should suffice. - -See the documentation about :ref:`the 500 (HTTP Internal Server Error) view -<http_internal_server_error_view>` for more information. +.. _urlpatterns-view-prefix: The view prefix =============== @@ -436,6 +316,8 @@ New:: (r'^tag/(?P<tag>\w+)/$', 'tag'), ) +.. _including-other-urlconfs: + Including other URLconfs ======================== @@ -445,7 +327,7 @@ essentially "roots" a set of URLs below other ones. For example, here's an excerpt of the URLconf for the `Django Web site`_ itself. It includes a number of other URLconfs:: - from django.conf.urls import patterns, url, include + from django.conf.urls import patterns, include urlpatterns = patterns('', # ... snip ... @@ -458,34 +340,30 @@ itself. It includes a number of other URLconfs:: Note that the regular expressions in this example don't have a ``$`` (end-of-string match character) but do include a trailing slash. Whenever -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. +Django encounters ``include()`` (:func:`django.conf.urls.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. 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:: +URLconf Python module defining them as the ``include()`` argument but by using +directly the pattern list as returned by :func:`~django.conf.urls.patterns` +instead. For example, consider this URLconf:: from django.conf.urls import patterns, url, include extra_patterns = patterns('', - url(r'^reports/(?P<id>\d+)/$', 'credit.views.report', name='credit-reports'), - url(r'^charge/$', 'credit.views.charge', name='credit-charge'), + url(r'^reports/(?P<id>\d+)/$', 'credit.views.report'), + url(r'^charge/$', 'credit.views.charge'), ) urlpatterns = patterns('', - url(r'^$', 'apps.main.views.homepage', name='site-homepage'), + url(r'^$', 'apps.main.views.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:`~django.contrib.admin.AdminSite`; each -:class:`~django.contrib.admin.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. +In this example, the ``/credit/reports/`` URL will be handled by the +``credit.views.report()`` Django view. .. _`Django Web site`: https://www.djangoproject.com/ @@ -509,57 +387,7 @@ the following example is valid:: In the above example, the captured ``"username"`` variable is passed to the included URLconf, as expected. -.. _topics-http-defining-url-namespaces: - -Defining URL namespaces ------------------------ - -When you need to deploy multiple instances of a single application, it can be -helpful to be able to differentiate between instances. This is especially -important when using :ref:`named URL patterns <naming-url-patterns>`, since -multiple instances of a single application will share named URLs. Namespaces -provide a way to tell these named URLs apart. - -A URL namespace comes in two parts, both of which are strings: - -* An **application namespace**. This describes the name of the application - that is being deployed. Every instance of a single application will have - the same application namespace. For example, Django's admin application - has the somewhat predictable application namespace of ``admin``. - -* An **instance namespace**. This identifies a specific instance of an - application. Instance namespaces should be unique across your entire - project. However, an instance namespace can be the same as the - application namespace. This is used to specify a default instance of an - application. For example, the default Django Admin instance has an - instance namespace of ``admin``. - -URL Namespaces can be specified in two ways. - -Firstly, you can provide the application and instance namespace as arguments -to ``include()`` when you construct your URL patterns. For example,:: - - (r'^help/', include('apps.help.urls', namespace='foo', app_name='bar')), - -This will include the URLs defined in ``apps.help.urls`` into the application -namespace ``bar``, with the instance namespace ``foo``. - -Secondly, you can include an object that contains embedded namespace data. If -you ``include()`` a ``patterns`` object, that object will be added to the -global namespace. However, you can also ``include()`` an object that contains -a 3-tuple containing:: - - (<patterns object>, <application namespace>, <instance namespace>) - -This will include the nominated URL patterns into the given application and -instance namespace. For example, the ``urls`` attribute of Django's -:class:`~django.contrib.admin.AdminSite` object returns a 3-tuple that contains -all the patterns in an admin site, plus the name of the admin instance, and the -application namespace ``admin``. - -Once you have defined namespaced URLs, you can reverse them. For details on -reversing namespaced urls, see the documentation on :ref:`reversing namespaced -URLs <topics-http-reversing-url-namespaces>`. +.. _views-extra-options: Passing extra options to view functions ======================================= @@ -593,9 +421,9 @@ options to views. Passing extra options to ``include()`` -------------------------------------- -Similarly, you can pass extra options to ``include()``. When you pass extra -options to ``include()``, *each* line in the included URLconf will be passed -the extra options. +Similarly, you can pass extra options to :func:`~django.conf.urls.include`. +When you pass extra options to ``include()``, *each* line in the included +URLconf will be passed the extra options. For example, these two URLconf sets are functionally identical: @@ -673,6 +501,112 @@ The style you use is up to you. Note that if you use this technique -- passing objects rather than strings -- the view prefix (as explained in "The view prefix" above) will have no effect. +Note that :doc:`class based views</topics/class-based-views/index>` must be +imported:: + + from mysite.views import ClassBasedView + + urlpatterns = patterns('', + (r'^myview/$', ClassBasedView.as_view()), + ) + +Reverse resolution of URLs +========================== + +A common need when working on a Django project is the possibility to obtain URLs +in their final forms either for embedding in generated content (views and assets +URLs, URLs shown to the user, etc.) or for handling of the navigation flow on +the server side (redirections, etc.) + +It is strongly desirable not having to hard-code these URLs (a laborious, +non-scalable and error-prone strategy) or having to devise ad-hoc mechanisms for +generating URLs that are parallel to the design described by the URLconf and as +such in danger of producing stale URLs at some point. + +In other words, what's needed is a DRY mechanism. Among other advantages it +would allow evolution of the URL design without having to go all over the +project source code to search and replace outdated URLs. + +The piece of information we have available as a starting point to get a URL is +an identification (e.g. the name) of the view in charge of handling it, other +pieces of information that necessarily must participate in the lookup of the +right URL are the types (positional, keyword) and values of the view arguments. + +Django provides a solution such that the URL mapper is the only repository of +the URL design. You feed it with your URLconf and then it can be used in both +directions: + +* Starting with a URL requested by the user/browser, it calls the right Django + view providing any arguments it might need with their values as extracted from + the URL. + +* Starting with the identification of the corresponding Django view plus the + values of arguments that would be passed to it, obtain the associated URL. + +The first one is the usage we've been discussing in the previous sections. The +second one is what is known as *reverse resolution of URLs*, *reverse URL +matching*, *reverse URL lookup*, or simply *URL reversing*. + +Django provides tools for performing URL reversing that match the different +layers where URLs are needed: + +* In templates: Using the :ttag:`url` template tag. + +* In Python code: Using the :func:`django.core.urlresolvers.reverse()` + function. + +* In higher level code related to handling of URLs of Django model instances: + The :meth:`django.db.models.Model.get_absolute_url()` method and the + :func:`django.db.models.permalink` decorator. + +Examples +-------- + +Consider again this URLconf entry:: + + from django.conf.urls import patterns, url + + urlpatterns = patterns('', + #... + url(r'^articles/(\d{4})/$', 'news.views.year_archive'), + #... + ) + +According to this design, the URL for the archive corresponding to year *nnnn* +is ``/articles/nnnn/``. + +You can obtain these in template code by using: + +.. code-block:: html+django + + <a href="{% url 'news.views.year_archive' 2012 %}">2012 Archive</a> + {# Or with the year in a template context variable: #} + <ul> + {% for yearvar in year_list %} + <li><a href="{% url 'news.views.year_archive' yearvar %}">{{ yearvar }} Archive</a></li> + {% endfor %} + </ul> + +Or in Python code:: + + from django.core.urlresolvers import reverse + from django.http import HttpResponseRedirect + + def redirect_to_year(request): + # ... + year = 2006 + # ... + return HttpResponseRedirect(reverse('news.views.year_archive', args=(year,))) + +If, for some reason, it was decided that the URLs where content for yearly +article archives are published at should be changed then you would only need to +change the entry in the URLconf. + +In some scenarios where views are of a generic nature, a many-to-one +relationship might exist between URLs and views. For these cases the view name +isn't a good enough identificator for it when it comes the time of reversing +URLs. Read the next section to know about the solution Django provides for this. + .. _naming-url-patterns: Naming URL patterns @@ -688,10 +622,10 @@ 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 -``archive`` view, Django's reverse URL matcher would get confused, because *two* -URL patterns point at that view. +URL matching (through the :func:`~django.db.models.permalink` decorator or the +:ttag:`url` template tag). Continuing this example, if you wanted to retrieve +the URL for the ``archive`` view, Django's reverse URL matcher would get +confused, because *two* URL patterns point at that view. To solve this problem, Django supports **named URL patterns**. That is, you can give a name to a URL pattern in order to distinguish it from other patterns @@ -731,24 +665,55 @@ 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: +.. _topics-http-defining-url-namespaces: URL namespaces --------------- +============== + +Introduction +------------ + +When you need to deploy multiple instances of a single application, it can be +helpful to be able to differentiate between instances. This is especially +important when using :ref:`named URL patterns <naming-url-patterns>`, since +multiple instances of a single application will share named URLs. Namespaces +provide a way to tell these named URLs apart. + +A URL namespace comes in two parts, both of which are strings: -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``. +.. glossary:: -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``. + 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'``. -When given a namespaced URL (e.g. ``myapp:index``) to resolve, Django splits + 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'``. + +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'``. + +.. _topics-http-reversing-url-namespaces: + +Reversing namespaced URLs +------------------------- + +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 +1. First, Django looks for a matching :term:`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 @@ -759,265 +724,101 @@ the fully qualified name into parts, and then tries the following lookup: render a template. The current application can also be specified manually as an argument - to the :func:`reverse()` function. + to the :func:`django.core.urlresolvers.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``). + that has an :term:`instance namespace` matching the :term:`application + namespace` (in this example, an instance of the ``myapp`` called + ``'myapp'``). 4. If there is no default application instance, Django will pick the last deployed instance of the application, whatever its instance name may be. -5. If the provided namespace doesn't match an application namespace in +5. If the provided namespace doesn't match an :term:`application namespace` in step 1, Django will attempt a direct lookup of the namespace as an - instance namespace. + :term:`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. +Example +~~~~~~~ + 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: +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``. + 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 last + somewhere else on the site - ``'myapp:index'`` will resolve to the last registered instance of ``myapp``. Since there is no default instance, the last instance of ``myapp`` that is registered will be used. This could - be ``foo`` or ``bar``, depending on the order they are introduced into the + 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``. +* ``'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 +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``. + 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 + 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``. - - -``django.core.urlresolvers`` utility functions -============================================== - -.. currentmodule:: django.core.urlresolvers - -reverse() ---------- +* ``'foo:index'`` will again resolve to the index page of the instance + ``'foo'``. -If you need to use something similar to the :ttag:`url` template tag in -your code, Django provides the following function (in the -:mod:`django.core.urlresolvers` module): +.. _namespaces-and-include: -.. function:: reverse(viewname, [urlconf=None, args=None, kwargs=None, current_app=None]) +URL namespaces and included URLconfs +------------------------------------ -``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 -`URL pattern name`_. Normally, you won't need to worry about the -``urlconf`` parameter and will only pass in the positional and keyword -arguments to use in the URL matching. For example:: +URL namespaces of included URLconfs can be specified in two ways. - from django.core.urlresolvers import reverse - - def myview(request): - return HttpResponseRedirect(reverse('arch-summary', args=[1945])) - -.. _URL pattern name: `Naming URL patterns`_ - -The ``reverse()`` function can reverse a large variety of regular expression -patterns for URLs, but not every possible one. The main restriction at the -moment is that the pattern cannot contain alternative choices using the -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. - -The ``current_app`` argument allows you to provide a hint to the resolver -indicating the application to which the currently executing view belongs. -This ``current_app`` argument is used as a hint to resolve application -namespaces into URLs on specific application instances, according to the -:ref:`namespaced URL resolution strategy <topics-http-reversing-url-namespaces>`. - -You can use ``kwargs`` instead of ``args``. For example:: +Firstly, you can provide the :term:`application <application namespace>` and +:term:`instance <instance namespace>` namespaces as arguments to +:func:`django.conf.urls.include()` when you construct your URL patterns. For +example,:: - >>> reverse('admin:app_list', kwargs={'app_label': 'auth'}) - '/admin/auth/' - -``args`` and ``kwargs`` cannot be passed to ``reverse()`` at the same time. - -.. admonition:: Make sure your views are all correct. - - As part of working out which URL names map to which patterns, the - ``reverse()`` function has to import all of your URLconf files and examine - the name of each view. This involves importing each view function. If - there are *any* errors whilst importing any of your view functions, it - will cause ``reverse()`` to raise an error, even if that view function is - not the one you are trying to reverse. - - Make sure that any views you reference in your URLconf files exist and can - be imported correctly. Do not include lines that reference views you - haven't written yet, because those views will not be importable. - -.. note:: - - The string returned by :meth:`~django.core.urlresolvers.reverse` is already - :ref:`urlquoted <uri-and-iri-handling>`. For example:: - - >>> reverse('cities', args=[u'Orléans']) - '.../Orl%C3%A9ans/' - - Applying further encoding (such as :meth:`~django.utils.http.urlquote` or - ``urllib.quote``) to the output of :meth:`~django.core.urlresolvers.reverse` - may produce undesirable results. - -reverse_lazy() --------------- - -.. versionadded:: 1.4 - -A lazily evaluated version of `reverse()`_. - -.. function:: reverse_lazy(viewname, [urlconf=None, args=None, kwargs=None, current_app=None]) - -It is useful for when you need to use a URL reversal before your project's -URLConf is loaded. Some common cases where this function is necessary are: - -* providing a reversed URL as the ``url`` attribute of a generic class-based - view. - -* providing a reversed URL to a decorator (such as the ``login_url`` argument - for the :func:`django.contrib.auth.decorators.permission_required` - decorator). - -* providing a reversed URL as a default value for a parameter in a function's - signature. - -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: - -.. function:: resolve(path, urlconf=None) - -``path`` is the URL path you want to resolve. As with -:func:`~django.core.urlresolvers.reverse`, you don't need to -worry about the ``urlconf`` parameter. The function returns a -:class:`ResolverMatch` object that allows you -to access various meta-data about the resolved URL. - -If the URL does not resolve, the function raises an -:class:`~django.http.Http404` exception. - -.. class:: ResolverMatch - - .. attribute:: ResolverMatch.func - - The view function that would be used to serve the URL - - .. attribute:: ResolverMatch.args - - The arguments that would be passed to the view function, as - parsed from the URL. - - .. attribute:: ResolverMatch.kwargs - - The keyword arguments that would be passed to the view - function, as parsed from the URL. - - .. attribute:: ResolverMatch.url_name - - The name of the URL pattern that matches the URL. - - .. attribute:: ResolverMatch.app_name - - The application namespace for the URL pattern that matches the - URL. - - .. attribute:: ResolverMatch.namespace - - The instance namespace for the URL pattern that matches the - URL. - - .. attribute:: ResolverMatch.namespaces - - The list of individual namespace components in the full - instance namespace for the URL pattern that matches the URL. - i.e., if the namespace is ``foo:bar``, then namespaces will be - ``['foo', 'bar']``. - -A :class:`ResolverMatch` object can then be interrogated to provide -information about the URL pattern that matches a URL:: - - # Resolve a URL - match = resolve('/some/path/') - # Print the URL pattern that matches the URL - print(match.url_name) - -A :class:`ResolverMatch` object can also be assigned to a triple:: - - func, args, kwargs = resolve('/some/path/') - -.. versionchanged:: 1.3 - Triple-assignment exists for backwards-compatibility. Prior to - Django 1.3, :func:`~django.core.urlresolvers.resolve` returned a - triple containing (view function, arguments, keyword arguments); - the :class:`ResolverMatch` object (as well as the namespace and pattern - information it provides) is not available in earlier Django releases. - -One possible use of :func:`~django.core.urlresolvers.resolve` would be to test -whether a view would raise a ``Http404`` error before redirecting to it:: - - from urlparse import urlparse - from django.core.urlresolvers import resolve - from django.http import HttpResponseRedirect, Http404 - - def myview(request): - next = request.META.get('HTTP_REFERER', None) or '/' - response = HttpResponseRedirect(next) + (r'^help/', include('apps.help.urls', namespace='foo', app_name='bar')), - # modify the request and response as required, e.g. change locale - # and set corresponding locale cookie +This will include the URLs defined in ``apps.help.urls`` into the +:term:`application namespace` ``'bar'``, with the :term:`instance namespace` +``'foo'``. - view, args, kwargs = resolve(urlparse(next)[2]) - kwargs['request'] = request - try: - view(*args, **kwargs) - except Http404: - return HttpResponseRedirect('/') - return response +Secondly, you can include an object that contains embedded namespace data. If +you ``include()`` an object as returned by :func:`~django.conf.urls.patterns`, +the URLs contained in that object will be added to the global namespace. +However, you can also ``include()`` a 3-tuple containing:: + (<patterns object>, <application namespace>, <instance namespace>) -permalink() ------------ +For example:: -The :func:`django.db.models.permalink` decorator is useful for writing short -methods that return a full URL path. For example, a model's -``get_absolute_url()`` method. See :func:`django.db.models.permalink` for more. + help_patterns = patterns('', + url(r'^basic/$', 'apps.help.views.views.basic'), + url(r'^advanced/$', 'apps.help.views.views.advanced'), + ) -get_script_prefix() -------------------- + (r'^help/', include(help_patterns, 'bar', 'foo')), -.. function:: get_script_prefix() +This will include the nominated URL patterns into the given application and +instance namespace. -Normally, you should always use :func:`~django.core.urlresolvers.reverse` or -:func:`~django.db.models.permalink` to define URLs within your application. -However, if your application constructs part of the URL hierarchy itself, you -may occasionally need to generate URLs. In that case, you need to be able to -find the base URL of the Django project within its Web server -(normally, :func:`~django.core.urlresolvers.reverse` takes care of this for -you). In that case, you can call ``get_script_prefix()``, which will return the -script prefix portion of the URL for your Django project. If your Django -project is at the root of its Web server, this is always ``"/"``. +For example, the Django Admin is deployed as instances of +:class:`~django.contrib.admin.AdminSite`. ``AdminSite`` objects have a ``urls`` +attribute: A 3-tuple that contains all the patterns in the corresponding admin +site, plus the application namespace ``'admin'``, and the name of the admin +instance. It is this ``urls`` attribute that you ``include()`` into your +projects ``urlpatterns`` when you deploy an Admin instance. diff --git a/docs/topics/http/views.txt b/docs/topics/http/views.txt index c4bd15e72e..7c4d1bbb6e 100644 --- a/docs/topics/http/views.txt +++ b/docs/topics/http/views.txt @@ -134,13 +134,12 @@ The 404 (page not found) view When you raise an ``Http404`` exception, Django loads a special view devoted to handling 404 errors. By default, it's the view -``django.views.defaults.page_not_found``, which loads and renders the template -``404.html``. +``django.views.defaults.page_not_found``, which either produces a very simple +"Not Found" message or loads and renders the template ``404.html`` if you +created it in your root template directory. -This means you need to define a ``404.html`` template in your root template -directory. This template will be used for all 404 errors. The default 404 view -will pass one variable to the template: ``request_path``, which is the URL -that resulted in the error. +The default 404 view will pass one variable to the template: ``request_path``, +which is the URL that resulted in the error. The ``page_not_found`` view should suffice for 99% of Web applications, but if you want to override it, you can specify ``handler404`` in your URLconf, like @@ -152,15 +151,11 @@ Behind the scenes, Django determines the 404 view by looking for ``handler404`` in your root URLconf, and falling back to ``django.views.defaults.page_not_found`` if you did not define one. -Four things to note about 404 views: +Three things to note about 404 views: * The 404 view is also called if Django doesn't find a match after checking every regular expression in the URLconf. -* If you don't define your own 404 view — and simply use the default, - which is recommended — you still have one obligation: you must create a - ``404.html`` template in the root of your template directory. - * The 404 view is passed a :class:`~django.template.RequestContext` and will have access to variables supplied by your :setting:`TEMPLATE_CONTEXT_PROCESSORS` setting (e.g., ``MEDIA_URL``). @@ -176,13 +171,12 @@ The 500 (server error) view Similarly, Django executes special-case behavior in the case of runtime errors in view code. If a view results in an exception, Django will, by default, call -the view ``django.views.defaults.server_error``, which loads and renders the -template ``500.html``. +the view ``django.views.defaults.server_error``, which either produces a very +simple "Server Error" message or loads and renders the template ``500.html`` if +you created it in your root template directory. -This means you need to define a ``500.html`` template in your root template -directory. This template will be used for all server errors. The default 500 -view passes no variables to this template and is rendered with an empty -``Context`` to lessen the chance of additional errors. +The default 500 view passes no variables to the ``500.html`` template and is +rendered with an empty ``Context`` to lessen the chance of additional errors. This ``server_error`` view should suffice for 99% of Web applications, but if you want to override the view, you can specify ``handler500`` in your URLconf, @@ -194,11 +188,7 @@ Behind the scenes, Django determines the 500 view by looking for ``handler500`` in your root URLconf, and falling back to ``django.views.defaults.server_error`` if you did not define one. -Two things to note about 500 views: - -* If you don't define your own 500 view — and simply use the default, - which is recommended — you still have one obligation: you must create a - ``500.html`` template in the root of your template directory. +One thing to note about 500 views: * If :setting:`DEBUG` is set to ``True`` (in your settings module), then your 500 view will never be used, and the traceback will be displayed diff --git a/docs/topics/i18n/formatting.txt b/docs/topics/i18n/formatting.txt index b09164769e..fc3f37de32 100644 --- a/docs/topics/i18n/formatting.txt +++ b/docs/topics/i18n/formatting.txt @@ -80,8 +80,6 @@ Template tags localize ~~~~~~~~ -.. versionadded:: 1.3 - Enables or disables localization of template variables in the contained block. @@ -116,8 +114,6 @@ Template filters localize ~~~~~~~~ -.. versionadded:: 1.3 - Forces localization of a single value. For example:: @@ -136,8 +132,6 @@ tag. unlocalize ~~~~~~~~~~ -.. versionadded:: 1.3 - Forces a single value to be printed without localization. For example:: diff --git a/docs/topics/i18n/translation.txt b/docs/topics/i18n/translation.txt index a7f48fe1fd..65c6fe2445 100644 --- a/docs/topics/i18n/translation.txt +++ b/docs/topics/i18n/translation.txt @@ -134,8 +134,6 @@ translations wouldn't be able to reorder placeholder text. Comments for translators ------------------------ -.. versionadded:: 1.3 - If you would like to give translators hints about a translatable string, you can add a comment prefixed with the ``Translators`` keyword on the line preceding the string, e.g.:: @@ -255,8 +253,6 @@ cardinality of the elements at play. Contextual markers ------------------ -.. versionadded:: 1.3 - Sometimes words have several meanings, such as ``"May"`` in English, which refers to a month name and to a verb. To enable translators to translate these words correctly in different contexts, you can use the @@ -431,13 +427,29 @@ In this case, the lazy translations in ``result`` will only be converted to strings when ``result`` itself is used in a string (usually at template rendering time). +Other uses of lazy in delayed translations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For any other case where you would like to delay the translation, but have to +pass the translatable string as argument to another function, you can wrap +this function inside a lazy call yourself. For example:: + + from django.utils import six # Python 3 compatibility + from django.utils.functional import lazy + from django.utils.safestring import mark_safe + from django.utils.translation import ugettext_lazy as _ + + mark_safe_lazy = lazy(mark_safe, six.text_type) + +And then later:: + + lazy_string = mark_safe_lazy(_("<p>My <strong>string!</strong></p>")) + Localized names of languages ---------------------------- .. function:: get_language_info -.. versionadded:: 1.3 - The ``get_language_info()`` function provides detailed information about languages:: @@ -535,9 +547,6 @@ using the ``context`` keyword: ``blocktrans`` template tag --------------------------- -.. versionchanged:: 1.3 - New keyword argument format. - Contrarily to the :ttag:`trans` tag, the ``blocktrans`` tag allows you to mark complex sentences consisting of literals and variable content for translation by making use of placeholders:: @@ -664,8 +673,6 @@ string, so they don't need to be aware of translations. translator might translate the string ``"yes,no"`` as ``"ja,nein"`` (keeping the comma intact). -.. versionadded:: 1.3 - You can also retrieve information about any of the available languages using provided template tags and filters. To get information about a single language, use the ``{% get_language_info %}`` tag:: @@ -787,10 +794,6 @@ directories listed in :setting:`LOCALE_PATHS` have the highest precedence with the ones appearing first having higher precedence than the ones appearing later. -.. versionchanged:: 1.3 - Directories listed in :setting:`LOCALE_PATHS` weren't included in the - lookup algorithm until version 1.3. - Using the JavaScript translation catalog ---------------------------------------- diff --git a/docs/topics/install.txt b/docs/topics/install.txt index 39b9a93c04..52994ed16a 100644 --- a/docs/topics/install.txt +++ b/docs/topics/install.txt @@ -80,7 +80,14 @@ Get your database running If you plan to use Django's database API functionality, you'll need to make sure a database server is running. Django supports many different database servers and is officially supported with PostgreSQL_, MySQL_, Oracle_ and -SQLite_ (although SQLite doesn't require a separate server to be running). +SQLite_. + +If you are developing a simple project or something you don't plan to deploy +in a production environment, SQLite is generally the simplest option as it +doesn't require running a separate server. However, SQLite has many differences +from other databases, so if you are working on something substantial, it's +recommended to develop with the same database as you plan on using in +production. In addition to the officially supported databases, there are backends provided by 3rd parties that allow you to use other databases with Django: diff --git a/docs/topics/logging.txt b/docs/topics/logging.txt index 28baf87522..7bd56e92ec 100644 --- a/docs/topics/logging.txt +++ b/docs/topics/logging.txt @@ -2,8 +2,6 @@ Logging ======= -.. versionadded:: 1.3 - .. module:: django.utils.log :synopsis: Logging tools for Django applications @@ -194,6 +192,8 @@ There are two other logging calls available: * ``logger.exception()``: Creates an ``ERROR`` level logging message wrapping the current exception stack frame. +.. _configuring-logging: + Configuring logging =================== @@ -218,6 +218,14 @@ handlers, filters and formatters that you want in your logging setup, and the log levels and other properties that you want those components to have. +Prior to Django 1.5, the :setting:`LOGGING` setting overwrote the :ref:`default +Django logging configuration <default-logging-configuration>`. From Django +1.5 forward, the project's logging configuration is merged with Django's +defaults, hence you can decide if you want to add to, or replace the existing +configuration. To completely override the default configuration, set the +``disable_existing_loggers`` key to True in the :setting:`LOGGING` +dictConfig. Alternatively you can redefine some or all of the loggers. + Logging is configured as soon as settings have been loaded (either manually using :func:`~django.conf.settings.configure` or when at least one setting is accessed). Since the loading of settings is one of the first @@ -347,36 +355,6 @@ This logging configuration does the following things: printed to the console; ``ERROR`` and ``CRITICAL`` messages will also be output via email. -.. admonition:: Custom handlers and circular imports - - If your ``settings.py`` specifies a custom handler class and the file - defining that class also imports ``settings.py`` a circular import will - occur. - - For example, if ``settings.py`` contains the following config for - :setting:`LOGGING`:: - - LOGGING = { - 'version': 1, - 'handlers': { - 'custom_handler': { - 'level': 'INFO', - 'class': 'myproject.logconfig.MyHandler', - } - } - } - - and ``myproject/logconfig.py`` has the following line before the - ``MyHandler`` definition:: - - from django.conf import settings - - then the ``dictconfig`` module will raise an exception like the following:: - - ValueError: Unable to configure handler 'custom_handler': - Unable to configure handler 'custom_handler': - 'module' object has no attribute 'logconfig' - .. _formatter documentation: http://docs.python.org/library/logging.html#formatter-objects Custom logging configuration @@ -567,3 +545,31 @@ logging module. 'class': 'django.utils.log.AdminEmailHandler' } }, + +.. class:: RequireDebugTrue() + + .. versionadded:: 1.5 + + This filter is similar to :class:`RequireDebugFalse`, except that records are + passed only when :setting:`DEBUG` is `True`. + +.. _default-logging-configuration: + +Django's default logging configuration +====================================== + +By default, Django configures the ``django.request`` logger so that all messages +with ``ERROR`` or ``CRITICAL`` level are sent to :class:`AdminEmailHandler`, as +long as the :setting:`DEBUG` setting is set to ``False``. + +All messages reaching the ``django`` catch-all logger when :setting:`DEBUG` is +`True` are sent ot the console. They are simply discarded (sent to +``NullHandler``) when :setting:`DEBUG` is `False`. + +.. versionchanged:: 1.5 + + Before Django 1.5, all messages reaching the ``django`` logger were + discarded, regardless of :setting:`DEBUG`. + +See also :ref:`Configuring logging <configuring-logging>` to learn how you can +complement or replace this default logging configuration. diff --git a/docs/topics/serialization.txt b/docs/topics/serialization.txt index ac1a77ed98..9b44166e42 100644 --- a/docs/topics/serialization.txt +++ b/docs/topics/serialization.txt @@ -130,6 +130,14 @@ trust your data source you could just save the object and move on. The Django object itself can be inspected as ``deserialized_object.object``. +.. versionadded:: 1.5 + +If fields in the serialized data do not exist on a model, +a ``DeserializationError`` will be raised unless the ``ignorenonexistent`` +argument is passed in as True:: + + serializers.deserialize("xml", data, ignorenonexistent=True) + .. _serialization-formats: Serialization formats diff --git a/docs/topics/signals.txt b/docs/topics/signals.txt index db1bcb03df..1078d0372c 100644 --- a/docs/topics/signals.txt +++ b/docs/topics/signals.txt @@ -132,10 +132,6 @@ Now, our ``my_callback`` function will be called each time a request finishes. Note that ``receiver`` can also take a list of signals to connect a function to. -.. versionadded:: 1.3 - -The ``receiver`` decorator was added in Django 1.3. - .. versionchanged:: 1.5 The ability to pass a list of signals was added. diff --git a/docs/topics/testing.txt b/docs/topics/testing.txt index c4c73733f5..d0b2e7cdf9 100644 --- a/docs/topics/testing.txt +++ b/docs/topics/testing.txt @@ -73,8 +73,6 @@ module defines tests in class-based approach. .. admonition:: unittest2 - .. versionchanged:: 1.3 - Python 2.7 introduced some major changes to the unittest library, adding some extremely useful features. To ensure that every Django project can benefit from these new features, Django ships with a @@ -436,8 +434,6 @@ two databases. Controlling creation order for test databases ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 1.3 - By default, Django will always create the ``default`` database first. However, no guarantees are made on the creation order of any other databases in your test setup. @@ -512,6 +508,13 @@ file, all Django tests run with :setting:`DEBUG`\=False. This is to ensure that the observed output of your code matches what will be seen in a production setting. +Caches are not cleared after each test, and running "manage.py test fooapp" can +insert data from the tests into the cache of a live system if you run your +tests in production because, unlike databases, a separate "test cache" is not +used. This behavior `may change`_ in the future. + +.. _may change: https://code.djangoproject.com/ticket/11505 + Understanding the test output ----------------------------- @@ -586,6 +589,36 @@ to a faster hashing algorithm:: Don't forget to also include in :setting:`PASSWORD_HASHERS` any hashing algorithm used in fixtures, if any. +.. _topics-testing-code-coverage: + +Integration with coverage.py +---------------------------- + +Code coverage describes how much source code has been tested. It shows which +parts of your code are being exercised by tests and which are not. It's an +important part of testing applications, so it's strongly recommended to check +the coverage of your tests. + +Django can be easily integrated with `coverage.py`_, a tool for measuring code +coverage of Python programs. First, `install coverage.py`_. Next, run the +following from your project folder containing ``manage.py``:: + + coverage run --source='.' manage.py test myapp + +This runs your tests and collects coverage data of the executed files in your +project. You can see a report of this data by typing following command:: + + coverage report + +Note that some Django code was executed while running tests, but it is not +listed here because of the ``source`` flag passed to the previous command. + +For more options like annotated HTML listings detailing missed lines, see the +`coverage.py`_ docs. + +.. _coverage.py: http://nedbatchelder.com/code/coverage/ +.. _install coverage.py: http://pypi.python.org/pypi/coverage + Testing tools ============= @@ -766,7 +799,7 @@ Use the ``django.test.client.Client`` class to make requests. and a ``redirect_chain`` attribute will be set in the response object containing tuples of the intermediate urls and status codes. - If you had an url ``/redirect_me/`` that redirected to ``/next/``, that + If you had a URL ``/redirect_me/`` that redirected to ``/next/``, that redirected to ``/final/``, this is what you'd see:: >>> response = c.get('/redirect_me/', follow=True) @@ -1001,8 +1034,6 @@ Specifically, a ``Response`` object has the following attributes: The HTTP status of the response, as an integer. See :rfc:`2616#section-10` for a full list of HTTP status codes. - .. versionadded:: 1.3 - .. attribute:: templates A list of ``Template`` instances used to render the final content, in @@ -1089,8 +1120,6 @@ The request factory .. class:: RequestFactory -.. versionadded:: 1.3 - The :class:`~django.test.client.RequestFactory` shares the same API as the test client. However, instead of behaving like a browser, the RequestFactory provides a way to generate a request instance that can @@ -1327,8 +1356,6 @@ This means, instead of instantiating a ``Client`` in each test:: Customizing the test client ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 1.3 - .. attribute:: TestCase.client_class If you want to use a different ``Client`` class (for example, a subclass @@ -1625,7 +1652,7 @@ your test suite. "a@a.com" as a valid email address, but rejects "aaa" with a reasonable error message:: - self.assertFieldOutput(EmailField, {'a@a.com': 'a@a.com'}, {'aaa': [u'Enter a valid e-mail address.']}) + self.assertFieldOutput(EmailField, {'a@a.com': 'a@a.com'}, {'aaa': [u'Enter a valid email address.']}) .. method:: TestCase.assertContains(response, text, count=None, status_code=200, msg_prefix='', html=False) @@ -1708,8 +1735,6 @@ your test suite. .. method:: TestCase.assertQuerysetEqual(qs, values, transform=repr, ordered=True) - .. versionadded:: 1.3 - Asserts that a queryset ``qs`` returns a particular list of values ``values``. The comparison of the contents of ``qs`` and ``values`` is performed using @@ -1730,8 +1755,6 @@ your test suite. .. method:: TestCase.assertNumQueries(num, func, *args, **kwargs) - .. versionadded:: 1.3 - Asserts that when ``func`` is called with ``*args`` and ``**kwargs`` that ``num`` database queries are executed. @@ -1790,6 +1813,25 @@ your test suite. ``html1`` and ``html2`` must be valid HTML. An ``AssertionError`` will be raised if one of them cannot be parsed. +.. method:: SimpleTestCase.assertXMLEqual(xml1, xml2, msg=None) + + .. versionadded:: 1.5 + + Asserts that the strings ``xml1`` and ``xml2`` are equal. The + comparison is based on XML semantics. Similarily to + :meth:`~SimpleTestCase.assertHTMLEqual`, the comparison is + made on parsed content, hence only semantic differences are considered, not + syntax differences. When unvalid XML is passed in any parameter, an + ``AssertionError`` is always raised, even if both string are identical. + +.. method:: SimpleTestCase.assertXMLNotEqual(xml1, xml2, msg=None) + + .. versionadded:: 1.5 + + Asserts that the strings ``xml1`` and ``xml2`` are *not* equal. The + comparison is based on XML semantics. See + :meth:`~SimpleTestCase.assertXMLEqual` for details. + .. _topics-testing-email: Email services @@ -1854,8 +1896,6 @@ Skipping tests .. currentmodule:: django.test -.. versionadded:: 1.3 - The unittest library provides the :func:`@skipIf <unittest.skipIf>` and :func:`@skipUnless <unittest.skipUnless>` decorators to allow you to skip tests if you know ahead of time that those tests are going to fail under certain @@ -1982,8 +2022,8 @@ Then, add a ``LiveServerTestCase``-based test to your app's tests module @classmethod def tearDownClass(cls): - super(MySeleniumTests, cls).tearDownClass() cls.selenium.quit() + super(MySeleniumTests, cls).tearDownClass() def test_login(self): self.selenium.get('%s%s' % (self.live_server_url, '/login/')) |
