diff options
author | Nishanth Amuluru | 2011-01-08 11:20:57 +0530 |
---|---|---|
committer | Nishanth Amuluru | 2011-01-08 11:20:57 +0530 |
commit | 65411d01d448ff0cd4abd14eee14cf60b5f8fc20 (patch) | |
tree | b4c404363c4c63a61d6e2f8bd26c5b057c1fb09d /parts/django/docs/topics/http | |
parent | 2e35094d43b4cc6974172e1febf76abb50f086ec (diff) | |
download | pytask-65411d01d448ff0cd4abd14eee14cf60b5f8fc20.tar.gz pytask-65411d01d448ff0cd4abd14eee14cf60b5f8fc20.tar.bz2 pytask-65411d01d448ff0cd4abd14eee14cf60b5f8fc20.zip |
Added buildout stuff and made changes accordingly
--HG--
rename : profile/management/__init__.py => eggs/djangorecipe-0.20-py2.6.egg/EGG-INFO/dependency_links.txt
rename : profile/management/__init__.py => eggs/djangorecipe-0.20-py2.6.egg/EGG-INFO/not-zip-safe
rename : profile/management/__init__.py => eggs/infrae.subversion-1.4.5-py2.6.egg/EGG-INFO/dependency_links.txt
rename : profile/management/__init__.py => eggs/infrae.subversion-1.4.5-py2.6.egg/EGG-INFO/not-zip-safe
rename : profile/management/__init__.py => eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/EGG-INFO/dependency_links.txt
rename : profile/management/__init__.py => eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/EGG-INFO/not-zip-safe
rename : profile/management/__init__.py => eggs/py-1.4.0-py2.6.egg/EGG-INFO/dependency_links.txt
rename : profile/management/__init__.py => eggs/py-1.4.0-py2.6.egg/EGG-INFO/not-zip-safe
rename : profile/management/__init__.py => eggs/zc.buildout-1.5.2-py2.6.egg/EGG-INFO/dependency_links.txt
rename : profile/management/__init__.py => eggs/zc.buildout-1.5.2-py2.6.egg/EGG-INFO/not-zip-safe
rename : profile/management/__init__.py => eggs/zc.recipe.egg-1.3.2-py2.6.egg/EGG-INFO/dependency_links.txt
rename : profile/management/__init__.py => eggs/zc.recipe.egg-1.3.2-py2.6.egg/EGG-INFO/not-zip-safe
rename : profile/management/__init__.py => parts/django/Django.egg-info/dependency_links.txt
rename : taskapp/models.py => parts/django/django/conf/app_template/models.py
rename : taskapp/tests.py => parts/django/django/conf/app_template/tests.py
rename : taskapp/views.py => parts/django/django/conf/app_template/views.py
rename : taskapp/views.py => parts/django/django/contrib/gis/tests/geo3d/views.py
rename : profile/management/__init__.py => parts/django/tests/modeltests/delete/__init__.py
rename : profile/management/__init__.py => parts/django/tests/modeltests/files/__init__.py
rename : profile/management/__init__.py => parts/django/tests/modeltests/invalid_models/__init__.py
rename : profile/management/__init__.py => parts/django/tests/modeltests/m2m_signals/__init__.py
rename : profile/management/__init__.py => parts/django/tests/modeltests/model_package/__init__.py
rename : profile/management/__init__.py => parts/django/tests/regressiontests/bash_completion/__init__.py
rename : profile/management/__init__.py => parts/django/tests/regressiontests/bash_completion/management/__init__.py
rename : profile/management/__init__.py => parts/django/tests/regressiontests/bash_completion/management/commands/__init__.py
rename : profile/management/__init__.py => parts/django/tests/regressiontests/bash_completion/models.py
rename : profile/management/__init__.py => parts/django/tests/regressiontests/delete_regress/__init__.py
rename : profile/management/__init__.py => parts/django/tests/regressiontests/file_storage/__init__.py
rename : profile/management/__init__.py => parts/django/tests/regressiontests/max_lengths/__init__.py
rename : profile/forms.py => pytask/profile/forms.py
rename : profile/management/__init__.py => pytask/profile/management/__init__.py
rename : profile/management/commands/seed_db.py => pytask/profile/management/commands/seed_db.py
rename : profile/models.py => pytask/profile/models.py
rename : profile/templatetags/user_tags.py => pytask/profile/templatetags/user_tags.py
rename : taskapp/tests.py => pytask/profile/tests.py
rename : profile/urls.py => pytask/profile/urls.py
rename : profile/utils.py => pytask/profile/utils.py
rename : profile/views.py => pytask/profile/views.py
rename : static/css/base.css => pytask/static/css/base.css
rename : taskapp/tests.py => pytask/taskapp/tests.py
rename : taskapp/views.py => pytask/taskapp/views.py
rename : templates/base.html => pytask/templates/base.html
rename : templates/profile/browse_notifications.html => pytask/templates/profile/browse_notifications.html
rename : templates/profile/edit.html => pytask/templates/profile/edit.html
rename : templates/profile/view.html => pytask/templates/profile/view.html
rename : templates/profile/view_notification.html => pytask/templates/profile/view_notification.html
rename : templates/registration/activate.html => pytask/templates/registration/activate.html
rename : templates/registration/activation_email.txt => pytask/templates/registration/activation_email.txt
rename : templates/registration/activation_email_subject.txt => pytask/templates/registration/activation_email_subject.txt
rename : templates/registration/logged_out.html => pytask/templates/registration/logged_out.html
rename : templates/registration/login.html => pytask/templates/registration/login.html
rename : templates/registration/logout.html => pytask/templates/registration/logout.html
rename : templates/registration/password_change_done.html => pytask/templates/registration/password_change_done.html
rename : templates/registration/password_change_form.html => pytask/templates/registration/password_change_form.html
rename : templates/registration/password_reset_complete.html => pytask/templates/registration/password_reset_complete.html
rename : templates/registration/password_reset_confirm.html => pytask/templates/registration/password_reset_confirm.html
rename : templates/registration/password_reset_done.html => pytask/templates/registration/password_reset_done.html
rename : templates/registration/password_reset_email.html => pytask/templates/registration/password_reset_email.html
rename : templates/registration/password_reset_form.html => pytask/templates/registration/password_reset_form.html
rename : templates/registration/registration_complete.html => pytask/templates/registration/registration_complete.html
rename : templates/registration/registration_form.html => pytask/templates/registration/registration_form.html
rename : utils.py => pytask/utils.py
Diffstat (limited to 'parts/django/docs/topics/http')
-rw-r--r-- | parts/django/docs/topics/http/_images/middleware.png | bin | 0 -> 56301 bytes | |||
-rw-r--r-- | parts/django/docs/topics/http/file-uploads.txt | 394 | ||||
-rw-r--r-- | parts/django/docs/topics/http/generic-views.txt | 5 | ||||
-rw-r--r-- | parts/django/docs/topics/http/index.txt | 15 | ||||
-rw-r--r-- | parts/django/docs/topics/http/middleware.txt | 179 | ||||
-rw-r--r-- | parts/django/docs/topics/http/sessions.txt | 529 | ||||
-rw-r--r-- | parts/django/docs/topics/http/shortcuts.txt | 229 | ||||
-rw-r--r-- | parts/django/docs/topics/http/urls.txt | 890 | ||||
-rw-r--r-- | parts/django/docs/topics/http/views.txt | 202 |
9 files changed, 2443 insertions, 0 deletions
diff --git a/parts/django/docs/topics/http/_images/middleware.png b/parts/django/docs/topics/http/_images/middleware.png Binary files differnew file mode 100644 index 0000000..505c70a --- /dev/null +++ b/parts/django/docs/topics/http/_images/middleware.png diff --git a/parts/django/docs/topics/http/file-uploads.txt b/parts/django/docs/topics/http/file-uploads.txt new file mode 100644 index 0000000..a06a1ca --- /dev/null +++ b/parts/django/docs/topics/http/file-uploads.txt @@ -0,0 +1,394 @@ +============ +File Uploads +============ + +.. currentmodule:: django.core.files + +.. versionadded:: 1.0 + +When Django handles a file upload, the file data ends up placed in +:attr:`request.FILES <django.http.HttpRequest.FILES>` (for more on the +``request`` object see the documentation for :doc:`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 :class:`~django.forms.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 +:attr:`request.FILES <django.http.HttpRequest.FILES>`, which is a dictionary +containing a key for each :class:`~django.forms.FileField` (or +:class:`~django.forms.ImageField`, or other :class:`~django.forms.FileField` +subclass) in the form. So the data from the above form would +be accessible as ``request.FILES['file']``. + +Note that :attr:`request.FILES <django.http.HttpRequest.FILES>` will only +contain data if the request method was ``POST`` and the ``<form>`` that posted +the request has the attribute ``enctype="multipart/form-data"``. Otherwise, +``request.FILES`` will be empty. + +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 :attr:`request.FILES <django.http.HttpRequest.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 +:attr:`request.FILES <django.http.HttpRequest.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) + destination.close() + +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: + + :setting:`FILE_UPLOAD_MAX_MEMORY_SIZE` + The maximum size, in bytes, for files that will be uploaded into memory. + Files larger than :setting:`FILE_UPLOAD_MAX_MEMORY_SIZE` will be + streamed to disk. + + Defaults to 2.5 megabytes. + + :setting:`FILE_UPLOAD_TEMP_DIR` + The directory where uploaded files larger than + :setting:`FILE_UPLOAD_MAX_MEMORY_SIZE` will be stored. + + Defaults to your system's standard temporary directory (i.e. ``/tmp`` on + most Unix-like systems). + + :setting:`FILE_UPLOAD_PERMISSIONS` + The numeric mode (i.e. ``0644``) to set newly uploaded files to. For + more information about what these modes mean, see the `documentation for + os.chmod`_ + + If this isn't given or is ``None``, you'll get operating-system + dependent behavior. On most platforms, temporary files will have a mode + of ``0600``, and files saved from memory will be saved using the + system's standard umask. + + .. warning:: + + If you're not familiar with file modes, please note that the leading + ``0`` is very important: it indicates an octal number, which is the + way that modes must be specified. If you try to use ``644``, you'll + get totally incorrect behavior. + + **Always prefix the mode with a 0.** + + :setting:`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." + +.. _documentation for os.chmod: http://docs.python.org/library/os.html#os.chmod + +``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. + +.. note:: + + Like regular Python files, you can read the file line-by-line simply by + iterating over the uploaded file: + + .. code-block:: python + + for line in uploadedfile: + do_something_with(line) + + However, *unlike* standard Python files, :class:`UploadedFile` only + understands ``\n`` (also known as "Unix-style") line endings. If you know + that you need to handle uploaded files with different line endings, you'll + need to do so in your view. + +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.POST`` or ``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.POST`` or ``request.FILES`` Django will + throw an error. + + Thus, you should always modify uploading handlers as early in your view as + possible. + + Also, ``request.POST`` is accessed by + :class:`~django.middleware.csrf.CsrfViewMiddleware` which is enabled by + default. This means you will probably need to use + :func:`~django.views.decorators.csrf.csrf_exempt` on your view to allow you + to change the upload handlers. Assuming you do need CSRF protection, you + will then need to use :func:`~django.views.decorators.csrf.csrf_protect` on + the function that actually processes the request. Note that this means that + the handlers may start receiving the file upload before the CSRF checks have + been done. Example code: + + .. code-block:: python + + from django.views.decorators.csrf import csrf_exempt, csrf_protect + + @csrf_exempt + def upload_file_view(request): + request.upload_handlers.insert(0, ProgressBarUploadHandler()) + return _upload_file_view(request) + + @csrf_protect + def _upload_file_view(request): + ... # Process request + + +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``. + + ``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. diff --git a/parts/django/docs/topics/http/generic-views.txt b/parts/django/docs/topics/http/generic-views.txt new file mode 100644 index 0000000..15f895e --- /dev/null +++ b/parts/django/docs/topics/http/generic-views.txt @@ -0,0 +1,5 @@ +============= +Generic views +============= + +See :doc:`/ref/generic-views`. diff --git a/parts/django/docs/topics/http/index.txt b/parts/django/docs/topics/http/index.txt new file mode 100644 index 0000000..5ef776d --- /dev/null +++ b/parts/django/docs/topics/http/index.txt @@ -0,0 +1,15 @@ +Handling HTTP requests +====================== + +Information on handling HTTP requests in Django: + +.. toctree:: + :maxdepth: 1 + + urls + views + file-uploads + shortcuts + generic-views + middleware + sessions diff --git a/parts/django/docs/topics/http/middleware.txt b/parts/django/docs/topics/http/middleware.txt new file mode 100644 index 0000000..d376c6b --- /dev/null +++ b/parts/django/docs/topics/http/middleware.txt @@ -0,0 +1,179 @@ +========== +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 :doc:`built-in +middleware reference </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.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + ) + +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()`` must 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`. + +Unlike the ``process_request()`` and ``process_view()`` methods, the +``process_response()`` method is always called, even if the ``process_request()`` +and ``process_view()`` methods of the same middleware class were skipped because +an earlier middleware method returned an :class:`~django.http.HttpResponse` +(this means that your ``process_response()`` method cannot rely on setup done in +``process_request()``, for example). In addition, during the response phase the +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. + +.. _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. + +Again, middleware are run in reverse order during the response phase, which +includes ``process_exception``. If an exception middleware return a response, +the middleware classes above that middleware will not be called at all. + +``__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 :doc:`Django's available middleware + </ref/middleware>` for examples. + + * If you write a middleware component that you think would be useful to + other people, contribute to the community! :doc:`Let us know + </internals/contributing>`, and we'll consider adding it to Django. diff --git a/parts/django/docs/topics/http/sessions.txt b/parts/django/docs/topics/http/sessions.txt new file mode 100644 index 0000000..8a0f0d4 --- /dev/null +++ b/parts/django/docs/topics/http/sessions.txt @@ -0,0 +1,529 @@ +=================== +How to use sessions +=================== + +.. module:: django.contrib.sessions + :synopsis: Provides session management for Django projects. + +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 :doc:`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. + +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 +============================== + +.. versionadded:: 1.0 + +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 database-backed sessions +------------------------------ + +If you want to use a database-backed session, you need to add +``'django.contrib.sessions'`` to your ``INSTALLED_APPS`` setting. + +Once you have configured your installation, run ``manage.py syncdb`` +to install the single database table that stores session data. + +Using cached sessions +--------------------- + +For better performance, you may want to use a cache-based session backend. + +.. versionchanged:: 1.1 + Django 1.0 did not include the ``cached_db`` session backend. + +To store session data using Django's cache system, you'll first need to make +sure you've configured your cache; see the :doc:`cache documentation +</topics/cache>` for details. + +.. warning:: + + You should 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. + +Once your cache is configured, you've got two choices for how to store data in +the cache: + + * Set :setting:`SESSION_ENGINE` to + ``"django.contrib.sessions.backends.cache"`` for a simple caching session + store. Session data will be stored directly your cache. However, session + data may not be persistent: cached data can be evicted if the cache fills + up or if the cache server is restarted. + + * For persistent, cached data, set :setting:`SESSION_ENGINE` to + ``"django.contrib.sessions.backends.cached_db"``. This uses a + write-through cache -- every write to the cache will also be written to + the database. Session reads only use the database if the data is not + already in the cache. + +Both session stores are quite fast, but the simple cache is faster because it +disregards persistence. In most cases, the ``cached_db`` backend will be fast +enough, but if you need that last bit of performance, and are willing to let +session data be expunged from time to time, the ``cache`` backend is for you. + +If you use the ``cached_db`` session backend, you also need to follow the +configuration instructions for the `using database-backed sessions`_. + +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 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()`` + + * ``clear()`` + +.. versionadded:: 1.0 + ``setdefault()`` and ``clear()`` are new in this version. + +It also has these methods: + + * ``flush()`` + + .. versionadded:: 1.0 + + Delete the current session data from the session 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 + :func:`django.contrib.auth.logout()` function 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)`` + + .. versionadded:: 1.0 + + 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. + + Reading a session is not considered activity for expiration + purposes. Session expiration is computed from the last time the + session was *modified*. + + * ``get_expiry_age()`` + + .. versionadded:: 1.0 + + 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()`` + + .. versionadded:: 1.0 + + 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()`` + + .. versionadded:: 1.0 + + 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 +=========================== + +.. versionadded:: 1.0 + +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. + +.. versionadded:: 1.0 + +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 +========================== + +If you're using the database backend, 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: ``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 :doc:`Django settings </ref/settings>` give you control over session behavior: + +SESSION_ENGINE +-------------- + +.. versionadded:: 1.0 + +.. versionchanged:: 1.1 + The ``cached_db`` backend was added + +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'`` + * ``'django.contrib.sessions.backends.cached_db'`` + +See `configuring the session engine`_ for more details. + +SESSION_FILE_PATH +----------------- + +.. versionadded:: 1.0 + +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"`` (note the leading dot!) 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_PATH +------------------- + +.. versionadded:: 1.0 + +Default: ``'/'`` + +The path set on the session cookie. This should either match the URL path of +your Django installation or be parent of that path. + +This is useful if you have multiple Django instances running under the same +hostname. They can use different cookie paths, and each instance will only see +its own session cookie. + +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://docs.python.org/library/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. diff --git a/parts/django/docs/topics/http/shortcuts.txt b/parts/django/docs/topics/http/shortcuts.txt new file mode 100644 index 0000000..315460e --- /dev/null +++ b/parts/django/docs/topics/http/shortcuts.txt @@ -0,0 +1,229 @@ +========================= +Django shortcut functions +========================= + +.. module:: django.shortcuts + :synopsis: + Convience shortcuts that spam multiple levels of Django's MVC stack. + +.. index:: shortcuts + +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`` +====================== + +.. function:: render_to_response(template[, dictionary][, context_instance][, mimetype]) + + Renders a given template with a given context dictionary and returns an + :class:`~django.http.HttpResponse` object with that rendered text. + +Required arguments +------------------ + +``template`` + The full name of a template to use or sequence of template names. If a + sequence is given, the first template that exists will be used. See the + :ref:`template loader documentation <ref-templates-api-the-python-api>` + for more information on how templates are found. + +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 :class:`~django.template.Context` instance (filled + with values from ``dictionary``). If you need to use :ref:`context + processors <subclassing-context-requestcontext>`, render the template with + a :class:`~django.template.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`` + The MIME type to use for the resulting document. Defaults to the value of + the :setting:`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'}) + return HttpResponse(t.render(c), + mimetype="application/xhtml+xml") + +``redirect`` +============ + +.. function:: redirect(to[, permanent=False], *args, **kwargs) + + .. versionadded:: 1.1 + + Returns an :class:`~django.http.HttpResponseRedirect` to the appropriate URL + for the arguments passed. + + The arguments could be: + + * A model: the model's `get_absolute_url()` function will be called. + + * A view name, possibly with arguments: `urlresolvers.reverse()` will + be used to reverse-resolve the name. + + * A URL, which will be used as-is for the redirect location. + + By default issues a temporary redirect; pass ``permanent=True`` to issue a + permanent redirect + +Examples +-------- + +You can use the :func:`redirect` function in a number of ways. + + 1. By passing some object; that object's + :meth:`~django.db.models.Model.get_absolute_url` method will be called + to figure out the redirect URL:: + + def my_view(request): + ... + object = MyModel.objects.get(...) + return redirect(object) + + 2. By passing the name of a view and optionally some positional or + keyword arguments; the URL will be reverse resolved using the + :func:`~django.core.urlresolvers.reverse` method:: + + def my_view(request): + ... + return redirect('some-view-name', foo='bar') + + 3. By passing a hardcoded URL to redirect to:: + + def my_view(request): + ... + return redirect('/some/url/') + + This also works with full URLs:: + + def my_view(request): + ... + return redirect('http://example.com/') + +By default, :func:`redirect` returns a temporary redirect. All of the above +forms accept a ``permanent`` argument; if set to ``True`` a permanent redirect +will be returned:: + + def my_view(request): + ... + object = MyModel.objects.get(...) + return redirect(object, permanent=True) + +``get_object_or_404`` +===================== + +.. function:: get_object_or_404(klass, *args, **kwargs) + + Calls :meth:`~django.db.models.QuerySet.get()` on a given model manager, + but it raises :class:`~django.http.Http404` instead of the model's + :class:`~django.core.exceptions.DoesNotExist` exception. + +Required arguments +------------------ + +``klass`` + A :class:`~django.db.models.Model`, :class:`~django.db.models.Manager` or + :class:`~django.db.models.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()``, a +:class:`~django.core.exceptions.MultipleObjectsReturned` exception +will be raised if more than one object is found. + +``get_list_or_404`` +=================== + +.. function:: get_list_or_404(klass, *args, **kwargs) + + Returns the result of :meth:`~django.db.models.QuerySet.filter()` on a + given model manager, raising :class:`~django.http.Http404` if the resulting + list is empty. + +Required arguments +------------------ + +``klass`` + A :class:`~django.db.models.Model`, :class:`~django.db.models.Manager` or + :class:`~django.db.models.query.QuerySet` instance from which to get the + list. + +``**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 = list(MyModel.objects.filter(published=True)) + if not my_objects: + raise Http404 diff --git a/parts/django/docs/topics/http/urls.txt b/parts/django/docs/topics/http/urls.txt new file mode 100644 index 0000000..2361297 --- /dev/null +++ b/parts/django/docs/topics/http/urls.txt @@ -0,0 +1,890 @@ +============== +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. + +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 :setting:`ROOT_URLCONF` setting, but if the incoming + ``HttpRequest`` object has an attribute called ``urlconf`` (set by + middleware :ref:`request processing <request-middleware>`), its value + will be used in place of the :setting:`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 :func:`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 +:func:`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: + +.. module:: django.conf.urls.defaults + +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]]) + +...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 +--- + +.. versionadded:: 1.0 + +.. function:: url(regex, view, kwargs=None, name=None, prefix='') + +You can use the ``url()`` function, instead of a tuple, as an argument to +``patterns()``. This is convenient if you want to specify a name without the +optional extra arguments dictionary. For example:: + + 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 +---------- + +.. 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. + +.. versionchanged:: 1.2 + Previous versions of Django only accepted strings representing import paths. + +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. + +.. versionchanged:: 1.2 + Previous versions of Django only accepted strings representing import paths. + +include +------- + +.. function:: include(<module or pattern_list>) + +A function that takes a full Python import path to another URLconf module that +should be "included" in this place. + +.. versionadded:: 1.1 + +:func:`include` also accepts as an argument an iterable that returns URL +patterns. + +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 :doc:`Django overview </intro/overview>`:: + + from django.conf.urls.defaults import * + + urlpatterns = patterns('', + (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'), + ) + +In this example, each view has a common prefix -- ``'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('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')), + ) + +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. + +.. versionadded:: 1.1 + +Another possibility is to include additional URL patterns not by specifying the +URLconf Python module defining them as the `include`_ argument but by using +directly the pattern list as returned by `patterns`_ instead. For example:: + + from django.conf.urls.defaults import * + + extra_patterns = patterns('', + url(r'reports/(?P<id>\d+)/$', 'credit.views.report', name='credit-reports'), + url(r'charge/$', 'credit.views.charge', name='credit-charge'), + ) + + urlpatterns = patterns('', + url(r'^$', 'apps.main.views.homepage', name='site-homepage'), + (r'^help/', include('apps.help.urls')), + (r'^credit/', include(extra_patterns)), + ) + +This approach can be seen in use when you deploy an instance of the Django +Admin application. The Django Admin is deployed as instances of a +:class:`~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. + +.. _`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. + +.. _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>`. + +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 :doc:`generic views </ref/generic-views>` and in the +:doc:`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 +=================== + +.. versionadded:: 1.0 + +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 use 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``. + +.. _topics-http-reversing-url-namespaces: + +URL namespaces +-------------- + +.. versionadded:: 1.1 + +Namespaced URLs are specified using the ``:`` operator. For example, the main +index page of the admin application is referenced using ``admin:index``. This +indicates a namespace of ``admin``, and a named URL of ``index``. + +Namespaces can also be nested. The named URL ``foo:bar:whiz`` would look for +a pattern named ``whiz`` in the namespace ``bar`` that is itself defined within +the top-level namespace ``foo``. + +When given a namespaced URL (e.g. ``myapp:index``) to resolve, Django splits +the fully qualified name into parts, and then tries the following lookup: + + 1. First, Django looks for a matching application namespace (in this + example, ``myapp``). This will yield a list of instances of that + application. + + 2. If there is a *current* application defined, Django finds and returns + the URL resolver for that instance. The *current* application can be + specified as an attribute on the template context - applications that + expect to have multiple deployments should set the ``current_app`` + attribute on any ``Context`` or ``RequestContext`` that is used to + render a template. + + The current application can also be specified manually as an argument + to the :func:`reverse()` function. + + 3. If there is no current application. Django looks for a default + application instance. The default application instance is the instance + that has an instance namespace matching the application namespace (in + this example, an instance of the ``myapp`` called ``myapp``). + + 4. If there is no default application instance, Django will pick the last + deployed instance of the application, whatever its instance name may be. + + 5. If the provided namespace doesn't match an application namespace in + step 1, Django will attempt a direct lookup of the namespace as an + instance namespace. + +If there are nested namespaces, these steps are repeated for each part of the +namespace until only the view name is unresolved. The view name will then be +resolved into a URL in the namespace that has been found. + +To show this resolution strategy in action, consider an example of two instances +of ``myapp``: one called ``foo``, and one called ``bar``. ``myapp`` has a main +index page with a URL named `index`. Using this setup, the following lookups are +possible: + + * If one of the instances is current - say, if we were rendering a utility page + in the instance ``bar`` - ``myapp:index`` will resolve to the index page of + the instance ``bar``. + + * If there is no current instance - say, if we were rendering a page + somewhere else on the site - ``myapp:index`` will resolve to the 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 + urlpatterns of the project. + + * ``foo:index`` will always resolve to the index page of the instance ``foo``. + +If there was also a default instance - i.e., an instance named `myapp` - the +following would happen: + + * If one of the instances is current - say, if we were rendering a utility page + in the instance ``bar`` - ``myapp:index`` will resolve to the index page of + the instance ``bar``. + + * If there is no current instance - say, if we were rendering a page somewhere + else on the site - ``myapp:index`` will resolve to the index page of the + default instance. + + * ``foo:index`` will again resolve to the index page of the instance ``foo``. + + +Utility methods +=============== + +reverse() +--------- + +If you need to use something similar to the :ttag:`url` template tag in +your code, Django provides the following method (in the +``django.core.urlresolvers`` module): + +.. 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 +`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`_ + +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. + +.. versionadded:: 1.1 + +The ``current_app`` argument allows you to provide a hint to the resolver +indicating the application to which the currently executing view belongs. +This ``current_app`` argument is used as a hint to resolve application +namespaces into URLs on specific application instances, according to the +:ref:`namespaced URL resolution strategy <topics-http-reversing-url-namespaces>`. + +.. admonition:: Make sure your views are all correct. + + As part of working out which URL names map to which patterns, the + ``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. + +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 +the triple (view function, arguments, keyword arguments). + +If the URL does not resolve, the function raises an +:class:`~django.http.Http404` exception. + +For example, it can be used for testing if 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() + +.. versionadded:: 1.0 + +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 webserver, this is always ``"/"``, but it can be +changed, for instance by using ``django.root`` (see :ref:`How to use +Django with Apache and mod_python <howto-deployment-modpython>`).
\ No newline at end of file diff --git a/parts/django/docs/topics/http/views.txt b/parts/django/docs/topics/http/views.txt new file mode 100644 index 0000000..2818f42 --- /dev/null +++ b/parts/django/docs/topics/http/views.txt @@ -0,0 +1,202 @@ +============= +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 :class:`~django.http.HttpResponse` from the + :mod:`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 :class:`~django.http.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 :class:`~django.http.HttpResponse` object that + contains the generated response. Each view function is responsible for + returning an :class:`~django.http.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 :doc:`/topics/http/urls` for instructions. + +Returning errors +================ + +Returning HTTP error codes in Django is easy. There are subclasses of +:class:`~django.http.HttpResponse` for a number of common HTTP status codes +other than 200 (which means *"OK"*). You can find the full list of available +subclasses in the :ref:`request/response <ref-httpresponse-subclasses>` +documentation. Just return an instance of one of those subclasses instead of +a normal :class:`~django.http.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>') + +There isn't a specialized subclass for every possible HTTP response code, +since many of them aren't going to be that common. However, as documented in +the :class:`~django.http.HttpResponse` documentation, you can also pass the +HTTP status code into the constructor for :class:`~django.http.HttpResponse` +to create a return class for any status code you like. For example:: + + def my_view(request): + # ... + + # Return a "created" (201) response code. + return HttpResponse(status=201) + +Because 404 errors are by far the most common HTTP error, there's an easier way +to handle those errors. + +The Http404 exception +--------------------- + +.. class:: django.http.Http404() + +When you return an error such as :class:`~django.http.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 :class:`~django.template.RequestContext` and + will have access to variables supplied by your + :setting:`TEMPLATE_CONTEXT_PROCESSORS` setting (e.g., + :setting:`MEDIA_URL`). + + * If :setting:`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. |