mirror of
https://github.com/django/django.git
synced 2025-08-03 18:38:50 +00:00
Massive reorganization of the docs. See the new docs online at http://docs.djangoproject.com/.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8506 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
b3688e8194
commit
97cb07c3a1
188 changed files with 19913 additions and 17059 deletions
BIN
docs/topics/http/_images/middleware.png
Normal file
BIN
docs/topics/http/_images/middleware.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 55 KiB |
328
docs/topics/http/file-uploads.txt
Normal file
328
docs/topics/http/file-uploads.txt
Normal file
|
@ -0,0 +1,328 @@
|
|||
.. _topics-file-uploads:
|
||||
|
||||
============
|
||||
File Uploads
|
||||
============
|
||||
|
||||
.. currentmodule:: django.core.files
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
Most Web sites wouldn't be complete without a way to upload files. When Django
|
||||
handles a file upload, the file data ends up placed in ``request.FILES`` (for
|
||||
more on the ``request`` object see the documentation for :ref:`request and
|
||||
response objects <ref-request-response>`). This document explains how files are
|
||||
stored on disk and in memory, and how to customize the default behavior.
|
||||
|
||||
Basic file uploads
|
||||
==================
|
||||
|
||||
Consider a simple form containing a ``FileField``::
|
||||
|
||||
from django import forms
|
||||
|
||||
class UploadFileForm(forms.Form):
|
||||
title = forms.CharField(max_length=50)
|
||||
file = forms.FileField()
|
||||
|
||||
A view handling this form will receive the file data in ``request.FILES``, which
|
||||
is a dictionary containing a key for each ``FileField`` (or ``ImageField``, or
|
||||
other ``FileField`` subclass) in the form. So the data from the above form would
|
||||
be accessible as ``request.FILES['file']``.
|
||||
|
||||
Most of the time, you'll simply pass the file data from ``request`` into the
|
||||
form as described in :ref:`binding-uploaded-files`. This would look
|
||||
something like::
|
||||
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import render_to_response
|
||||
|
||||
# Imaginary function to handle an uploaded file.
|
||||
from somewhere import handle_uploaded_file
|
||||
|
||||
def upload_file(request):
|
||||
if request.method == 'POST':
|
||||
form = UploadFileForm(request.POST, request.FILES)
|
||||
if form.is_valid():
|
||||
handle_uploaded_file(request.FILES['file'])
|
||||
return HttpResponseRedirect('/success/url/')
|
||||
else:
|
||||
form = UploadFileForm()
|
||||
return render_to_response('upload.html', {'form': form})
|
||||
|
||||
Notice that we have to pass ``request.FILES`` into the form's constructor; this
|
||||
is how file data gets bound into a form.
|
||||
|
||||
Handling uploaded files
|
||||
-----------------------
|
||||
|
||||
The final piece of the puzzle is handling the actual file data from
|
||||
``request.FILES``. Each entry in this dictionary is an ``UploadedFile`` object
|
||||
-- a simple wrapper around an uploaded file. You'll usually use one of these
|
||||
methods to access the uploaded content:
|
||||
|
||||
``UploadedFile.read()``
|
||||
Read the entire uploaded data from the file. Be careful with this
|
||||
method: if the uploaded file is huge it can overwhelm your system if you
|
||||
try to read it into memory. You'll probably want to use ``chunks()``
|
||||
instead; see below.
|
||||
|
||||
``UploadedFile.multiple_chunks()``
|
||||
Returns ``True`` if the uploaded file is big enough to require
|
||||
reading in multiple chunks. By default this will be any file
|
||||
larger than 2.5 megabytes, but that's configurable; see below.
|
||||
|
||||
``UploadedFile.chunks()``
|
||||
A generator returning chunks of the file. If ``multiple_chunks()`` is
|
||||
``True``, you should use this method in a loop instead of ``read()``.
|
||||
|
||||
In practice, it's often easiest simply to use ``chunks()`` all the time;
|
||||
see the example below.
|
||||
|
||||
``UploadedFile.name``
|
||||
The name of the uploaded file (e.g. ``my_file.txt``).
|
||||
|
||||
``UploadedFile.size``
|
||||
The size, in bytes, of the uploaded file.
|
||||
|
||||
There are a few other methods and attributes available on ``UploadedFile``
|
||||
objects; see `UploadedFile objects`_ for a complete reference.
|
||||
|
||||
Putting it all together, here's a common way you might handle an uploaded file::
|
||||
|
||||
def handle_uploaded_file(f):
|
||||
destination = open('some/file/name.txt', 'wb+')
|
||||
for chunk in f.chunks():
|
||||
destination.write(chunk)
|
||||
|
||||
Looping over ``UploadedFile.chunks()`` instead of using ``read()`` ensures that
|
||||
large files don't overwhelm your system's memory.
|
||||
|
||||
Where uploaded data is stored
|
||||
-----------------------------
|
||||
|
||||
Before you save uploaded files, the data needs to be stored somewhere.
|
||||
|
||||
By default, if an uploaded file is smaller than 2.5 megabytes, Django will hold
|
||||
the entire contents of the upload in memory. This means that saving the file
|
||||
involves only a read from memory and a write to disk and thus is very fast.
|
||||
|
||||
However, if an uploaded file is too large, Django will write the uploaded file
|
||||
to a temporary file stored in your system's temporary directory. On a Unix-like
|
||||
platform this means you can expect Django to generate a file called something
|
||||
like ``/tmp/tmpzfp6I6.upload``. If an upload is large enough, you can watch this
|
||||
file grow in size as Django streams the data onto disk.
|
||||
|
||||
These specifics -- 2.5 megabytes; ``/tmp``; etc. -- are simply "reasonable
|
||||
defaults". Read on for details on how you can customize or completely replace
|
||||
upload behavior.
|
||||
|
||||
Changing upload handler behavior
|
||||
--------------------------------
|
||||
|
||||
Three settings control Django's file upload behavior:
|
||||
|
||||
``FILE_UPLOAD_MAX_MEMORY_SIZE``
|
||||
The maximum size, in bytes, for files that will be uploaded
|
||||
into memory. Files larger than ``FILE_UPLOAD_MAX_MEMORY_SIZE``
|
||||
will be streamed to disk.
|
||||
|
||||
Defaults to 2.5 megabytes.
|
||||
|
||||
``FILE_UPLOAD_TEMP_DIR``
|
||||
The directory where uploaded files larger than ``FILE_UPLOAD_TEMP_DIR``
|
||||
will be stored.
|
||||
|
||||
Defaults to your system's standard temporary directory (i.e. ``/tmp`` on
|
||||
most Unix-like systems).
|
||||
|
||||
``FILE_UPLOAD_HANDLERS``
|
||||
The actual handlers for uploaded files. Changing this setting
|
||||
allows complete customization -- even replacement -- of
|
||||
Django's upload process. See `upload handlers`_, below,
|
||||
for details.
|
||||
|
||||
Defaults to::
|
||||
|
||||
("django.core.files.uploadhandler.MemoryFileUploadHandler",
|
||||
"django.core.files.uploadhandler.TemporaryFileUploadHandler",)
|
||||
|
||||
Which means "try to upload to memory first, then fall back to temporary
|
||||
files."
|
||||
|
||||
``UploadedFile`` objects
|
||||
========================
|
||||
|
||||
.. class:: UploadedFile
|
||||
|
||||
In addition to those inherited from :class:`File`, all ``UploadedFile`` objects
|
||||
define the following methods/attributes:
|
||||
|
||||
``UploadedFile.content_type``
|
||||
The content-type header uploaded with the file (e.g. ``text/plain`` or
|
||||
``application/pdf``). Like any data supplied by the user, you shouldn't
|
||||
trust that the uploaded file is actually this type. You'll still need to
|
||||
validate that the file contains the content that the content-type header
|
||||
claims -- "trust but verify."
|
||||
|
||||
``UploadedFile.charset``
|
||||
For ``text/*`` content-types, the character set (i.e. ``utf8``) supplied
|
||||
by the browser. Again, "trust but verify" is the best policy here.
|
||||
|
||||
``UploadedFile.temporary_file_path()``
|
||||
Only files uploaded onto disk will have this method; it returns the full
|
||||
path to the temporary uploaded file.
|
||||
|
||||
Upload Handlers
|
||||
===============
|
||||
|
||||
When a user uploads a file, Django passes off the file data to an *upload
|
||||
handler* -- a small class that handles file data as it gets uploaded. Upload
|
||||
handlers are initially defined in the ``FILE_UPLOAD_HANDLERS`` setting, which
|
||||
defaults to::
|
||||
|
||||
("django.core.files.uploadhandler.MemoryFileUploadHandler",
|
||||
"django.core.files.uploadhandler.TemporaryFileUploadHandler",)
|
||||
|
||||
Together the ``MemoryFileUploadHandler`` and ``TemporaryFileUploadHandler``
|
||||
provide Django's default file upload behavior of reading small files into memory
|
||||
and large ones onto disk.
|
||||
|
||||
You can write custom handlers that customize how Django handles files. You
|
||||
could, for example, use custom handlers to enforce user-level quotas, compress
|
||||
data on the fly, render progress bars, and even send data to another storage
|
||||
location directly without storing it locally.
|
||||
|
||||
Modifying upload handlers on the fly
|
||||
------------------------------------
|
||||
|
||||
Sometimes particular views require different upload behavior. In these cases,
|
||||
you can override upload handlers on a per-request basis by modifying
|
||||
``request.upload_handlers``. By default, this list will contain the upload
|
||||
handlers given by ``FILE_UPLOAD_HANDLERS``, but you can modify the list as you
|
||||
would any other list.
|
||||
|
||||
For instance, suppose you've written a ``ProgressBarUploadHandler`` that
|
||||
provides feedback on upload progress to some sort of AJAX widget. You'd add this
|
||||
handler to your upload handlers like this::
|
||||
|
||||
request.upload_handlers.insert(0, ProgressBarUploadHandler())
|
||||
|
||||
You'd probably want to use ``list.insert()`` in this case (instead of
|
||||
``append()``) because a progress bar handler would need to run *before* any
|
||||
other handlers. Remember, the upload handlers are processed in order.
|
||||
|
||||
If you want to replace the upload handlers completely, you can just assign a new
|
||||
list::
|
||||
|
||||
request.upload_handlers = [ProgressBarUploadHandler()]
|
||||
|
||||
.. note::
|
||||
|
||||
You can only modify upload handlers *before* accessing ``request.FILES`` --
|
||||
it doesn't make sense to change upload handlers after upload handling has
|
||||
already started. If you try to modify ``request.upload_handlers`` after
|
||||
reading from ``request.FILES`` Django will throw an error.
|
||||
|
||||
Thus, you should always modify uploading handlers as early in your view as
|
||||
possible.
|
||||
|
||||
Writing custom upload handlers
|
||||
------------------------------
|
||||
|
||||
All file upload handlers should be subclasses of
|
||||
``django.core.files.uploadhandler.FileUploadHandler``. You can define upload
|
||||
handlers wherever you wish.
|
||||
|
||||
Required methods
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Custom file upload handlers **must** define the following methods:
|
||||
|
||||
``FileUploadHandler.receive_data_chunk(self, raw_data, start)``
|
||||
Receives a "chunk" of data from the file upload.
|
||||
|
||||
``raw_data`` is a byte string containing the uploaded data.
|
||||
|
||||
``start`` is the position in the file where this ``raw_data`` chunk
|
||||
begins.
|
||||
|
||||
The data you return will get fed into the subsequent upload handlers'
|
||||
``receive_data_chunk`` methods. In this way, one handler can be a
|
||||
"filter" for other handlers.
|
||||
|
||||
Return ``None`` from ``receive_data_chunk`` to sort-circuit remaining
|
||||
upload handlers from getting this chunk.. This is useful if you're
|
||||
storing the uploaded data yourself and don't want future handlers to
|
||||
store a copy of the data.
|
||||
|
||||
If you raise a ``StopUpload`` or a ``SkipFile`` exception, the upload
|
||||
will abort or the file will be completely skipped.
|
||||
|
||||
``FileUploadHandler.file_complete(self, file_size)``
|
||||
Called when a file has finished uploading.
|
||||
|
||||
The handler should return an ``UploadedFile`` object that will be stored
|
||||
in ``request.FILES``. Handlers may also return ``None`` to indicate that
|
||||
the ``UploadedFile`` object should come from subsequent upload handlers.
|
||||
|
||||
Optional methods
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Custom upload handlers may also define any of the following optional methods or
|
||||
attributes:
|
||||
|
||||
``FileUploadHandler.chunk_size``
|
||||
Size, in bytes, of the "chunks" Django should store into memory and feed
|
||||
into the handler. That is, this attribute controls the size of chunks
|
||||
fed into ``FileUploadHandler.receive_data_chunk``.
|
||||
|
||||
For maximum performance the chunk sizes should be divisible by ``4`` and
|
||||
should not exceed 2 GB (2\ :sup:`31` bytes) in size. When there are
|
||||
multiple chunk sizes provided by multiple handlers, Django will use the
|
||||
smallest chunk size defined by any handler.
|
||||
|
||||
The default is 64*2\ :sup:`10` bytes, or 64 KB.
|
||||
|
||||
``FileUploadHandler.new_file(self, field_name, file_name, content_type, content_length, charset)``
|
||||
Callback signaling that a new file upload is starting. This is called
|
||||
before any data has been fed to any upload handlers.
|
||||
|
||||
``field_name`` is a string name of the file ``<input>`` field.
|
||||
|
||||
``file_name`` is the unicode filename that was provided by the browser.
|
||||
|
||||
``content_type`` is the MIME type provided by the browser -- E.g.
|
||||
``'image/jpeg'``.
|
||||
|
||||
``content_length`` is the length of the image given by the browser.
|
||||
Sometimes this won't be provided and will be ``None``., ``None``
|
||||
otherwise.
|
||||
|
||||
``charset`` is the character set (i.e. ``utf8``) given by the browser.
|
||||
Like ``content_length``, this sometimes won't be provided.
|
||||
|
||||
This method may raise a ``StopFutureHandlers`` exception to prevent
|
||||
future handlers from handling this file.
|
||||
|
||||
``FileUploadHandler.upload_complete(self)``
|
||||
Callback signaling that the entire upload (all files) has completed.
|
||||
|
||||
``FileUploadHandler.handle_raw_input(self, input_data, META, content_length, boundary, encoding)``
|
||||
Allows the handler to completely override the parsing of the raw
|
||||
HTTP input.
|
||||
|
||||
``input_data`` is a file-like object that supports ``read()``-ing.
|
||||
|
||||
``META`` is the same object as ``request.META``.
|
||||
|
||||
``content_length`` is the length of the data in ``input_data``. Don't
|
||||
read more than ``content_length`` bytes from ``input_data``.
|
||||
|
||||
``boundary`` is the MIME boundary for this request.
|
||||
|
||||
``encoding`` is the encoding of the request.
|
||||
|
||||
Return ``None`` if you want upload handling to continue, or a tuple of
|
||||
``(POST, FILES)`` if you want to return the new data structures suitable
|
||||
for the request directly.
|
7
docs/topics/http/generic-views.txt
Normal file
7
docs/topics/http/generic-views.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
.. _topics-http-generic-views:
|
||||
|
||||
=============
|
||||
Generic views
|
||||
=============
|
||||
|
||||
See :ref:`ref-generic-views`.
|
17
docs/topics/http/index.txt
Normal file
17
docs/topics/http/index.txt
Normal file
|
@ -0,0 +1,17 @@
|
|||
.. _topics-http-index:
|
||||
|
||||
Handling HTTP requests
|
||||
======================
|
||||
|
||||
Information on handling HTTP requests in Django:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
urls
|
||||
views
|
||||
file-uploads
|
||||
shortcuts
|
||||
generic-views
|
||||
middleware
|
||||
sessions
|
169
docs/topics/http/middleware.txt
Normal file
169
docs/topics/http/middleware.txt
Normal file
|
@ -0,0 +1,169 @@
|
|||
.. _topics-http-middleware:
|
||||
|
||||
==========
|
||||
Middleware
|
||||
==========
|
||||
|
||||
Middleware is a framework of hooks into Django's request/response processing.
|
||||
It's a light, low-level "plugin" system for globally altering Django's input
|
||||
and/or output.
|
||||
|
||||
Each middleware component is responsible for doing some specific function. For
|
||||
example, Django includes a middleware component, ``XViewMiddleware``, that adds
|
||||
an ``"X-View"`` HTTP header to every response to a ``HEAD`` request.
|
||||
|
||||
This document explains how middleware works, how you activate middleware, and
|
||||
how to write your own middleware. Django ships with some built-in middleware you
|
||||
can use right out of the box; they're documented in the :ref:`built-in
|
||||
middleware guide <ref-middleware>`.
|
||||
|
||||
Activating middleware
|
||||
=====================
|
||||
|
||||
To activate a middleware component, add it to the :setting:`MIDDLEWARE_CLASSES`
|
||||
list in your Django settings. In :setting:`MIDDLEWARE_CLASSES`, each middleware
|
||||
component is represented by a string: the full Python path to the middleware's
|
||||
class name. For example, here's the default :setting:`MIDDLEWARE_CLASSES`
|
||||
created by :djadmin:`django-admin.py startproject <startproject>`::
|
||||
|
||||
MIDDLEWARE_CLASSES = (
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.middleware.doc.XViewMiddleware',
|
||||
)
|
||||
|
||||
During the request phases (:meth:`process_request` and :meth:`process_view`
|
||||
middleware), Django applies middleware in the order it's defined in
|
||||
:setting:`MIDDLEWARE_CLASSES`, top-down. During the response phases
|
||||
(:meth:`process_response` and :meth:`process_exception` middleware), the classes
|
||||
are applied in reverse order, from the bottom up. You can think of it like an
|
||||
onion: each middleware class is a "layer" that wraps the view:
|
||||
|
||||
.. image:: _images/middleware.png
|
||||
:width: 502
|
||||
:height: 417
|
||||
:alt: Middleware application order.
|
||||
|
||||
A Django installation doesn't require any middleware -- e.g.,
|
||||
:setting:`MIDDLEWARE_CLASSES` can be empty, if you'd like -- but it's strongly
|
||||
suggested that you at least use
|
||||
:class:`~django.middleware.common.CommonMiddleware`.
|
||||
|
||||
Writing your own middleware
|
||||
===========================
|
||||
|
||||
Writing your own middleware is easy. Each middleware component is a single
|
||||
Python class that defines one or more of the following methods:
|
||||
|
||||
.. _request-middleware:
|
||||
|
||||
``process_request``
|
||||
-------------------
|
||||
|
||||
.. method:: process_request(self, request)
|
||||
|
||||
``request`` is an :class:`~django.http.HttpRequest` object. This method is
|
||||
called on each request, before Django decides which view to execute.
|
||||
|
||||
``process_request()`` should return either ``None`` or an
|
||||
:class:`~django.http.HttpResponse` object. If it returns ``None``, Django will
|
||||
continue processing this request, executing any other middleware and, then, the
|
||||
appropriate view. If it returns an :class:`~django.http.HttpResponse` object,
|
||||
Django won't bother calling ANY other request, view or exception middleware, or
|
||||
the appropriate view; it'll return that :class:`~django.http.HttpResponse`.
|
||||
Response middleware is always called on every response.
|
||||
|
||||
.. _view-middleware:
|
||||
|
||||
``process_view``
|
||||
----------------
|
||||
|
||||
.. method:: process_view(self, request, view_func, view_args, view_kwargs)
|
||||
|
||||
``request`` is an :class:`~django.http.HttpRequest` object. ``view_func`` is the
|
||||
Python function that Django is about to use. (It's the actual function object,
|
||||
not the name of the function as a string.) ``view_args`` is a list of positional
|
||||
arguments that will be passed to the view, and ``view_kwargs`` is a dictionary
|
||||
of keyword arguments that will be passed to the view. Neither ``view_args`` nor
|
||||
``view_kwargs`` include the first view argument (``request``).
|
||||
|
||||
``process_view()`` is called just before Django calls the view. It should return
|
||||
either ``None`` or an :class:`~django.http. HttpResponse` object. If it returns
|
||||
``None``, Django will continue processing this request, executing any other
|
||||
``process_view()`` middleware and, then, the appropriate view. If it returns an
|
||||
:class:`~django.http. HttpResponse` object, Django won't bother calling ANY
|
||||
other request, view or exception middleware, or the appropriate view; it'll
|
||||
return that :class:`~django.http. HttpResponse`. Response middleware is always
|
||||
called on every response.
|
||||
|
||||
.. _response-middleware:
|
||||
|
||||
``process_response``
|
||||
--------------------
|
||||
|
||||
.. method:: process_response(self, request, response)
|
||||
|
||||
``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is the
|
||||
:class:`~django.http. HttpResponse` object returned by a Django view.
|
||||
|
||||
``process_response()`` should return an :class:`~django.http. HttpResponse`
|
||||
object. It could alter the given ``response``, or it could create and return a
|
||||
brand-new :class:`~django.http. HttpResponse`.
|
||||
|
||||
.. _exception-middleware:
|
||||
|
||||
``process_exception``
|
||||
---------------------
|
||||
|
||||
.. method:: process_exception(self, request, exception)
|
||||
|
||||
``request`` is an :class:`~django.http.HttpRequest` object. ``exception`` is an
|
||||
``Exception`` object raised by the view function.
|
||||
|
||||
Django calls ``process_exception()`` when a view raises an exception.
|
||||
``process_exception()`` should return either ``None`` or an
|
||||
:class:`~django.http. HttpResponse` object. If it returns an
|
||||
:class:`~django.http. HttpResponse` object, the response will be returned to the
|
||||
browser. Otherwise, default exception handling kicks in.
|
||||
|
||||
``__init__``
|
||||
------------
|
||||
|
||||
Most middleware classes won't need an initializer since middleware classes are
|
||||
essentially placeholders for the ``process_*`` methods. If you do need some
|
||||
global state you may use ``__init__`` to set up. However, keep in mind a couple
|
||||
of caveats:
|
||||
|
||||
* Django initializes your middleware without any arguments, so you can't
|
||||
define ``__init__`` as requiring any arguments.
|
||||
|
||||
* Unlike the ``process_*`` methods which get called once per request,
|
||||
``__init__`` gets called only *once*, when the web server starts up.
|
||||
|
||||
Marking middleware as unused
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
It's sometimes useful to determine at run-time whether a piece of middleware
|
||||
should be used. In these cases, your middleware's ``__init__`` method may raise
|
||||
``django.core.exceptions.MiddlewareNotUsed``. Django will then remove that piece
|
||||
of middleware from the middleware process.
|
||||
|
||||
Guidelines
|
||||
----------
|
||||
|
||||
* Middleware classes don't have to subclass anything.
|
||||
|
||||
* The middleware class can live anywhere on your Python path. All Django
|
||||
cares about is that the :setting:`MIDDLEWARE_CLASSES` setting includes the
|
||||
path
|
||||
to it.
|
||||
|
||||
* Feel free to look at :mod:`Django's available middleware for examples
|
||||
<django.middleware>`. The core Django middleware classes are in
|
||||
``django/middleware/`` in the Django distribution. The session middleware
|
||||
is in ``django/contrib/sessions``.
|
||||
|
||||
* If you write a middleware component that you think would be useful to
|
||||
other people, contribute to the community! :ref:`Let us know
|
||||
<internals-contributing>`, and we'll consider adding it to Django.
|
474
docs/topics/http/sessions.txt
Normal file
474
docs/topics/http/sessions.txt
Normal file
|
@ -0,0 +1,474 @@
|
|||
.. _topics-http-sessions:
|
||||
|
||||
===================
|
||||
How to use sessions
|
||||
===================
|
||||
|
||||
Django provides full support for anonymous sessions. The session framework lets
|
||||
you store and retrieve arbitrary data on a per-site-visitor basis. It stores
|
||||
data on the server side and abstracts the sending and receiving of cookies.
|
||||
Cookies contain a session ID -- not the data itself.
|
||||
|
||||
Enabling sessions
|
||||
=================
|
||||
|
||||
Sessions are implemented via a piece of :ref:`middleware <ref-middleware>`.
|
||||
|
||||
To enable session functionality, do the following:
|
||||
|
||||
* Edit the ``MIDDLEWARE_CLASSES`` setting and make sure
|
||||
``MIDDLEWARE_CLASSES`` contains ``'django.contrib.sessions.middleware.SessionMiddleware'``.
|
||||
The default ``settings.py`` created by ``django-admin.py startproject`` has
|
||||
``SessionMiddleware`` activated.
|
||||
|
||||
* Add ``'django.contrib.sessions'`` to your ``INSTALLED_APPS`` setting,
|
||||
and run ``manage.py syncdb`` to install the single database table
|
||||
that stores session data.
|
||||
|
||||
**New in development version**: this step is optional if you're not using
|
||||
the database session backend; see `configuring the session engine`_.
|
||||
|
||||
If you don't want to use sessions, you might as well remove the
|
||||
``SessionMiddleware`` line from ``MIDDLEWARE_CLASSES`` and ``'django.contrib.sessions'``
|
||||
from your ``INSTALLED_APPS``. It'll save you a small bit of overhead.
|
||||
|
||||
Configuring the session engine
|
||||
==============================
|
||||
|
||||
**New in development version**.
|
||||
|
||||
By default, Django stores sessions in your database (using the model
|
||||
``django.contrib.sessions.models.Session``). Though this is convenient, in
|
||||
some setups it's faster to store session data elsewhere, so Django can be
|
||||
configured to store session data on your filesystem or in your cache.
|
||||
|
||||
Using file-based sessions
|
||||
-------------------------
|
||||
|
||||
To use file-based sessions, set the ``SESSION_ENGINE`` setting to
|
||||
``"django.contrib.sessions.backends.file"``.
|
||||
|
||||
You might also want to set the ``SESSION_FILE_PATH`` setting (which defaults
|
||||
to output from ``tempfile.gettempdir()``, most likely ``/tmp``) to control
|
||||
where Django stores session files. Be sure to check that your Web server has
|
||||
permissions to read and write to this location.
|
||||
|
||||
Using cache-based sessions
|
||||
--------------------------
|
||||
|
||||
To store session data using Django's cache system, set ``SESSION_ENGINE``
|
||||
to ``"django.contrib.sessions.backends.cache"``. You'll want to make sure
|
||||
you've configured your cache; see the :ref:`cache documentation <topics-cache>` for details.
|
||||
|
||||
.. _cache documentation: ../cache/
|
||||
|
||||
.. note::
|
||||
|
||||
You should probably only use cache-based sessions if you're using the
|
||||
Memcached cache backend. The local-memory cache backend doesn't retain data
|
||||
long enough to be a good choice, and it'll be faster to use file or
|
||||
database sessions directly instead of sending everything through the file
|
||||
or database cache backends.
|
||||
|
||||
Using sessions in views
|
||||
=======================
|
||||
|
||||
When ``SessionMiddleware`` is activated, each ``HttpRequest`` object -- the
|
||||
first argument to any Django view function -- will have a ``session``
|
||||
attribute, which is a dictionary-like object. You can read it and write to it.
|
||||
|
||||
A session object has the following standard dictionary methods:
|
||||
|
||||
* ``__getitem__(key)``
|
||||
|
||||
Example: ``fav_color = request.session['fav_color']``
|
||||
|
||||
* ``__setitem__(key, value)``
|
||||
|
||||
Example: ``request.session['fav_color'] = 'blue'``
|
||||
|
||||
* ``__delitem__(key)``
|
||||
|
||||
Example: ``del request.session['fav_color']``. This raises ``KeyError``
|
||||
if the given ``key`` isn't already in the session.
|
||||
|
||||
* ``__contains__(key)``
|
||||
|
||||
Example: ``'fav_color' in request.session``
|
||||
|
||||
* ``get(key, default=None)``
|
||||
|
||||
Example: ``fav_color = request.session.get('fav_color', 'red')``
|
||||
|
||||
* ``keys()``
|
||||
|
||||
* ``items()``
|
||||
|
||||
* ``setdefault()`` (**New in Django development version**)
|
||||
|
||||
* ``clear()`` (**New in Django development version**)
|
||||
|
||||
It also has these methods:
|
||||
|
||||
* ``flush()``
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
Delete the current session data from the database and regenerate the
|
||||
session key value that is sent back to the user in the cookie. This is
|
||||
used if you want to ensure that the previous session data can't be
|
||||
accessed again from the user's browser (for example, the
|
||||
``django.contrib.auth.logout()`` method calls it).
|
||||
|
||||
* ``set_test_cookie()``
|
||||
|
||||
Sets a test cookie to determine whether the user's browser supports
|
||||
cookies. Due to the way cookies work, you won't be able to test this
|
||||
until the user's next page request. See `Setting test cookies`_ below for
|
||||
more information.
|
||||
|
||||
* ``test_cookie_worked()``
|
||||
|
||||
Returns either ``True`` or ``False``, depending on whether the user's
|
||||
browser accepted the test cookie. Due to the way cookies work, you'll
|
||||
have to call ``set_test_cookie()`` on a previous, separate page request.
|
||||
See `Setting test cookies`_ below for more information.
|
||||
|
||||
* ``delete_test_cookie()``
|
||||
|
||||
Deletes the test cookie. Use this to clean up after yourself.
|
||||
|
||||
* ``set_expiry(value)``
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
Sets the expiration time for the session. You can pass a number of
|
||||
different values:
|
||||
|
||||
* If ``value`` is an integer, the session will expire after that
|
||||
many seconds of inactivity. For example, calling
|
||||
``request.session.set_expiry(300)`` would make the session expire
|
||||
in 5 minutes.
|
||||
|
||||
* If ``value`` is a ``datetime`` or ``timedelta`` object, the
|
||||
session will expire at that specific date/time.
|
||||
|
||||
* If ``value`` is ``0``, the user's session cookie will expire
|
||||
when the user's Web browser is closed.
|
||||
|
||||
* If ``value`` is ``None``, the session reverts to using the global
|
||||
session expiry policy.
|
||||
|
||||
* ``get_expiry_age()``
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
Returns the number of seconds until this session expires. For sessions
|
||||
with no custom expiration (or those set to expire at browser close), this
|
||||
will equal ``settings.SESSION_COOKIE_AGE``.
|
||||
|
||||
* ``get_expiry_date()``
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
Returns the date this session will expire. For sessions with no custom
|
||||
expiration (or those set to expire at browser close), this will equal the
|
||||
date ``settings.SESSION_COOKIE_AGE`` seconds from now.
|
||||
|
||||
* ``get_expire_at_browser_close()``
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
Returns either ``True`` or ``False``, depending on whether the user's
|
||||
session cookie will expire when the user's Web browser is closed.
|
||||
|
||||
You can edit ``request.session`` at any point in your view. You can edit it
|
||||
multiple times.
|
||||
|
||||
Session object guidelines
|
||||
-------------------------
|
||||
|
||||
* Use normal Python strings as dictionary keys on ``request.session``. This
|
||||
is more of a convention than a hard-and-fast rule.
|
||||
|
||||
* Session dictionary keys that begin with an underscore are reserved for
|
||||
internal use by Django.
|
||||
|
||||
* Don't override ``request.session`` with a new object, and don't access or
|
||||
set its attributes. Use it like a Python dictionary.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
This simplistic view sets a ``has_commented`` variable to ``True`` after a user
|
||||
posts a comment. It doesn't let a user post a comment more than once::
|
||||
|
||||
def post_comment(request, new_comment):
|
||||
if request.session.get('has_commented', False):
|
||||
return HttpResponse("You've already commented.")
|
||||
c = comments.Comment(comment=new_comment)
|
||||
c.save()
|
||||
request.session['has_commented'] = True
|
||||
return HttpResponse('Thanks for your comment!')
|
||||
|
||||
This simplistic view logs in a "member" of the site::
|
||||
|
||||
def login(request):
|
||||
m = Member.objects.get(username=request.POST['username'])
|
||||
if m.password == request.POST['password']:
|
||||
request.session['member_id'] = m.id
|
||||
return HttpResponse("You're logged in.")
|
||||
else:
|
||||
return HttpResponse("Your username and password didn't match.")
|
||||
|
||||
...And this one logs a member out, according to ``login()`` above::
|
||||
|
||||
def logout(request):
|
||||
try:
|
||||
del request.session['member_id']
|
||||
except KeyError:
|
||||
pass
|
||||
return HttpResponse("You're logged out.")
|
||||
|
||||
The standard ``django.contrib.auth.logout()`` function actually does a bit
|
||||
more than this to prevent inadvertent data leakage. It calls
|
||||
``request.session.flush()``. We are using this example as a demonstration of
|
||||
how to work with session objects, not as a full ``logout()`` implementation.
|
||||
|
||||
Setting test cookies
|
||||
====================
|
||||
|
||||
As a convenience, Django provides an easy way to test whether the user's
|
||||
browser accepts cookies. Just call ``request.session.set_test_cookie()`` in a
|
||||
view, and call ``request.session.test_cookie_worked()`` in a subsequent view --
|
||||
not in the same view call.
|
||||
|
||||
This awkward split between ``set_test_cookie()`` and ``test_cookie_worked()``
|
||||
is necessary due to the way cookies work. When you set a cookie, you can't
|
||||
actually tell whether a browser accepted it until the browser's next request.
|
||||
|
||||
It's good practice to use ``delete_test_cookie()`` to clean up after yourself.
|
||||
Do this after you've verified that the test cookie worked.
|
||||
|
||||
Here's a typical usage example::
|
||||
|
||||
def login(request):
|
||||
if request.method == 'POST':
|
||||
if request.session.test_cookie_worked():
|
||||
request.session.delete_test_cookie()
|
||||
return HttpResponse("You're logged in.")
|
||||
else:
|
||||
return HttpResponse("Please enable cookies and try again.")
|
||||
request.session.set_test_cookie()
|
||||
return render_to_response('foo/login_form.html')
|
||||
|
||||
Using sessions out of views
|
||||
===========================
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
An API is available to manipulate session data outside of a view::
|
||||
|
||||
>>> from django.contrib.sessions.backends.db import SessionStore
|
||||
>>> s = SessionStore(session_key='2b1189a188b44ad18c35e113ac6ceead')
|
||||
>>> s['last_login'] = datetime.datetime(2005, 8, 20, 13, 35, 10)
|
||||
>>> s['last_login']
|
||||
datetime.datetime(2005, 8, 20, 13, 35, 0)
|
||||
>>> s.save()
|
||||
|
||||
If you're using the ``django.contrib.sessions.backends.db`` backend, each
|
||||
session is just a normal Django model. The ``Session`` model is defined in
|
||||
``django/contrib/sessions/models.py``. Because it's a normal model, you can
|
||||
access sessions using the normal Django database API::
|
||||
|
||||
>>> from django.contrib.sessions.models import Session
|
||||
>>> s = Session.objects.get(pk='2b1189a188b44ad18c35e113ac6ceead')
|
||||
>>> s.expire_date
|
||||
datetime.datetime(2005, 8, 20, 13, 35, 12)
|
||||
|
||||
Note that you'll need to call ``get_decoded()`` to get the session dictionary.
|
||||
This is necessary because the dictionary is stored in an encoded format::
|
||||
|
||||
>>> s.session_data
|
||||
'KGRwMQpTJ19hdXRoX3VzZXJfaWQnCnAyCkkxCnMuMTExY2ZjODI2Yj...'
|
||||
>>> s.get_decoded()
|
||||
{'user_id': 42}
|
||||
|
||||
When sessions are saved
|
||||
=======================
|
||||
|
||||
By default, Django only saves to the session database when the session has been
|
||||
modified -- that is if any of its dictionary values have been assigned or
|
||||
deleted::
|
||||
|
||||
# Session is modified.
|
||||
request.session['foo'] = 'bar'
|
||||
|
||||
# Session is modified.
|
||||
del request.session['foo']
|
||||
|
||||
# Session is modified.
|
||||
request.session['foo'] = {}
|
||||
|
||||
# Gotcha: Session is NOT modified, because this alters
|
||||
# request.session['foo'] instead of request.session.
|
||||
request.session['foo']['bar'] = 'baz'
|
||||
|
||||
In the last case of the above example, we can tell the session object
|
||||
explicitly that it has been modified by setting the ``modified`` attribute on
|
||||
the session object::
|
||||
|
||||
request.session.modified = True
|
||||
|
||||
To change this default behavior, set the ``SESSION_SAVE_EVERY_REQUEST`` setting
|
||||
to ``True``. If ``SESSION_SAVE_EVERY_REQUEST`` is ``True``, Django will save
|
||||
the session to the database on every single request.
|
||||
|
||||
Note that the session cookie is only sent when a session has been created or
|
||||
modified. If ``SESSION_SAVE_EVERY_REQUEST`` is ``True``, the session cookie
|
||||
will be sent on every request.
|
||||
|
||||
Similarly, the ``expires`` part of a session cookie is updated each time the
|
||||
session cookie is sent.
|
||||
|
||||
Browser-length sessions vs. persistent sessions
|
||||
===============================================
|
||||
|
||||
You can control whether the session framework uses browser-length sessions vs.
|
||||
persistent sessions with the ``SESSION_EXPIRE_AT_BROWSER_CLOSE`` setting.
|
||||
|
||||
By default, ``SESSION_EXPIRE_AT_BROWSER_CLOSE`` is set to ``False``, which
|
||||
means session cookies will be stored in users' browsers for as long as
|
||||
``SESSION_COOKIE_AGE``. Use this if you don't want people to have to log in
|
||||
every time they open a browser.
|
||||
|
||||
If ``SESSION_EXPIRE_AT_BROWSER_CLOSE`` is set to ``True``, Django will use
|
||||
browser-length cookies -- cookies that expire as soon as the user closes his or
|
||||
her browser. Use this if you want people to have to log in every time they open
|
||||
a browser.
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
This setting is a global default and can be overwritten at a per-session level
|
||||
by explicitly calling ``request.session.set_expiry()`` as described above in
|
||||
`using sessions in views`_.
|
||||
|
||||
Clearing the session table
|
||||
==========================
|
||||
|
||||
Note that session data can accumulate in the ``django_session`` database table
|
||||
and Django does *not* provide automatic purging. Therefore, it's your job to
|
||||
purge expired sessions on a regular basis.
|
||||
|
||||
To understand this problem, consider what happens when a user uses a session.
|
||||
When a user logs in, Django adds a row to the ``django_session`` database
|
||||
table. Django updates this row each time the session data changes. If the user
|
||||
logs out manually, Django deletes the row. But if the user does *not* log out,
|
||||
the row never gets deleted.
|
||||
|
||||
Django provides a sample clean-up script in ``django-admin.py cleanup``.
|
||||
That script deletes any session in the session table whose ``expire_date`` is
|
||||
in the past -- but your application may have different requirements.
|
||||
|
||||
Settings
|
||||
========
|
||||
|
||||
A few :ref:`Django settings <ref-settings>` give you control over session behavior:
|
||||
|
||||
SESSION_ENGINE
|
||||
--------------
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
Default: ``django.contrib.sessions.backends.db``
|
||||
|
||||
Controls where Django stores session data. Valid values are:
|
||||
|
||||
* ``'django.contrib.sessions.backends.db'``
|
||||
* ``'django.contrib.sessions.backends.file'``
|
||||
* ``'django.contrib.sessions.backends.cache'``
|
||||
|
||||
See `configuring the session engine`_ for more details.
|
||||
|
||||
SESSION_FILE_PATH
|
||||
-----------------
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
Default: ``/tmp/``
|
||||
|
||||
If you're using file-based session storage, this sets the directory in
|
||||
which Django will store session data.
|
||||
|
||||
SESSION_COOKIE_AGE
|
||||
------------------
|
||||
|
||||
Default: ``1209600`` (2 weeks, in seconds)
|
||||
|
||||
The age of session cookies, in seconds.
|
||||
|
||||
SESSION_COOKIE_DOMAIN
|
||||
---------------------
|
||||
|
||||
Default: ``None``
|
||||
|
||||
The domain to use for session cookies. Set this to a string such as
|
||||
``".lawrence.com"`` for cross-domain cookies, or use ``None`` for a standard
|
||||
domain cookie.
|
||||
|
||||
SESSION_COOKIE_NAME
|
||||
-------------------
|
||||
|
||||
Default: ``'sessionid'``
|
||||
|
||||
The name of the cookie to use for sessions. This can be whatever you want.
|
||||
|
||||
SESSION_COOKIE_SECURE
|
||||
---------------------
|
||||
|
||||
Default: ``False``
|
||||
|
||||
Whether to use a secure cookie for the session cookie. If this is set to
|
||||
``True``, the cookie will be marked as "secure," which means browsers may
|
||||
ensure that the cookie is only sent under an HTTPS connection.
|
||||
|
||||
SESSION_EXPIRE_AT_BROWSER_CLOSE
|
||||
-------------------------------
|
||||
|
||||
Default: ``False``
|
||||
|
||||
Whether to expire the session when the user closes his or her browser. See
|
||||
"Browser-length sessions vs. persistent sessions" above.
|
||||
|
||||
SESSION_SAVE_EVERY_REQUEST
|
||||
--------------------------
|
||||
|
||||
Default: ``False``
|
||||
|
||||
Whether to save the session data on every request. If this is ``False``
|
||||
(default), then the session data will only be saved if it has been modified --
|
||||
that is, if any of its dictionary values have been assigned or deleted.
|
||||
|
||||
.. _Django settings: ../settings/
|
||||
|
||||
Technical details
|
||||
=================
|
||||
|
||||
* The session dictionary should accept any pickleable Python object. See
|
||||
`the pickle module`_ for more information.
|
||||
|
||||
* Session data is stored in a database table named ``django_session`` .
|
||||
|
||||
* Django only sends a cookie if it needs to. If you don't set any session
|
||||
data, it won't send a session cookie.
|
||||
|
||||
.. _`the pickle module`: http://www.python.org/doc/current/lib/module-pickle.html
|
||||
|
||||
Session IDs in URLs
|
||||
===================
|
||||
|
||||
The Django sessions framework is entirely, and solely, cookie-based. It does
|
||||
not fall back to putting session IDs in URLs as a last resort, as PHP does.
|
||||
This is an intentional design decision. Not only does that behavior make URLs
|
||||
ugly, it makes your site vulnerable to session-ID theft via the "Referer"
|
||||
header.
|
151
docs/topics/http/shortcuts.txt
Normal file
151
docs/topics/http/shortcuts.txt
Normal file
|
@ -0,0 +1,151 @@
|
|||
.. _topics-http-shortcuts:
|
||||
|
||||
=========================
|
||||
Django shortcut functions
|
||||
=========================
|
||||
|
||||
The package ``django.shortcuts`` collects helper functions and classes that
|
||||
"span" multiple levels of MVC. In other words, these functions/classes
|
||||
introduce controlled coupling for convenience's sake.
|
||||
|
||||
``render_to_response()``
|
||||
========================
|
||||
|
||||
``django.shortcuts.render_to_response`` renders a given template with a given
|
||||
context dictionary and returns an ``HttpResponse`` object with that rendered
|
||||
text.
|
||||
|
||||
Required arguments
|
||||
------------------
|
||||
|
||||
``template``
|
||||
The full name of a template to use.
|
||||
|
||||
Optional arguments
|
||||
------------------
|
||||
|
||||
``dictionary``
|
||||
A dictionary of values to add to the template context. By default, this
|
||||
is an empty dictionary. If a value in the dictionary is callable, the
|
||||
view will call it just before rendering the template.
|
||||
|
||||
``context_instance``
|
||||
The context instance to render the template with. By default, the template
|
||||
will be rendered with a ``Context`` instance (filled with values from
|
||||
``dictionary``). If you need to use :ref:`context processors
|
||||
<subclassing-context-requestcontext>`, render the template with a
|
||||
``RequestContext`` instance instead. Your code might look something like
|
||||
this::
|
||||
|
||||
return render_to_response('my_template.html',
|
||||
my_data_dictionary,
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
``mimetype``
|
||||
**New in Django development version:** The MIME type to use for the
|
||||
resulting document. Defaults to the value of the ``DEFAULT_CONTENT_TYPE``
|
||||
setting.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
The following example renders the template ``myapp/index.html`` with the
|
||||
MIME type ``application/xhtml+xml``::
|
||||
|
||||
from django.shortcuts import render_to_response
|
||||
|
||||
def my_view(request):
|
||||
# View code here...
|
||||
return render_to_response('myapp/index.html', {"foo": "bar"},
|
||||
mimetype="application/xhtml+xml")
|
||||
|
||||
This example is equivalent to::
|
||||
|
||||
from django.http import HttpResponse
|
||||
from django.template import Context, loader
|
||||
|
||||
def my_view(request):
|
||||
# View code here...
|
||||
t = loader.get_template('myapp/template.html')
|
||||
c = Context({'foo': 'bar'})
|
||||
r = HttpResponse(t.render(c),
|
||||
mimetype="application/xhtml+xml")
|
||||
|
||||
``get_object_or_404``
|
||||
=====================
|
||||
|
||||
``django.shortcuts.get_object_or_404`` calls
|
||||
:meth:`~django.db.models.QuerySet.get()` on a given model manager, but it raises
|
||||
``django.http.Http404`` instead of the model's ``DoesNotExist`` exception.
|
||||
|
||||
Required arguments
|
||||
------------------
|
||||
|
||||
``klass``
|
||||
A ``Model``, ``Manager`` or ``QuerySet`` instance from which to get the
|
||||
object.
|
||||
|
||||
``**kwargs``
|
||||
Lookup parameters, which should be in the format accepted by ``get()`` and
|
||||
``filter()``.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
The following example gets the object with the primary key of 1 from
|
||||
``MyModel``::
|
||||
|
||||
from django.shortcuts import get_object_or_404
|
||||
|
||||
def my_view(request):
|
||||
my_object = get_object_or_404(MyModel, pk=1)
|
||||
|
||||
This example is equivalent to::
|
||||
|
||||
from django.http import Http404
|
||||
|
||||
def my_view(request):
|
||||
try:
|
||||
my_object = MyModel.objects.get(pk=1)
|
||||
except MyModel.DoesNotExist:
|
||||
raise Http404
|
||||
|
||||
Note: As with ``get()``, an ``MultipleObjectsReturned`` exception will be
|
||||
raised if more than one object is found.
|
||||
|
||||
``get_list_or_404``
|
||||
===================
|
||||
|
||||
``django.shortcuts.get_list_or_404`` returns the result of
|
||||
:meth:`~django.db.models.QuerySet.filter()` on a given model manager, raising
|
||||
``django.http.Http404`` if the resulting list is empty.
|
||||
|
||||
Required arguments
|
||||
------------------
|
||||
|
||||
``klass``
|
||||
A ``Model``, ``Manager`` or ``QuerySet`` instance from which to get the
|
||||
object.
|
||||
|
||||
``**kwargs``
|
||||
Lookup parameters, which should be in the format accepted by ``get()`` and
|
||||
``filter()``.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
The following example gets all published objects from ``MyModel``::
|
||||
|
||||
from django.shortcuts import get_list_or_404
|
||||
|
||||
def my_view(request):
|
||||
my_objects = get_list_or_404(MyModel, published=True)
|
||||
|
||||
This example is equivalent to::
|
||||
|
||||
from django.http import Http404
|
||||
|
||||
def my_view(request):
|
||||
my_objects = MyModel.objects.filter(published=True)
|
||||
if not my_objects:
|
||||
raise Http404
|
620
docs/topics/http/urls.txt
Normal file
620
docs/topics/http/urls.txt
Normal file
|
@ -0,0 +1,620 @@
|
|||
.. _topics-http-urls:
|
||||
|
||||
==============
|
||||
URL dispatcher
|
||||
==============
|
||||
|
||||
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.
|
||||
|
||||
There's no ``.php`` or ``.cgi`` required, and certainly none of that
|
||||
``0,2097,1-1-1928,00`` nonsense.
|
||||
|
||||
See `Cool URIs don't change`_, by World Wide Web creator Tim Berners-Lee, for
|
||||
excellent arguments on why URLs should be clean and usable.
|
||||
|
||||
.. _Cool URIs don't change: http://www.w3.org/Provider/Style/URI
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
To design URLs for an app, you create a Python module informally called a
|
||||
**URLconf** (URL configuration). This module is pure Python code and
|
||||
is a simple mapping between URL patterns (as simple regular expressions) to
|
||||
Python callback functions (your views).
|
||||
|
||||
This mapping can be as short or as long as needed. It can reference other
|
||||
mappings. And, because it's pure Python code, it can be constructed
|
||||
dynamically.
|
||||
|
||||
.. _how-django-processes-a-request:
|
||||
|
||||
How Django processes a request
|
||||
==============================
|
||||
|
||||
When a user requests a page from your Django-powered site, this is the
|
||||
algorithm the system follows to determine which Python code to execute:
|
||||
|
||||
1. Django determines the root URLconf module to use. Ordinarily,
|
||||
this is the value of the ``ROOT_URLCONF`` setting, but if the incoming
|
||||
``HttpRequest`` object has an attribute called ``urlconf``, its value
|
||||
will be used in place of the ``ROOT_URLCONF`` setting.
|
||||
|
||||
2. Django loads that Python module and looks for the variable
|
||||
``urlpatterns``. This should be a Python list, in the format returned by
|
||||
the function ``django.conf.urls.defaults.patterns()``.
|
||||
|
||||
3. Django runs through each URL pattern, in order, and stops at the first
|
||||
one that matches the requested URL.
|
||||
|
||||
4. Once one of the regexes matches, Django imports and calls the given
|
||||
view, which is a simple Python function. The view gets passed an
|
||||
:class:`~django.http.HttpRequest`` as its first argument and any values
|
||||
captured in the regex as remaining arguments.
|
||||
|
||||
Example
|
||||
=======
|
||||
|
||||
Here's a sample URLconf::
|
||||
|
||||
from django.conf.urls.defaults import *
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^articles/2003/$', 'news.views.special_case_2003'),
|
||||
(r'^articles/(\d{4})/$', 'news.views.year_archive'),
|
||||
(r'^articles/(\d{4})/(\d{2})/$', 'news.views.month_archive'),
|
||||
(r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'news.views.article_detail'),
|
||||
)
|
||||
|
||||
Notes:
|
||||
|
||||
* ``from django.conf.urls.defaults import *`` makes the ``patterns()``
|
||||
function available.
|
||||
|
||||
* To capture a value from the URL, just put parenthesis around it.
|
||||
|
||||
* There's no need to add a leading slash, because every URL has that. For
|
||||
example, it's ``^articles``, not ``^/articles``.
|
||||
|
||||
* The ``'r'`` in front of each regular expression string is optional but
|
||||
recommended. It tells Python that a string is "raw" -- that nothing in
|
||||
the string should be escaped. See `Dive Into Python's explanation`_.
|
||||
|
||||
Example requests:
|
||||
|
||||
* A request to ``/articles/2005/03/`` would match the third entry in the
|
||||
list. Django would call the function
|
||||
``news.views.month_archive(request, '2005', '03')``.
|
||||
|
||||
* ``/articles/2005/3/`` would not match any URL patterns, because the
|
||||
third entry in the list requires two digits for the month.
|
||||
|
||||
* ``/articles/2003/`` would match the first pattern in the list, not the
|
||||
second one, because the patterns are tested in order, and the first one
|
||||
is the first test to pass. Feel free to exploit the ordering to insert
|
||||
special cases like this.
|
||||
|
||||
* ``/articles/2003`` would not match any of these patterns, because each
|
||||
pattern requires that the URL end with a slash.
|
||||
|
||||
* ``/articles/2003/03/3/`` would match the final pattern. Django would call
|
||||
the function ``news.views.article_detail(request, '2003', '03', '3')``.
|
||||
|
||||
.. _Dive Into Python's explanation: http://diveintopython.org/regular_expressions/street_addresses.html#re.matching.2.3
|
||||
|
||||
Named groups
|
||||
============
|
||||
|
||||
The above example used simple, *non-named* regular-expression groups (via
|
||||
parenthesis) to capture bits of the URL and pass them as *positional* arguments
|
||||
to a view. In more advanced usage, it's possible to use *named*
|
||||
regular-expression groups to capture URL bits and pass them as *keyword*
|
||||
arguments to a view.
|
||||
|
||||
In Python regular expressions, the syntax for named regular-expression groups
|
||||
is ``(?P<name>pattern)``, where ``name`` is the name of the group and
|
||||
``pattern`` is some pattern to match.
|
||||
|
||||
Here's the above example URLconf, rewritten to use named groups::
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^articles/2003/$', 'news.views.special_case_2003'),
|
||||
(r'^articles/(?P<year>\d{4})/$', 'news.views.year_archive'),
|
||||
(r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', 'news.views.month_archive'),
|
||||
(r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d+)/$', 'news.views.article_detail'),
|
||||
)
|
||||
|
||||
This accomplishes exactly the same thing as the previous example, with one
|
||||
subtle difference: The captured values are passed to view functions as keyword
|
||||
arguments rather than positional arguments. For example:
|
||||
|
||||
* A request to ``/articles/2005/03/`` would call the function
|
||||
``news.views.month_archive(request, year='2005', month='03')``, instead
|
||||
of ``news.views.month_archive(request, '2005', '03')``.
|
||||
|
||||
* A request to ``/articles/2003/03/3/`` would call the function
|
||||
``news.views.article_detail(request, year='2003', month='03', day='3')``.
|
||||
|
||||
In practice, this means your URLconfs are slightly more explicit and less prone
|
||||
to argument-order bugs -- and you can reorder the arguments in your views'
|
||||
function definitions. Of course, these benefits come at the cost of brevity;
|
||||
some developers find the named-group syntax ugly and too verbose.
|
||||
|
||||
The matching/grouping algorithm
|
||||
-------------------------------
|
||||
|
||||
Here's the algorithm the URLconf parser follows, with respect to named groups
|
||||
vs. non-named groups in a regular expression:
|
||||
|
||||
If there are any named arguments, it will use those, ignoring non-named arguments.
|
||||
Otherwise, it will pass all non-named arguments as positional arguments.
|
||||
|
||||
In both cases, it will pass any extra keyword arguments as keyword arguments.
|
||||
See "Passing extra options to view functions" below.
|
||||
|
||||
What the URLconf searches against
|
||||
=================================
|
||||
|
||||
The URLconf searches against the requested URL, as a normal Python string. This
|
||||
does not include GET or 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 URLconf doesn't look at the request method. In other words, all request
|
||||
methods -- ``POST``, ``GET``, ``HEAD``, etc. -- will be routed to the same
|
||||
function for the same URL.
|
||||
|
||||
Syntax of the urlpatterns variable
|
||||
==================================
|
||||
|
||||
``urlpatterns`` should be a Python list, in the format returned by the function
|
||||
``django.conf.urls.defaults.patterns()``. Always use ``patterns()`` to create
|
||||
the ``urlpatterns`` variable.
|
||||
|
||||
Convention is to use ``from django.conf.urls.defaults import *`` at the top of
|
||||
your URLconf. This gives your module access to these objects:
|
||||
|
||||
patterns
|
||||
--------
|
||||
|
||||
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]])
|
||||
|
||||
...where ``optional dictionary`` and ``optional name`` are optional. (See
|
||||
`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
|
||||
---
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
You can use the ``url()`` function, instead of a tuple, as an argument to
|
||||
``patterns()``. This is convenient if you want to specify a name without the
|
||||
optional extra arguments dictionary. For example::
|
||||
|
||||
urlpatterns = patterns('',
|
||||
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.
|
||||
|
||||
handler404
|
||||
----------
|
||||
|
||||
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.
|
||||
|
||||
handler500
|
||||
----------
|
||||
|
||||
A string representing the full Python import path to the view that should be
|
||||
called in case of server errors. Server errors happen when you have runtime
|
||||
errors in view code.
|
||||
|
||||
By default, this is ``'django.views.defaults.server_error'``. That default
|
||||
value should suffice.
|
||||
|
||||
include
|
||||
-------
|
||||
|
||||
A function that takes a full Python import path to another URLconf that should
|
||||
be "included" in this place. See `Including other URLconfs`_ below.
|
||||
|
||||
Notes on capturing text in URLs
|
||||
===============================
|
||||
|
||||
Each captured argument is sent to the view as a plain Python string, regardless
|
||||
of what sort of match the regular expression makes. For example, in this
|
||||
URLconf line::
|
||||
|
||||
(r'^articles/(?P<year>\d{4})/$', 'news.views.year_archive'),
|
||||
|
||||
...the ``year`` argument to ``news.views.year_archive()`` will be a string, not
|
||||
an integer, even though the ``\d{4}`` will only match integer strings.
|
||||
|
||||
A convenient trick is to specify default parameters for your views' arguments.
|
||||
Here's an example URLconf and view::
|
||||
|
||||
# URLconf
|
||||
urlpatterns = patterns('',
|
||||
(r'^blog/$', 'blog.views.page'),
|
||||
(r'^blog/page(?P<num>\d+)/$', 'blog.views.page'),
|
||||
)
|
||||
|
||||
# View (in blog/views.py)
|
||||
def page(request, num="1"):
|
||||
# Output the appropriate page of blog entries, according to num.
|
||||
|
||||
In the above example, both URL patterns point to the same view --
|
||||
``blog.views.page`` -- but the first pattern doesn't capture anything from the
|
||||
URL. If the first pattern matches, the ``page()`` function will use its
|
||||
default argument for ``num``, ``"1"``. If the second pattern matches,
|
||||
``page()`` will use whatever ``num`` value was captured by the regex.
|
||||
|
||||
Performance
|
||||
===========
|
||||
|
||||
Each regular expression in a ``urlpatterns`` is compiled the first time it's
|
||||
accessed. This makes the system blazingly fast.
|
||||
|
||||
The view prefix
|
||||
===============
|
||||
|
||||
You can specify a common prefix in your ``patterns()`` call, to cut down on
|
||||
code duplication.
|
||||
|
||||
Here's the example URLconf from the :ref:`Django overview <intro-overview>`::
|
||||
|
||||
from django.conf.urls.defaults import *
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^articles/(\d{4})/$', 'mysite.news.views.year_archive'),
|
||||
(r'^articles/(\d{4})/(\d{2})/$', 'mysite.news.views.month_archive'),
|
||||
(r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'mysite.news.views.article_detail'),
|
||||
)
|
||||
|
||||
In this example, each view has a common prefix -- ``'mysite.news.views'``.
|
||||
Instead of typing that out for each entry in ``urlpatterns``, you can use the
|
||||
first argument to the ``patterns()`` function to specify a prefix to apply to
|
||||
each view function.
|
||||
|
||||
With this in mind, the above example can be written more concisely as::
|
||||
|
||||
from django.conf.urls.defaults import *
|
||||
|
||||
urlpatterns = patterns('mysite.news.views',
|
||||
(r'^articles/(\d{4})/$', 'year_archive'),
|
||||
(r'^articles/(\d{4})/(\d{2})/$', 'month_archive'),
|
||||
(r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'article_detail'),
|
||||
)
|
||||
|
||||
Note that you don't put a trailing dot (``"."``) in the prefix. Django puts
|
||||
that in automatically.
|
||||
|
||||
Multiple view prefixes
|
||||
----------------------
|
||||
|
||||
In practice, you'll probably end up mixing and matching views to the point
|
||||
where the views in your ``urlpatterns`` won't have a common prefix. However,
|
||||
you can still take advantage of the view prefix shortcut to remove duplication.
|
||||
Just add multiple ``patterns()`` objects together, like this:
|
||||
|
||||
Old::
|
||||
|
||||
from django.conf.urls.defaults import *
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^$', 'django.views.generic.date_based.archive_index'),
|
||||
(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$', 'django.views.generic.date_based.archive_month'),
|
||||
(r'^tag/(?P<tag>\w+)/$', 'weblog.views.tag'),
|
||||
)
|
||||
|
||||
New::
|
||||
|
||||
from django.conf.urls.defaults import *
|
||||
|
||||
urlpatterns = patterns('django.views.generic.date_based',
|
||||
(r'^$', 'archive_index'),
|
||||
(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$','archive_month'),
|
||||
)
|
||||
|
||||
urlpatterns += patterns('weblog.views',
|
||||
(r'^tag/(?P<tag>\w+)/$', 'tag'),
|
||||
)
|
||||
|
||||
Including other URLconfs
|
||||
========================
|
||||
|
||||
At any point, your ``urlpatterns`` can "include" other URLconf modules. This
|
||||
essentially "roots" a set of URLs below other ones.
|
||||
|
||||
For example, here's the URLconf for the `Django Web site`_ itself. It includes a
|
||||
number of other URLconfs::
|
||||
|
||||
from django.conf.urls.defaults import *
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^weblog/', include('django_website.apps.blog.urls.blog')),
|
||||
(r'^documentation/', include('django_website.apps.docs.urls.docs')),
|
||||
(r'^comments/', include('django.contrib.comments.urls.comments')),
|
||||
)
|
||||
|
||||
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 Web site`: http://www.djangoproject.com/
|
||||
|
||||
Captured parameters
|
||||
-------------------
|
||||
|
||||
An included URLconf receives any captured parameters from parent URLconfs, so
|
||||
the following example is valid::
|
||||
|
||||
# In settings/urls/main.py
|
||||
urlpatterns = patterns('',
|
||||
(r'^(?P<username>\w+)/blog/', include('foo.urls.blog')),
|
||||
)
|
||||
|
||||
# In foo/urls/blog.py
|
||||
urlpatterns = patterns('foo.views',
|
||||
(r'^$', 'blog.index'),
|
||||
(r'^archive/$', 'blog.archive'),
|
||||
)
|
||||
|
||||
In the above example, the captured ``"username"`` variable is passed to the
|
||||
included URLconf, as expected.
|
||||
|
||||
Passing extra options to view functions
|
||||
=======================================
|
||||
|
||||
URLconfs have a hook that lets you pass extra arguments to your view functions,
|
||||
as a Python dictionary.
|
||||
|
||||
Any URLconf tuple can have an optional third element, which should be a
|
||||
dictionary of extra keyword arguments to pass to the view function.
|
||||
|
||||
For example::
|
||||
|
||||
urlpatterns = patterns('blog.views',
|
||||
(r'^blog/(?P<year>\d{4})/$', 'year_archive', {'foo': 'bar'}),
|
||||
)
|
||||
|
||||
In this example, for a request to ``/blog/2005/``, Django will call the
|
||||
``blog.views.year_archive()`` view, passing it these keyword arguments::
|
||||
|
||||
year='2005', foo='bar'
|
||||
|
||||
This technique is used in :ref:`generic views <ref-generic-views>` and in the
|
||||
:ref:`syndication framework <ref-contrib-syndication>` to pass metadata and
|
||||
options to views.
|
||||
|
||||
.. admonition:: Dealing with conflicts
|
||||
|
||||
It's possible to have a URL pattern which captures named keyword arguments,
|
||||
and also passes arguments with the same names in its dictionary of extra
|
||||
arguments. When this happens, the arguments in the dictionary will be used
|
||||
instead of the arguments captured in the URL.
|
||||
|
||||
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.
|
||||
|
||||
For example, these two URLconf sets are functionally identical:
|
||||
|
||||
Set one::
|
||||
|
||||
# main.py
|
||||
urlpatterns = patterns('',
|
||||
(r'^blog/', include('inner'), {'blogid': 3}),
|
||||
)
|
||||
|
||||
# inner.py
|
||||
urlpatterns = patterns('',
|
||||
(r'^archive/$', 'mysite.views.archive'),
|
||||
(r'^about/$', 'mysite.views.about'),
|
||||
)
|
||||
|
||||
Set two::
|
||||
|
||||
# main.py
|
||||
urlpatterns = patterns('',
|
||||
(r'^blog/', include('inner')),
|
||||
)
|
||||
|
||||
# inner.py
|
||||
urlpatterns = patterns('',
|
||||
(r'^archive/$', 'mysite.views.archive', {'blogid': 3}),
|
||||
(r'^about/$', 'mysite.views.about', {'blogid': 3}),
|
||||
)
|
||||
|
||||
Note that extra options will *always* be passed to *every* line in the included
|
||||
URLconf, regardless of whether the line's view actually accepts those options
|
||||
as valid. For this reason, this technique is only useful if you're certain that
|
||||
every view in the included URLconf accepts the extra options you're passing.
|
||||
|
||||
Passing callable objects instead of strings
|
||||
===========================================
|
||||
|
||||
Some developers find it more natural to pass the actual Python function object
|
||||
rather than a string containing the path to its module. This alternative is
|
||||
supported -- you can pass any callable object as the view.
|
||||
|
||||
For example, given this URLconf in "string" notation::
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^archive/$', 'mysite.views.archive'),
|
||||
(r'^about/$', 'mysite.views.about'),
|
||||
(r'^contact/$', 'mysite.views.contact'),
|
||||
)
|
||||
|
||||
You can accomplish the same thing by passing objects rather than strings. Just
|
||||
be sure to import the objects::
|
||||
|
||||
from mysite.views import archive, about, contact
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^archive/$', archive),
|
||||
(r'^about/$', about),
|
||||
(r'^contact/$', contact),
|
||||
)
|
||||
|
||||
The following example is functionally identical. It's just a bit more compact
|
||||
because it imports the module that contains the views, rather than importing
|
||||
each view individually::
|
||||
|
||||
from mysite import views
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^archive/$', views.archive),
|
||||
(r'^about/$', views.about),
|
||||
(r'^contact/$', views.contact),
|
||||
)
|
||||
|
||||
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.
|
||||
|
||||
.. _naming-url-patterns:
|
||||
|
||||
Naming URL patterns
|
||||
===================
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
It's fairly common to use the same view function in multiple URL patterns in
|
||||
your URLconf. For example, these two URL patterns both point to the ``archive``
|
||||
view::
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'/archive/(\d{4})/$', archive),
|
||||
(r'/archive-summary/(\d{4})/$', archive, {'summary': True}),
|
||||
)
|
||||
|
||||
This is completely valid, but it leads to problems when you try to do reverse
|
||||
URL matching (through the ``permalink()`` decorator or the :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*
|
||||
URLpatterns 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
|
||||
using the same view and parameters. Then, you can use this name in reverse URL
|
||||
matching.
|
||||
|
||||
Here's the above example, rewritten to used named URL patterns::
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'/archive/(\d{4})/$', archive, name="full-archive"),
|
||||
url(r'/archive-summary/(\d{4})/$', archive, {'summary': True}, "arch-summary"),
|
||||
)
|
||||
|
||||
With these names in place (``full-archive`` and ``arch-summary``), you can
|
||||
target each pattern individually by using its name:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{% url arch-summary 1945 %}
|
||||
{% url full-archive 2007 %}
|
||||
|
||||
Even though both URL patterns refer to the ``archive`` view here, using the
|
||||
``name`` parameter to ``url()`` allows you to tell them apart in templates.
|
||||
|
||||
The string used for the URL name can contain any characters you like. You are
|
||||
not restricted to valid Python names.
|
||||
|
||||
.. note::
|
||||
|
||||
When you name your URL patterns, make sure you use names that are unlikely
|
||||
to clash with any other application's choice of names. If you call your URL
|
||||
pattern ``comment``, and another application does the same thing, there's
|
||||
no guarantee which URL will be inserted into your template when you use
|
||||
this name.
|
||||
|
||||
Putting a prefix on your URL names, perhaps derived from the application
|
||||
name, will decrease the chances of collision. We recommend something like
|
||||
``myapp-comment`` instead of ``comment``.
|
||||
|
||||
Utility methods
|
||||
===============
|
||||
|
||||
reverse()
|
||||
---------
|
||||
|
||||
If you need to use something similar to the :ttag:`url` template tag in
|
||||
your code, Django provides the ``django.core.urlresolvers.reverse()``. The
|
||||
``reverse()`` function has the following signature::
|
||||
|
||||
reverse(viewname, urlconf=None, args=None, kwargs=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
|
||||
`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::
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
def myview(request):
|
||||
return HttpResponseRedirect(reverse('arch-summary', args=[1945]))
|
||||
|
||||
.. _URL pattern name: `Naming URL patterns`_
|
||||
|
||||
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.
|
186
docs/topics/http/views.txt
Normal file
186
docs/topics/http/views.txt
Normal file
|
@ -0,0 +1,186 @@
|
|||
.. _topics-http-views:
|
||||
|
||||
=============
|
||||
Writing Views
|
||||
=============
|
||||
|
||||
A view function, or *view* for short, is simply a Python function that takes a
|
||||
Web request and returns a Web response. This response can be the HTML contents
|
||||
of a Web page, or a redirect, or a 404 error, or an XML document, or an image .
|
||||
. . or anything, really. The view itself contains whatever arbitrary logic is
|
||||
necessary to return that response. This code can live anywhere you want, as long
|
||||
as it's on your Python path. There's no other requirement--no "magic," so to
|
||||
speak. For the sake of putting the code *somewhere*, let's create a file called
|
||||
``views.py`` in the ``mysite`` directory, which you created in the previous
|
||||
chapter.
|
||||
|
||||
A simple view
|
||||
=============
|
||||
|
||||
Here's a view that returns the current date and time, as an HTML document:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.http import HttpResponse
|
||||
import datetime
|
||||
|
||||
def current_datetime(request):
|
||||
now = datetime.datetime.now()
|
||||
html = "<html><body>It is now %s.</body></html>" % now
|
||||
return HttpResponse(html)
|
||||
|
||||
Let's step through this code one line at a time:
|
||||
|
||||
* First, we import the class ``HttpResponse``, which lives in the
|
||||
``django.http`` module, along with Python's ``datetime`` library.
|
||||
|
||||
* Next, we define a function called ``current_datetime``. This is the view
|
||||
function. Each view function takes an ``HttpRequest`` object as its first
|
||||
parameter, which is typically named ``request``.
|
||||
|
||||
Note that the name of the view function doesn't matter; it doesn't have to
|
||||
be named in a certain way in order for Django to recognize it. We're
|
||||
calling it ``current_datetime`` here, because that name clearly indicates
|
||||
what it does.
|
||||
|
||||
* The view returns an ``HttpResponse`` object that contains the
|
||||
generated response. Each view function is responsible for returning an
|
||||
``HttpResponse`` object. (There are exceptions, but we'll get to those
|
||||
later.)
|
||||
|
||||
.. admonition:: Django's Time Zone
|
||||
|
||||
Django includes a ``TIME_ZONE`` setting that defaults to
|
||||
``America/Chicago``. This probably isn't where you live, so you might want
|
||||
to change it in your settings file.
|
||||
|
||||
Mapping URLs to Views
|
||||
=====================
|
||||
|
||||
So, to recap, this view function returns an HTML page that includes the current
|
||||
date and time. To display this view at a particular URL, you'll need to create a
|
||||
*URLconf*; see :ref:`topics-http-urls` for instructions.
|
||||
|
||||
Returning errors
|
||||
================
|
||||
|
||||
Returning HTTP error codes in Django is easy. We've already mentioned the
|
||||
:class:`HttpResponseNotFound`, :class:`HttpResponseForbidden`,
|
||||
:class:`HttpResponseServerError`, etc., subclasses; just return an instance of one
|
||||
of those subclasses instead of a normal :class:`HttpResponse` in order to signify
|
||||
an error. For example::
|
||||
|
||||
def my_view(request):
|
||||
# ...
|
||||
if foo:
|
||||
return HttpResponseNotFound('<h1>Page not found</h1>')
|
||||
else:
|
||||
return HttpResponse('<h1>Page was found</h1>')
|
||||
|
||||
Because 404 errors are by far the most common HTTP error, there's an easier way
|
||||
to handle those errors.
|
||||
|
||||
The Http404 exception
|
||||
---------------------
|
||||
|
||||
When you return an error such as ``HttpResponseNotFound``, you're responsible
|
||||
for defining the HTML of the resulting error page::
|
||||
|
||||
return HttpResponseNotFound('<h1>Page not found</h1>')
|
||||
|
||||
For convenience, and because it's a good idea to have a consistent 404 error page
|
||||
across your site, Django provides an ``Http404`` exception. If you raise
|
||||
``Http404`` at any point in a view function, Django will catch it and return the
|
||||
standard error page for your application, along with an HTTP error code 404.
|
||||
|
||||
Example usage::
|
||||
|
||||
from django.http import Http404
|
||||
|
||||
def detail(request, poll_id):
|
||||
try:
|
||||
p = Poll.objects.get(pk=poll_id)
|
||||
except Poll.DoesNotExist:
|
||||
raise Http404
|
||||
return render_to_response('polls/detail.html', {'poll': p})
|
||||
|
||||
In order to use the ``Http404`` exception to its fullest, you should create a
|
||||
template that is displayed when a 404 error is raised. This template should be
|
||||
called ``404.html`` and located in the top level of your template tree.
|
||||
|
||||
Customizing error views
|
||||
=======================
|
||||
|
||||
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``.
|
||||
|
||||
This means you need to define a ``404.html`` template in your root template
|
||||
directory. This template will be used for all 404 errors.
|
||||
|
||||
This ``page_not_found`` view should suffice for 99% of Web applications, but if
|
||||
you want to override the 404 view, you can specify ``handler404`` in your
|
||||
URLconf, like so::
|
||||
|
||||
handler404 = 'mysite.views.my_custom_404_view'
|
||||
|
||||
Behind the scenes, Django determines the 404 view by looking for ``handler404``.
|
||||
By default, URLconfs contain the following line::
|
||||
|
||||
from django.conf.urls.defaults import *
|
||||
|
||||
That takes care of setting ``handler404`` in the current module. As you can see
|
||||
in ``django/conf/urls/defaults.py``, ``handler404`` is set to
|
||||
``'django.views.defaults.page_not_found'`` by default.
|
||||
|
||||
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 default 404 view will use that template
|
||||
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 404.
|
||||
|
||||
* The 404 view is passed a ``RequestContext`` and will have access to
|
||||
variables supplied by your ``TEMPLATE_CONTEXT_PROCESSORS`` setting (e.g.,
|
||||
``MEDIA_URL``).
|
||||
|
||||
* If ``DEBUG`` is set to ``True`` (in your settings module), then your 404
|
||||
view will never be used, and the traceback will be displayed instead.
|
||||
|
||||
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``.
|
||||
|
||||
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.
|
||||
|
||||
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, like so::
|
||||
|
||||
handler500 = 'mysite.views.my_custom_error_view'
|
||||
|
||||
Behind the scenes, Django determines the error view by looking for ``handler500``.
|
||||
By default, URLconfs contain the following line::
|
||||
|
||||
from django.conf.urls.defaults import *
|
||||
|
||||
That takes care of setting ``handler500`` in the current module. As you can see
|
||||
in ``django/conf/urls/defaults.py``, ``handler500`` is set to
|
||||
``'django.views.defaults.server_error'`` by default.
|
Loading…
Add table
Add a link
Reference in a new issue