summaryrefslogtreecommitdiff
path: root/parts/django/docs/topics/conditional-view-processing.txt
diff options
context:
space:
mode:
authorNishanth Amuluru2011-01-08 11:20:57 +0530
committerNishanth Amuluru2011-01-08 11:20:57 +0530
commit65411d01d448ff0cd4abd14eee14cf60b5f8fc20 (patch)
treeb4c404363c4c63a61d6e2f8bd26c5b057c1fb09d /parts/django/docs/topics/conditional-view-processing.txt
parent2e35094d43b4cc6974172e1febf76abb50f086ec (diff)
downloadpytask-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/conditional-view-processing.txt')
-rw-r--r--parts/django/docs/topics/conditional-view-processing.txt199
1 files changed, 199 insertions, 0 deletions
diff --git a/parts/django/docs/topics/conditional-view-processing.txt b/parts/django/docs/topics/conditional-view-processing.txt
new file mode 100644
index 0000000..c631a13
--- /dev/null
+++ b/parts/django/docs/topics/conditional-view-processing.txt
@@ -0,0 +1,199 @@
+===========================
+Conditional View Processing
+===========================
+
+.. versionadded:: 1.1
+
+HTTP clients can send a number of headers to tell the server about copies of a
+resource that they have already seen. This is commonly used when retrieving a
+Web page (using an HTTP ``GET`` request) to avoid sending all the data for
+something the client has already retrieved. However, the same headers can be
+used for all HTTP methods (``POST``, ``PUT``, ``DELETE``, etc).
+
+For each page (response) that Django sends back from a view, it might provide
+two HTTP headers: the ``ETag`` header and the ``Last-Modified`` header. These
+headers are optional on HTTP responses. They can be set by your view function,
+or you can rely on the :class:`~django.middleware.common.CommonMiddleware`
+middleware to set the ``ETag`` header.
+
+When the client next requests the same resource, it might send along a header
+such as `If-modified-since`_, containing the date of the last modification
+time it was sent, or `If-none-match`_, containing the ``ETag`` it was sent.
+If the current version of the page matches the ``ETag`` sent by the client, or
+if the resource has not been modified, a 304 status code can be sent back,
+instead of a full response, telling the client that nothing has changed.
+
+.. _If-none-match: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26
+.. _If-modified-since: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25
+
+When you need more fine-grained control you may use per-view conditional
+processing functions.
+
+.. conditional-decorators:
+
+The ``condition`` decorator
+===========================
+
+Sometimes (in fact, quite often) you can create functions to rapidly compute the ETag_
+value or the last-modified time for a resource, **without** needing to do all
+the computations needed to construct the full view. Django can then use these
+functions to provide an "early bailout" option for the view processing.
+Telling the client that the content has not been modified since the last
+request, perhaps.
+
+.. _ETag: http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.11
+
+These two functions are passed as parameters the
+``django.views.decorators.http.condition`` decorator. This decorator uses
+the two functions (you only need to supply one, if you can't compute both
+quantities easily and quickly) to work out if the headers in the HTTP request
+match those on the resource. If they don't match, a new copy of the resource
+must be computed and your normal view is called.
+
+The ``condition`` decorator's signature looks like this::
+
+ condition(etag_func=None, last_modified_func=None)
+
+The two functions, to compute the ETag and the last modified time, will be
+passed the incoming ``request`` object and the same parameters, in the same
+order, as the view function they are helping to wrap. The function passed
+``last_modified_func`` should return a standard datetime value specifying the
+last time the resource was modified, or ``None`` if the resource doesn't
+exist. The function passed to the ``etag`` decorator should return a string
+representing the `Etag`_ for the resource, or ``None`` if it doesn't exist.
+
+Using this feature usefully is probably best explained with an example.
+Suppose you have this pair of models, representing a simple blog system::
+
+ import datetime
+ from django.db import models
+
+ class Blog(models.Model):
+ ...
+
+ class Entry(models.Model):
+ blog = models.ForeignKey(Blog)
+ published = models.DateTimeField(default=datetime.datetime.now)
+ ...
+
+If the front page, displaying the latest blog entries, only changes when you
+add a new blog entry, you can compute the last modified time very quickly. You
+need the latest ``published`` date for every entry associated with that blog.
+One way to do this would be::
+
+ def latest_entry(request, blog_id):
+ return Entry.objects.filter(blog=blog_id).latest("published").published
+
+You can then use this function to provide early detection of an unchanged page
+for your front page view::
+
+ from django.views.decorators.http import condition
+
+ @condition(last_modified_func=latest_entry)
+ def front_page(request, blog_id):
+ ...
+
+Shortcuts for only computing one value
+======================================
+
+As a general rule, if you can provide functions to compute *both* the ETag and
+the last modified time, you should do so. You don't know which headers any
+given HTTP client will send you, so be prepared to handle both. However,
+sometimes only one value is easy to compute and Django provides decorators
+that handle only ETag or only last-modified computations.
+
+The ``django.views.decorators.http.etag`` and
+``django.views.decorators.http.last_modified`` decorators are passed the same
+type of functions as the ``condition`` decorator. Their signatures are::
+
+ etag(etag_func)
+ last_modified(last_modified_func)
+
+We could write the earlier example, which only uses a last-modified function,
+using one of these decorators::
+
+ @last_modified(latest_entry)
+ def front_page(request, blog_id):
+ ...
+
+...or::
+
+ def front_page(request, blog_id):
+ ...
+ front_page = last_modified(latest_entry)(front_page)
+
+Use ``condition`` when testing both conditions
+------------------------------------------------
+
+It might look nicer to some people to try and chain the ``etag`` and
+``last_modified`` decorators if you want to test both preconditions. However,
+this would lead to incorrect behavior.
+
+::
+
+ # Bad code. Don't do this!
+ @etag(etag_func)
+ @last_modified(last_modified_func)
+ def my_view(request):
+ # ...
+
+ # End of bad code.
+
+The first decorator doesn't know anything about the second and might
+answer that the response is not modified even if the second decorators would
+determine otherwise. The ``condition`` decorator uses both callback functions
+simultaneously to work out the right action to take.
+
+Using the decorators with other HTTP methods
+============================================
+
+The ``condition`` decorator is useful for more than only ``GET`` and
+``HEAD`` requests (``HEAD`` requests are the same as ``GET`` in this
+situation). It can be used also to be used to provide checking for ``POST``,
+``PUT`` and ``DELETE`` requests. In these situations, the idea isn't to return
+a "not modified" response, but to tell the client that the resource they are
+trying to change has been altered in the meantime.
+
+For example, consider the following exchange between the client and server:
+
+ 1. Client requests ``/foo/``.
+ 2. Server responds with some content with an ETag of ``"abcd1234"``.
+ 3. Client sends an HTTP ``PUT`` request to ``/foo/`` to update the
+ resource. It also sends an ``If-Match: "abcd1234"`` header to specify
+ the version it is trying to update.
+ 4. Server checks to see if the resource has changed, by computing the ETag
+ the same way it does for a ``GET`` request (using the same function).
+ If the resource *has* changed, it will return a 412 status code code,
+ meaning "precondition failed".
+ 5. Client sends a ``GET`` request to ``/foo/``, after receiving a 412
+ response, to retrieve an updated version of the content before updating
+ it.
+
+The important thing this example shows is that the same functions can be used
+to compute the ETag and last modification values in all situations. In fact,
+you **should** use the same functions, so that the same values are returned
+every time.
+
+Comparison with middleware conditional processing
+=================================================
+
+You may notice that Django already provides simple and straightforward
+conditional ``GET`` handling via the
+:class:`django.middleware.http.ConditionalGetMiddleware` and
+:class:`~django.middleware.common.CommonMiddleware`. Whilst certainly being
+easy to use and suitable for many situations, those pieces of middleware
+functionality have limitations for advanced usage:
+
+ * They are applied globally to all views in your project
+ * They don't save you from generating the response itself, which may be
+ expensive
+ * They are only appropriate for HTTP ``GET`` requests.
+
+You should choose the most appropriate tool for your particular problem here.
+If you have a way to compute ETags and modification times quickly and if some
+view takes a while to generate the content, you should consider using the
+``condition`` decorator described in this document. If everything already runs
+fairly quickly, stick to using the middleware and the amount of network
+traffic sent back to the clients will still be reduced if the view hasn't
+changed.
+