mirror of
https://github.com/django/django.git
synced 2025-07-04 01:39:20 +00:00
[soc2009/http-wsgi-improvements] Merged up to 11103 from trunk.
git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/http-wsgi-improvements@11109 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
7acae8f4d8
commit
eac54911f5
1
AUTHORS
1
AUTHORS
@ -226,6 +226,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Ian G. Kelly <ian.g.kelly@gmail.com>
|
||||
Ryan Kelly <ryan@rfk.id.au>
|
||||
Thomas Kerpe <thomas@kerpe.net>
|
||||
Wiley Kestner <wiley.kestner@gmail.com>
|
||||
Ossama M. Khayat <okhayat@yahoo.com>
|
||||
Ben Khoo <khoobks@westnet.com.au>
|
||||
Garth Kidd <http://www.deadlybloodyserious.com/>
|
||||
|
@ -36,7 +36,7 @@
|
||||
<ul>
|
||||
{% regroup models by app_label as grouped_models %}
|
||||
{% for group in grouped_models %}
|
||||
<li><a href="#{{ group.grouper }}">{{ group.grouper|capfirst }}</a></li>
|
||||
<li><a href="#app-{{ group.grouper }}">{{ group.grouper|capfirst }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -37,6 +37,9 @@ def post_comment(request, next=None):
|
||||
if not data.get('email', ''):
|
||||
data["email"] = request.user.email
|
||||
|
||||
# Check to see if the POST data overrides the view's next argument.
|
||||
next = data.get("next", next)
|
||||
|
||||
# Look up the object we're trying to comment about
|
||||
ctype = data.get("content_type")
|
||||
object_pk = data.get("object_pk")
|
||||
|
@ -3,6 +3,7 @@ from django.template import resolve_variable
|
||||
from django.core.cache import cache
|
||||
from django.utils.encoding import force_unicode
|
||||
from django.utils.http import urlquote
|
||||
from django.utils.hashcompat import md5_constructor
|
||||
|
||||
register = Library()
|
||||
|
||||
@ -23,7 +24,8 @@ class CacheNode(Node):
|
||||
except (ValueError, TypeError):
|
||||
raise TemplateSyntaxError('"cache" tag got a non-integer timeout value: %r' % expire_time)
|
||||
# Build a unicode key for this fragment and all vary-on's.
|
||||
cache_key = u':'.join([self.fragment_name] + [urlquote(resolve_variable(var, context)) for var in self.vary_on])
|
||||
args = md5_constructor(u':'.join([urlquote(resolve_variable(var, context)) for var in self.vary_on]))
|
||||
cache_key = 'template.cache.%s.%s' % (self.fragment_name, args.hexdigest())
|
||||
value = cache.get(cache_key)
|
||||
if value is None:
|
||||
value = self.nodelist.render(context)
|
||||
|
@ -26,7 +26,7 @@ For a development environment -- if you just want to experiment with Django --
|
||||
you don't need to have a separate Web server installed; Django comes with its
|
||||
own lightweight development server. For a production environment, Django
|
||||
follows the WSGI_ spec, which means it can run on a variety of server
|
||||
platforms. See :ref:`Deplying Django <howto-deployment-index>` for some
|
||||
platforms. See :ref:`Deploying Django <howto-deployment-index>` for some
|
||||
popular alternatives. Also, the `server arrangements wiki page`_ contains
|
||||
details for several deployment strategies.
|
||||
|
||||
|
@ -51,8 +51,9 @@ If your project is not on your ``PYTHONPATH`` by default you can add::
|
||||
|
||||
sys.path.append('/usr/local/django')
|
||||
|
||||
just above the ``import`` line to place your project on the path. Remember to
|
||||
replace 'mysite.settings' with your correct settings file.
|
||||
just above the final ``import`` line to place your project on the path. Remember to
|
||||
replace 'mysite.settings' with your correct settings file, and '/usr/local/django'
|
||||
with your own project's location.
|
||||
|
||||
See the :ref:`Apache/mod_python documentation<howto-deployment-modpython>` for
|
||||
directions on serving static media, and the `mod_wsgi documentation`_ for an
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
.. _index:
|
||||
|
||||
====================
|
||||
@ -99,8 +100,11 @@ The view layer
|
||||
:ref:`Managing files <topics-files>` |
|
||||
:ref:`Custom storage <howto-custom-file-storage>`
|
||||
|
||||
* **Generic views:**
|
||||
:ref:`Overview<topics-generic-views>` |
|
||||
:ref:`Built-in generic views<ref-generic-views>`
|
||||
|
||||
* **Advanced:**
|
||||
:ref:`Generic views <ref-generic-views>` |
|
||||
:ref:`Generating CSV <howto-outputting-csv>` |
|
||||
:ref:`Generating PDF <howto-outputting-pdf>`
|
||||
|
||||
|
@ -130,11 +130,6 @@ TODO
|
||||
|
||||
The work is mostly done, but here's what's left, in rough order of priority.
|
||||
|
||||
* Fix up generic view docs: adapt Chapter 9 of the Django Book (consider
|
||||
this TODO item my permission and license) into
|
||||
``topics/generic-views.txt``; remove the intro material from
|
||||
``ref/generic-views.txt`` and just leave the function reference.
|
||||
|
||||
* Change the "Added/changed in development version" callouts to proper
|
||||
Sphinx ``.. versionadded::`` or ``.. versionchanged::`` directives.
|
||||
|
||||
|
@ -243,9 +243,9 @@ might look like:
|
||||
<h1>Articles for {{ year }}</h1>
|
||||
|
||||
{% for article in article_list %}
|
||||
<p>{{ article.headline }}</p>
|
||||
<p>By {{ article.reporter.full_name }}</p>
|
||||
<p>Published {{ article.pub_date|date:"F j, Y" }}</p>
|
||||
<p>{{ article.headline }}</p>
|
||||
<p>By {{ article.reporter.full_name }}</p>
|
||||
<p>Published {{ article.pub_date|date:"F j, Y" }}</p>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
|
@ -238,8 +238,8 @@ the admin page doesn't display choices.
|
||||
|
||||
Yet.
|
||||
|
||||
There are two ways to solve this problem. The first register ``Choice`` with the
|
||||
admin just as we did with ``Poll``. That's easy::
|
||||
There are two ways to solve this problem. The first is to register ``Choice``
|
||||
with the admin just as we did with ``Poll``. That's easy::
|
||||
|
||||
from mysite.polls.models import Choice
|
||||
|
||||
|
@ -71,7 +71,7 @@ For more on :class:`~django.http.HttpRequest` objects, see the
|
||||
:ref:`ref-request-response`. For more details on URLconfs, see the
|
||||
:ref:`topics-http-urls`.
|
||||
|
||||
When you ran ``python django-admin.py startproject mysite`` at the beginning of
|
||||
When you ran ``django-admin.py startproject mysite`` at the beginning of
|
||||
Tutorial 1, it created a default URLconf in ``mysite/urls.py``. It also
|
||||
automatically set your :setting:`ROOT_URLCONF` setting (in ``settings.py``) to
|
||||
point at that file::
|
||||
@ -82,6 +82,9 @@ Time for an example. Edit ``mysite/urls.py`` so it looks like this::
|
||||
|
||||
from django.conf.urls.defaults import *
|
||||
|
||||
from django.contrib import admin
|
||||
admin.autodiscover()
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^polls/$', 'mysite.polls.views.index'),
|
||||
(r'^polls/(?P<poll_id>\d+)/$', 'mysite.polls.views.detail'),
|
||||
@ -95,8 +98,7 @@ This is worth a review. When somebody requests a page from your Web site -- say,
|
||||
the :setting:`ROOT_URLCONF` setting. It finds the variable named ``urlpatterns``
|
||||
and traverses the regular expressions in order. When it finds a regular
|
||||
expression that matches -- ``r'^polls/(?P<poll_id>\d+)/$'`` -- it loads the
|
||||
associated Python package/module: ``mysite.polls.views.detail``. That
|
||||
corresponds to the function ``detail()`` in ``mysite/polls/views.py``. Finally,
|
||||
function ``detail()`` from ``mysite/polls/views.py``. Finally,
|
||||
it calls that ``detail()`` function like so::
|
||||
|
||||
detail(request=<HttpRequest object>, poll_id='23')
|
||||
@ -465,7 +467,10 @@ Copy the file ``mysite/urls.py`` to ``mysite/polls/urls.py``. Then, change
|
||||
``mysite/urls.py`` to remove the poll-specific URLs and insert an
|
||||
:func:`~django.conf.urls.defaults.include`::
|
||||
|
||||
(r'^polls/', include('mysite.polls.urls')),
|
||||
...
|
||||
urlpatterns = patterns('',
|
||||
(r'^polls/', include('mysite.polls.urls')),
|
||||
...
|
||||
|
||||
:func:`~django.conf.urls.defaults.include`, simply, references another URLconf.
|
||||
Note that the regular expression doesn't have a ``$`` (end-of-string match
|
||||
@ -483,7 +488,8 @@ Here's what happens if a user goes to "/polls/34/" in this system:
|
||||
further processing.
|
||||
|
||||
Now that we've decoupled that, we need to decouple the 'mysite.polls.urls'
|
||||
URLconf by removing the leading "polls/" from each line::
|
||||
URLconf by removing the leading "polls/" from each line, and removing the
|
||||
lines registering the admin site::
|
||||
|
||||
urlpatterns = patterns('mysite.polls.views',
|
||||
(r'^$', 'index'),
|
||||
|
@ -347,7 +347,7 @@ A few special cases to note about ``list_display``:
|
||||
birthday = models.DateField()
|
||||
|
||||
def born_in_fifties(self):
|
||||
return self.birthday.strftime('%Y')[:3] == 5
|
||||
return self.birthday.strftime('%Y')[:3] == '195'
|
||||
born_in_fifties.boolean = True
|
||||
|
||||
class PersonAdmin(admin.ModelAdmin):
|
||||
@ -667,6 +667,43 @@ Controls where on the page the actions bar appears. By default, the admin
|
||||
changelist displays actions at the top of the page (``actions_on_top = True;
|
||||
actions_on_bottom = False``).
|
||||
|
||||
.. attribute:: ModelAdmin.change_list_template
|
||||
|
||||
Path to a custom template that will be used by the model objects "change list"
|
||||
view. Templates can override or extend base admin templates as described in
|
||||
`Overriding Admin Templates`_.
|
||||
|
||||
If you don't specify this attribute, a default template shipped with Django
|
||||
that provides the standard appearance is used.
|
||||
|
||||
.. attribute:: ModelAdmin.change_form_template
|
||||
|
||||
Path to a custom template that will be used by both the model object creation
|
||||
and change views. Templates can override or extend base admin templates as
|
||||
described in `Overriding Admin Templates`_.
|
||||
|
||||
If you don't specify this attribute, a default template shipped with Django
|
||||
that provides the standard appearance is used.
|
||||
|
||||
.. attribute:: ModelAdmin.object_history_template
|
||||
|
||||
Path to a custom template that will be used by the model object change history
|
||||
display view. Templates can override or extend base admin templates as
|
||||
described in `Overriding Admin Templates`_.
|
||||
|
||||
If you don't specify this attribute, a default template shipped with Django
|
||||
that provides the standard appearance is used.
|
||||
|
||||
.. attribute:: ModelAdmin.delete_confirmation_template
|
||||
|
||||
Path to a custom template that will be used by the view responsible of showing
|
||||
the confirmation page when the user decides to delete one or more model
|
||||
objects. Templates can override or extend base admin templates as described in
|
||||
`Overriding Admin Templates`_.
|
||||
|
||||
If you don't specify this attribute, a default template shipped with Django
|
||||
that provides the standard appearance is used.
|
||||
|
||||
``ModelAdmin`` methods
|
||||
----------------------
|
||||
|
||||
@ -762,6 +799,56 @@ return a subset of objects for this foreign key field based on the user::
|
||||
This uses the ``HttpRequest`` instance to filter the ``Car`` foreign key field
|
||||
to only the cars owned by the ``User`` instance.
|
||||
|
||||
Other methods
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. method:: ModelAdmin.add_view(self, request, form_url='', extra_context=None)
|
||||
|
||||
Django view for the model instance addition page. See note below.
|
||||
|
||||
.. method:: ModelAdmin.change_view(self, request, object_id, extra_context=None)
|
||||
|
||||
Django view for the model instance edition page. See note below.
|
||||
|
||||
.. method:: ModelAdmin.changelist_view(self, request, extra_context=None)
|
||||
|
||||
Django view for the model instances change list/actions page. See note below.
|
||||
|
||||
.. method:: ModelAdmin.delete_view(self, request, object_id, extra_context=None)
|
||||
|
||||
Django view for the model instance(s) deletion confirmation page. See note below.
|
||||
|
||||
.. method:: ModelAdmin.history_view(self, request, object_id, extra_context=None)
|
||||
|
||||
Django view for the page that shows the modification history for a given model
|
||||
instance.
|
||||
|
||||
Unlike the hook-type ``ModelAdmin`` methods detailed in the previous section,
|
||||
these five methods are in reality designed to be invoked as Django views from
|
||||
the admin application URL dispatching handler to render the pages that deal
|
||||
with model instances CRUD operations. As a result, completely overriding these
|
||||
methods will significantly change the behavior of the admin application.
|
||||
|
||||
One comon reason for overriding these methods is to augment the context data
|
||||
that is provided to the template that renders the view. In the following
|
||||
example, the change view is overridden so that the rendered template is
|
||||
provided some extra mapping data that would not otherwise be available::
|
||||
|
||||
class MyModelAdmin(admin.ModelAdmin):
|
||||
|
||||
# A template for a very customized change view:
|
||||
change_form_template = 'admin/myapp/extras/openstreetmap_change_form.html'
|
||||
|
||||
def get_osm_info(self):
|
||||
# ...
|
||||
|
||||
def change_view(self, request, object_id, extra_context=None):
|
||||
my_context = {
|
||||
'osm_data': self.get_osm_info(),
|
||||
}
|
||||
return super(MyModelAdmin, self).change_view(request, object_id,
|
||||
extra_context=my_context))
|
||||
|
||||
``ModelAdmin`` media definitions
|
||||
--------------------------------
|
||||
|
||||
@ -783,7 +870,7 @@ Adding custom validation to the admin
|
||||
-------------------------------------
|
||||
|
||||
Adding custom validation of data in the admin is quite easy. The automatic admin
|
||||
interfaces reuses :mod:`django.forms`, and the ``ModelAdmin`` class gives you
|
||||
interface reuses :mod:`django.forms`, and the ``ModelAdmin`` class gives you
|
||||
the ability define your own form::
|
||||
|
||||
class ArticleAdmin(admin.ModelAdmin):
|
||||
@ -803,7 +890,9 @@ any field::
|
||||
|
||||
It is important you use a ``ModelForm`` here otherwise things can break. See the
|
||||
:ref:`forms <ref-forms-index>` documentation on :ref:`custom validation
|
||||
<ref-forms-validation>` for more information.
|
||||
<ref-forms-validation>` and, more specifically, the
|
||||
:ref:`model form validation notes <overriding-modelform-clean-method>` for more
|
||||
information.
|
||||
|
||||
.. _admin-inlines:
|
||||
|
||||
@ -1106,7 +1195,7 @@ directory, our link would appear on every model's change form.
|
||||
Templates which may be overridden per app or model
|
||||
--------------------------------------------------
|
||||
|
||||
Not every template in ``contrib\admin\templates\admin`` may be overridden per
|
||||
Not every template in ``contrib/admin/templates/admin`` may be overridden per
|
||||
app or per model. The following can:
|
||||
|
||||
* ``app_index.html``
|
||||
@ -1131,8 +1220,8 @@ Root and login templates
|
||||
------------------------
|
||||
|
||||
If you wish to change the index or login templates, you are better off creating
|
||||
your own ``AdminSite`` instance (see below), and changing the ``index_template``
|
||||
or ``login_template`` properties.
|
||||
your own ``AdminSite`` instance (see below), and changing the :attr:`AdminSite.index_template`
|
||||
or :attr:`AdminSite.login_template` properties.
|
||||
|
||||
``AdminSite`` objects
|
||||
=====================
|
||||
@ -1151,6 +1240,21 @@ or add anything you like. Then, simply create an instance of your
|
||||
Python class), and register your models and ``ModelAdmin`` subclasses
|
||||
with it instead of using the default.
|
||||
|
||||
``AdminSite`` attributes
|
||||
------------------------
|
||||
|
||||
.. attribute:: AdminSite.index_template
|
||||
|
||||
Path to a custom template that will be used by the admin site main index view.
|
||||
Templates can override or extend base admin templates as described in
|
||||
`Overriding Admin Templates`_.
|
||||
|
||||
.. attribute:: AdminSite.login_template
|
||||
|
||||
Path to a custom template that will be used by the admin site login view.
|
||||
Templates can override or extend base admin templates as described in
|
||||
`Overriding Admin Templates`_.
|
||||
|
||||
Hooking ``AdminSite`` instances into your URLconf
|
||||
-------------------------------------------------
|
||||
|
||||
|
@ -601,3 +601,28 @@ some limitations on the usage of such LOB columns in general:
|
||||
Oracle. A workaround to this is to keep ``TextField`` columns out of any
|
||||
models that you foresee performing ``distinct()`` queries on, and to
|
||||
include the ``TextField`` in a related model instead.
|
||||
|
||||
.. _third-party-notes:
|
||||
|
||||
Using a 3rd-party database backend
|
||||
==================================
|
||||
|
||||
In addition to the officially supported databases, there are backends provided
|
||||
by 3rd parties that allow you to use other databases with Django:
|
||||
|
||||
* `Sybase SQL Anywhere`_
|
||||
* `IBM DB2`_
|
||||
* `Microsoft SQL Server 2005`_
|
||||
* Firebird_
|
||||
* ODBC_
|
||||
|
||||
The Django versions and ORM features supported by these unofficial backends
|
||||
vary considerably. Queries regarding the specific capabilities of these
|
||||
unofficial backends, along with any support queries, should be directed to
|
||||
the support channels provided by each 3rd party project.
|
||||
|
||||
.. _Sybase SQL Anywhere: http://code.google.com/p/sqlany-django/
|
||||
.. _IBM DB2: http://code.google.com/p/ibm-db/
|
||||
.. _Microsoft SQL Server 2005: http://code.google.com/p/django-mssql/
|
||||
.. _Firebird: http://code.google.com/p/django-firebird/
|
||||
.. _ODBC: http://code.google.com/p/django-pyodbc/
|
||||
|
@ -611,7 +611,11 @@ sqlsequencereset <appname appname ...>
|
||||
|
||||
Prints the SQL statements for resetting sequences for the given app name(s).
|
||||
|
||||
See http://simon.incutio.com/archive/2004/04/21/postgres for more information.
|
||||
Sequences are indexes used by some database engines to track the next available
|
||||
number for automatically incremented fields.
|
||||
|
||||
Use this command to generate SQL which will fix cases where a sequence is out
|
||||
of sync with its automatically incremented field data.
|
||||
|
||||
startapp <appname>
|
||||
------------------
|
||||
|
@ -9,67 +9,18 @@ again and again. In Django, the most common of these patterns have been
|
||||
abstracted into "generic views" that let you quickly provide common views of
|
||||
an object without actually needing to write any Python code.
|
||||
|
||||
Django's generic views contain the following:
|
||||
A general introduction to generic views can be found in the :ref:`topic guide
|
||||
<topics-generic-views>`.
|
||||
|
||||
* A set of views for doing list/detail interfaces.
|
||||
|
||||
* A set of views for year/month/day archive pages and associated
|
||||
detail and "latest" pages (for example, the Django weblog's year_,
|
||||
month_, day_, detail_, and latest_ pages).
|
||||
|
||||
* A set of views for creating, editing, and deleting objects.
|
||||
|
||||
.. _year: http://www.djangoproject.com/weblog/2005/
|
||||
.. _month: http://www.djangoproject.com/weblog/2005/jul/
|
||||
.. _day: http://www.djangoproject.com/weblog/2005/jul/20/
|
||||
.. _detail: http://www.djangoproject.com/weblog/2005/jul/20/autoreload/
|
||||
.. _latest: http://www.djangoproject.com/weblog/
|
||||
|
||||
All of these views are used by creating configuration dictionaries in
|
||||
your URLconf files and passing those dictionaries as the third member of the
|
||||
URLconf tuple for a given pattern. For example, here's the URLconf for the
|
||||
simple weblog app that drives the blog on djangoproject.com::
|
||||
|
||||
from django.conf.urls.defaults import *
|
||||
from django_website.apps.blog.models import Entry
|
||||
|
||||
info_dict = {
|
||||
'queryset': Entry.objects.all(),
|
||||
'date_field': 'pub_date',
|
||||
}
|
||||
|
||||
urlpatterns = patterns('django.views.generic.date_based',
|
||||
(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\w{1,2})/(?P<slug>[-\w]+)/$', 'object_detail', info_dict),
|
||||
(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\w{1,2})/$', 'archive_day', info_dict),
|
||||
(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$', 'archive_month', info_dict),
|
||||
(r'^(?P<year>\d{4})/$', 'archive_year', info_dict),
|
||||
(r'^$', 'archive_index', info_dict),
|
||||
)
|
||||
|
||||
As you can see, this URLconf defines a few options in ``info_dict``.
|
||||
``'queryset'`` gives the generic view a ``QuerySet`` of objects to use (in this
|
||||
case, all of the ``Entry`` objects) and tells the generic view which model is
|
||||
being used.
|
||||
|
||||
Documentation of each generic view follows, along with a list of all keyword
|
||||
arguments that a generic view expects. Remember that as in the example above,
|
||||
arguments may either come from the URL pattern (as ``month``, ``day``,
|
||||
``year``, etc. do above) or from the additional-information dictionary (as for
|
||||
``queryset``, ``date_field``, etc.).
|
||||
This reference contains details of Django's built-in generic views, along with
|
||||
a list of all keyword arguments that a generic view expects. Remember that
|
||||
arguments may either come from the URL pattern or from the ``extra_context``
|
||||
additional-information dictionary.
|
||||
|
||||
Most generic views require the ``queryset`` key, which is a ``QuerySet``
|
||||
instance; see :ref:`topics-db-queries` for more information about ``QuerySet``
|
||||
objects.
|
||||
|
||||
Most views also take an optional ``extra_context`` dictionary that you can use
|
||||
to pass any auxiliary information you wish to the view. The values in the
|
||||
``extra_context`` dictionary can be either functions (or other callables) or
|
||||
other objects. Functions are evaluated just before they are passed to the
|
||||
template. However, note that QuerySets retrieve and cache their data when they
|
||||
are first evaluated, so if you want to pass in a QuerySet via
|
||||
``extra_context`` that is always fresh you need to wrap it in a function or
|
||||
lambda that returns the QuerySet.
|
||||
|
||||
"Simple" generic views
|
||||
======================
|
||||
|
||||
@ -1137,3 +1088,4 @@ In addition to ``extra_context``, the template's context will be:
|
||||
variable's name depends on the ``template_object_name`` parameter, which
|
||||
is ``'object'`` by default. If ``template_object_name`` is ``'foo'``,
|
||||
this variable's name will be ``foo``.
|
||||
|
||||
|
@ -20,3 +20,4 @@ API Reference
|
||||
signals
|
||||
templates/index
|
||||
unicode
|
||||
|
||||
|
@ -35,7 +35,7 @@ You can evaluate a ``QuerySet`` in the following ways:
|
||||
|
||||
* **Slicing.** As explained in :ref:`limiting-querysets`, a ``QuerySet`` can
|
||||
be sliced, using Python's array-slicing syntax. Usually slicing a
|
||||
``QuerySet`` returns another (unevaluated ) ``QuerySet``, but Django will
|
||||
``QuerySet`` returns another (unevaluated) ``QuerySet``, but Django will
|
||||
execute the database query if you use the "step" parameter of slice
|
||||
syntax.
|
||||
|
||||
@ -616,6 +616,8 @@ call, since they are conflicting options.
|
||||
Both the ``depth`` argument and the ability to specify field names in the call
|
||||
to ``select_related()`` are new in Django version 1.0.
|
||||
|
||||
.. _extra:
|
||||
|
||||
``extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -330,7 +330,7 @@ isn't manually specified. Used with ``DEFAULT_CHARSET`` to construct the
|
||||
DEFAULT_FILE_STORAGE
|
||||
--------------------
|
||||
|
||||
Default: ``django.core.files.storage.FileSystemStorage``
|
||||
Default: ``'django.core.files.storage.FileSystemStorage'``
|
||||
|
||||
Default file storage class to be used for any file-related operations that don't
|
||||
specify a particular storage system. See :ref:`topics-files`.
|
||||
|
@ -677,7 +677,7 @@ load_data::
|
||||
management.call_command('flush', verbosity=0, interactive=False)
|
||||
management.call_command('loaddata', 'test_data', verbosity=0)
|
||||
|
||||
Subcommands must now preceed options
|
||||
Subcommands must now precede options
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``django-admin.py`` and ``manage.py`` now require subcommands to precede
|
||||
|
@ -945,11 +945,15 @@ in the :ref:`related objects reference <ref-models-relations>`.
|
||||
Removes all objects from the related object set.
|
||||
|
||||
To assign the members of a related set in one fell swoop, just assign to it
|
||||
from any iterable object. Example::
|
||||
from any iterable object. The iterable can contain object instances, or just
|
||||
a list of primary key values. For example::
|
||||
|
||||
b = Blog.objects.get(id=1)
|
||||
b.entry_set = [e1, e2]
|
||||
|
||||
In this example, ``e1`` and ``e2`` can be full Entry instances, or integer
|
||||
primary key values.
|
||||
|
||||
If the ``clear()`` method is available, any pre-existing objects will be
|
||||
removed from the ``entry_set`` before all objects in the iterable (in this
|
||||
case, a list) are added to the set. If the ``clear()`` method is *not*
|
||||
|
@ -29,6 +29,45 @@ is required. For example::
|
||||
|
||||
return row
|
||||
|
||||
.. _transactions-and-raw-sql:
|
||||
|
||||
Transactions and raw SQL
|
||||
------------------------
|
||||
If you are using transaction decorators (such as ``commit_on_success``) to
|
||||
wrap your views and provide transaction control, you don't have to make a
|
||||
manual call to ``transaction.commit_unless_managed()`` -- you can manually
|
||||
commit if you want to, but you aren't required to, since the decorator will
|
||||
commit for you. However, if you don't manually commit your changes, you will
|
||||
need to manually mark the transaction as dirty, using
|
||||
``transaction.set_dirty()``::
|
||||
|
||||
@commit_on_success
|
||||
def my_custom_sql_view(request, value):
|
||||
from django.db import connection, transaction
|
||||
cursor = connection.cursor()
|
||||
|
||||
# Data modifying operation
|
||||
cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [value])
|
||||
|
||||
# Since we modified data, mark the transaction as dirty
|
||||
transaction.set_dirty()
|
||||
|
||||
# Data retrieval operation. This doesn't dirty the transaction,
|
||||
# so no call to set_dirty() is required.
|
||||
cursor.execute("SELECT foo FROM bar WHERE baz = %s", [value])
|
||||
row = cursor.fetchone()
|
||||
|
||||
return render_to_response('template.html', {'row': row})
|
||||
|
||||
The call to ``set_dirty()`` is made automatically when you use the Django ORM
|
||||
to make data modifying database calls. However, when you use raw SQL, Django
|
||||
has no way of knowing if your SQL modifies data or not. The manual call to
|
||||
``set_dirty()`` ensures that Django knows that there are modifications that
|
||||
must be committed.
|
||||
|
||||
Connections and cursors
|
||||
-----------------------
|
||||
|
||||
``connection`` and ``cursor`` mostly implement the standard `Python DB-API`_
|
||||
(except when it comes to :ref:`transaction handling <topics-db-transactions>`).
|
||||
If you're not familiar with the Python DB-API, note that the SQL statement in
|
||||
@ -39,9 +78,12 @@ necessary. (Also note that Django expects the ``"%s"`` placeholder, *not* the
|
||||
``"?"`` placeholder, which is used by the SQLite Python bindings. This is for
|
||||
the sake of consistency and sanity.)
|
||||
|
||||
An easier option?
|
||||
-----------------
|
||||
|
||||
A final note: If all you want to do is a custom ``WHERE`` clause, you can just
|
||||
use the ``where``, ``tables`` and ``params`` arguments to the standard lookup
|
||||
API.
|
||||
use the ``where``, ``tables`` and ``params`` arguments to the
|
||||
:ref:`extra clause <extra>` in the standard queryset API.
|
||||
|
||||
.. _Python DB-API: http://www.python.org/peps/pep-0249.html
|
||||
|
||||
|
@ -397,16 +397,26 @@ to be rendered first, we could specify the following ``ModelForm``::
|
||||
... model = Book
|
||||
... fields = ['title', 'author']
|
||||
|
||||
.. _overriding-modelform-clean-method:
|
||||
|
||||
Overriding the clean() method
|
||||
-----------------------------
|
||||
|
||||
You can override the ``clean()`` method on a model form to provide additional
|
||||
validation in the same way you can on a normal form. However, by default the
|
||||
``clean()`` method validates the uniqueness of fields that are marked as
|
||||
``unique``, ``unique_together`` or ``unique_for_date|month|year`` on the model.
|
||||
Therefore, if you would like to override the ``clean()`` method and maintain the
|
||||
default validation, you must call the parent class's ``clean()`` method.
|
||||
validation in the same way you can on a normal form.
|
||||
|
||||
In this regard, model forms have two specific characteristics when compared to
|
||||
forms:
|
||||
|
||||
By default the ``clean()`` method validates the uniqueness of fields that are
|
||||
marked as ``unique``, ``unique_together`` or ``unique_for_date|month|year`` on
|
||||
the model. Therefore, if you would like to override the ``clean()`` method and
|
||||
maintain the default validation, you must call the parent class's ``clean()``
|
||||
method.
|
||||
|
||||
Also, a model form instance bound to a model object will contain a
|
||||
``self.instance`` attribute that gives model form methods access to that
|
||||
specific model instance.
|
||||
|
||||
Form inheritance
|
||||
----------------
|
||||
@ -611,7 +621,7 @@ Just like with ``ModelForms``, by default the ``clean()`` method of a
|
||||
the unique constraints on your model (either ``unique``, ``unique_together`` or
|
||||
``unique_for_date|month|year``). If you want to overide the ``clean()`` method
|
||||
on a ``model_formset`` and maintain this validation, you must call the parent
|
||||
classes ``clean`` method::
|
||||
class's ``clean`` method::
|
||||
|
||||
class MyModelFormSet(BaseModelFormSet):
|
||||
def clean(self):
|
||||
|
503
docs/topics/generic-views.txt
Normal file
503
docs/topics/generic-views.txt
Normal file
@ -0,0 +1,503 @@
|
||||
.. _topics-generic-views:
|
||||
|
||||
=============
|
||||
Generic views
|
||||
=============
|
||||
|
||||
Writing Web applications can be monotonous, because we repeat certain patterns
|
||||
again and again. Django tries to take away some of that monotony at the model
|
||||
and template layers, but Web developers also experience this boredom at the view
|
||||
level.
|
||||
|
||||
Django's *generic views* were developed to ease that pain. They take certain
|
||||
common idioms and patterns found in view development and abstract them so that
|
||||
you can quickly write common views of data without having to write too much
|
||||
code.
|
||||
|
||||
We can recognize certain common tasks, like displaying a list of objects, and
|
||||
write code that displays a list of *any* object. Then the model in question can
|
||||
be passed as an extra argument to the URLconf.
|
||||
|
||||
Django ships with generic views to do the following:
|
||||
|
||||
* Perform common "simple" tasks: redirect to a different page and
|
||||
render a given template.
|
||||
|
||||
* Display list and detail pages for a single object. If we were creating an
|
||||
application to manage conferences then a ``talk_list`` view and a
|
||||
``registered_user_list`` view would be examples of list views. A single
|
||||
talk page is an example of what we call a "detail" view.
|
||||
|
||||
* Present date-based objects in year/month/day archive pages,
|
||||
associated detail, and "latest" pages. The Django Weblog's
|
||||
(http://www.djangoproject.com/weblog/) year, month, and
|
||||
day archives are built with these, as would be a typical
|
||||
newspaper's archives.
|
||||
|
||||
* Allow users to create, update, and delete objects -- with or
|
||||
without authorization.
|
||||
|
||||
Taken together, these views provide easy interfaces to perform the most common
|
||||
tasks developers encounter.
|
||||
|
||||
Using generic views
|
||||
===================
|
||||
|
||||
All of these views are used by creating configuration dictionaries in
|
||||
your URLconf files and passing those dictionaries as the third member of the
|
||||
URLconf tuple for a given pattern.
|
||||
|
||||
For example, here's a simple URLconf you could use to present a static "about"
|
||||
page::
|
||||
|
||||
from django.conf.urls.defaults import *
|
||||
from django.views.generic.simple import direct_to_template
|
||||
|
||||
urlpatterns = patterns('',
|
||||
('^about/$', direct_to_template, {
|
||||
'template': 'about.html'
|
||||
})
|
||||
)
|
||||
|
||||
Though this might seem a bit "magical" at first glance -- look, a view with no
|
||||
code! --, actually the ``direct_to_template`` view simply grabs information from
|
||||
the extra-parameters dictionary and uses that information when rendering the
|
||||
view.
|
||||
|
||||
Because this generic view -- and all the others -- is a regular view functions
|
||||
like any other, we can reuse it inside our own views. As an example, let's
|
||||
extend our "about" example to map URLs of the form ``/about/<whatever>/`` to
|
||||
statically rendered ``about/<whatever>.html``. We'll do this by first modifying
|
||||
the URLconf to point to a view function:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
from django.conf.urls.defaults import *
|
||||
from django.views.generic.simple import direct_to_template
|
||||
**from mysite.books.views import about_pages**
|
||||
|
||||
urlpatterns = patterns('',
|
||||
('^about/$', direct_to_template, {
|
||||
'template': 'about.html'
|
||||
}),
|
||||
**('^about/(\w+)/$', about_pages),**
|
||||
)
|
||||
|
||||
Next, we'll write the ``about_pages`` view::
|
||||
|
||||
from django.http import Http404
|
||||
from django.template import TemplateDoesNotExist
|
||||
from django.views.generic.simple import direct_to_template
|
||||
|
||||
def about_pages(request, page):
|
||||
try:
|
||||
return direct_to_template(request, template="about/%s.html" % page)
|
||||
except TemplateDoesNotExist:
|
||||
raise Http404()
|
||||
|
||||
Here we're treating ``direct_to_template`` like any other function. Since it
|
||||
returns an ``HttpResponse``, we can simply return it as-is. The only slightly
|
||||
tricky business here is dealing with missing templates. We don't want a
|
||||
nonexistent template to cause a server error, so we catch
|
||||
``TemplateDoesNotExist`` exceptions and return 404 errors instead.
|
||||
|
||||
.. admonition:: Is there a security vulnerability here?
|
||||
|
||||
Sharp-eyed readers may have noticed a possible security hole: we're
|
||||
constructing the template name using interpolated content from the browser
|
||||
(``template="about/%s.html" % page``). At first glance, this looks like a
|
||||
classic *directory traversal* vulnerability. But is it really?
|
||||
|
||||
Not exactly. Yes, a maliciously crafted value of ``page`` could cause
|
||||
directory traversal, but although ``page`` *is* taken from the request URL,
|
||||
not every value will be accepted. The key is in the URLconf: we're using
|
||||
the regular expression ``\w+`` to match the ``page`` part of the URL, and
|
||||
``\w`` only accepts letters and numbers. Thus, any malicious characters
|
||||
(dots and slashes, here) will be rejected by the URL resolver before they
|
||||
reach the view itself.
|
||||
|
||||
Generic views of objects
|
||||
========================
|
||||
|
||||
The ``direct_to_template`` certainly is useful, but Django's generic views
|
||||
really shine when it comes to presenting views on your database content. Because
|
||||
it's such a common task, Django comes with a handful of built-in generic views
|
||||
that make generating list and detail views of objects incredibly easy.
|
||||
|
||||
Let's take a look at one of these generic views: the "object list" view. We'll
|
||||
be using these models::
|
||||
|
||||
# models.py
|
||||
from django.db import models
|
||||
|
||||
class Publisher(models.Model):
|
||||
name = models.CharField(max_length=30)
|
||||
address = models.CharField(max_length=50)
|
||||
city = models.CharField(max_length=60)
|
||||
state_province = models.CharField(max_length=30)
|
||||
country = models.CharField(max_length=50)
|
||||
website = models.URLField()
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
ordering = ["-name"]
|
||||
|
||||
class Book(models.Model):
|
||||
title = models.CharField(max_length=100)
|
||||
authors = models.ManyToManyField('Author')
|
||||
publisher = models.ForeignKey(Publisher)
|
||||
publication_date = models.DateField()
|
||||
|
||||
To build a list page of all books, we'd use a URLconf along these lines::
|
||||
|
||||
from django.conf.urls.defaults import *
|
||||
from django.views.generic import list_detail
|
||||
from mysite.books.models import Publisher
|
||||
|
||||
publisher_info = {
|
||||
"queryset" : Publisher.objects.all(),
|
||||
}
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^publishers/$', list_detail.object_list, publisher_info)
|
||||
)
|
||||
|
||||
That's all the Python code we need to write. We still need to write a template,
|
||||
however. We could explicitly tell the ``object_list`` view which template to use
|
||||
by including a ``template_name`` key in the extra arguments dictionary, but in
|
||||
the absence of an explicit template Django will infer one from the object's
|
||||
name. In this case, the inferred template will be
|
||||
``"books/publisher_list.html"`` -- the "books" part comes from the name of the
|
||||
app that defines the model, while the "publisher" bit is just the lowercased
|
||||
version of the model's name.
|
||||
|
||||
.. highlightlang:: html+django
|
||||
|
||||
This template will be rendered against a context containing a variable called
|
||||
``object_list`` that contains all the book objects. A very simple template
|
||||
might look like the following::
|
||||
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Publishers</h2>
|
||||
<ul>
|
||||
{% for publisher in object_list %}
|
||||
<li>{{ publisher.name }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
||||
That's really all there is to it. All the cool features of generic views come
|
||||
from changing the "info" dictionary passed to the generic view. The
|
||||
:ref:`generic views reference<ref-generic-views>` documents all the generic
|
||||
views and all their options in detail; the rest of this document will consider
|
||||
some of the common ways you might customize and extend generic views.
|
||||
|
||||
Extending generic views
|
||||
=======================
|
||||
|
||||
.. highlightlang:: python
|
||||
|
||||
There's no question that using generic views can speed up development
|
||||
substantially. In most projects, however, there comes a moment when the
|
||||
generic views no longer suffice. Indeed, the most common question asked by new
|
||||
Django developers is how to make generic views handle a wider array of
|
||||
situations.
|
||||
|
||||
Luckily, in nearly every one of these cases, there are ways to simply extend
|
||||
generic views to handle a larger array of use cases. These situations usually
|
||||
fall into a handful of patterns dealt with in the sections that follow.
|
||||
|
||||
Making "friendly" template contexts
|
||||
-----------------------------------
|
||||
|
||||
You might have noticed that our sample publisher list template stores all the
|
||||
books in a variable named ``object_list``. While this works just fine, it isn't
|
||||
all that "friendly" to template authors: they have to "just know" that they're
|
||||
dealing with books here. A better name for that variable would be
|
||||
``publisher_list``; that variable's content is pretty obvious.
|
||||
|
||||
We can change the name of that variable easily with the ``template_object_name``
|
||||
argument:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
publisher_info = {
|
||||
"queryset" : Publisher.objects.all(),
|
||||
**"template_object_name" : "publisher",**
|
||||
}
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^publishers/$', list_detail.object_list, publisher_info)
|
||||
)
|
||||
|
||||
Providing a useful ``template_object_name`` is always a good idea. Your
|
||||
coworkers who design templates will thank you.
|
||||
|
||||
Adding extra context
|
||||
--------------------
|
||||
|
||||
Often you simply need to present some extra information beyond that provided by
|
||||
the generic view. For example, think of showing a list of all the other
|
||||
publishers on each publisher detail page. The ``object_detail`` generic view
|
||||
provides the publisher to the context, but it seems there's no way to get a list
|
||||
of *all* publishers in that template.
|
||||
|
||||
But there is: all generic views take an extra optional parameter,
|
||||
``extra_context``. This is a dictionary of extra objects that will be added to
|
||||
the template's context. So, to provide the list of all publishers on the detail
|
||||
detail view, we'd use an info dict like this:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
from mysite.books.models import Publisher, **Book**
|
||||
|
||||
publisher_info = {
|
||||
"queryset" : Publisher.objects.all(),
|
||||
"template_object_name" : "publisher",
|
||||
**"extra_context" : {"book_list" : Book.objects.all()}**
|
||||
}
|
||||
|
||||
This would populate a ``{{ book_list }}`` variable in the template context.
|
||||
This pattern can be used to pass any information down into the template for the
|
||||
generic view. It's very handy.
|
||||
|
||||
However, there's actually a subtle bug here -- can you spot it?
|
||||
|
||||
The problem has to do with when the queries in ``extra_context`` are evaluated.
|
||||
Because this example puts ``Publisher.objects.all()`` in the URLconf, it will
|
||||
be evaluated only once (when the URLconf is first loaded). Once you add or
|
||||
remove publishers, you'll notice that the generic view doesn't reflect those
|
||||
changes until you reload the Web server (see :ref:`caching-and-querysets`
|
||||
for more information about when QuerySets are cached and evaluated).
|
||||
|
||||
.. note::
|
||||
|
||||
This problem doesn't apply to the ``queryset`` generic view argument. Since
|
||||
Django knows that particular QuerySet should *never* be cached, the generic
|
||||
view takes care of clearing the cache when each view is rendered.
|
||||
|
||||
The solution is to use a callback in ``extra_context`` instead of a value. Any
|
||||
callable (i.e., a function) that's passed to ``extra_context`` will be evaluated
|
||||
when the view is rendered (instead of only once). You could do this with an
|
||||
explicitly defined function:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
def get_books():
|
||||
return Book.objects.all()
|
||||
|
||||
publisher_info = {
|
||||
"queryset" : Publisher.objects.all(),
|
||||
"template_object_name" : "publisher",
|
||||
"extra_context" : **{"book_list" : get_books}**
|
||||
}
|
||||
|
||||
or you could use a less obvious but shorter version that relies on the fact that
|
||||
``Book.objects.all`` is itself a callable:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
publisher_info = {
|
||||
"queryset" : Publisher.objects.all(),
|
||||
"template_object_name" : "publisher",
|
||||
"extra_context" : **{"book_list" : Book.objects.all}**
|
||||
}
|
||||
|
||||
Notice the lack of parentheses after ``Book.objects.all``; this references
|
||||
the function without actually calling it (which the generic view will do later).
|
||||
|
||||
Viewing subsets of objects
|
||||
--------------------------
|
||||
|
||||
Now let's take a closer look at this ``queryset`` key we've been using all
|
||||
along. Most generic views take one of these ``queryset`` arguments -- it's how
|
||||
the view knows which set of objects to display (see :ref:`topics-db-queries` for
|
||||
more information about ``QuerySet`` objects, and see the
|
||||
:ref:`generic views reference<ref-generic-views>` for the complete details).
|
||||
|
||||
To pick a simple example, we might want to order a list of books by
|
||||
publication date, with the most recent first:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
book_info = {
|
||||
"queryset" : Book.objects.all().order_by("-publication_date"),
|
||||
}
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^publishers/$', list_detail.object_list, publisher_info),
|
||||
**(r'^books/$', list_detail.object_list, book_info),**
|
||||
)
|
||||
|
||||
|
||||
That's a pretty simple example, but it illustrates the idea nicely. Of course,
|
||||
you'll usually want to do more than just reorder objects. If you want to
|
||||
present a list of books by a particular publisher, you can use the same
|
||||
technique:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
**acme_books = {**
|
||||
**"queryset": Book.objects.filter(publisher__name="Acme Publishing"),**
|
||||
**"template_name" : "books/acme_list.html"**
|
||||
**}**
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^publishers/$', list_detail.object_list, publisher_info),
|
||||
**(r'^books/acme/$', list_detail.object_list, acme_books),**
|
||||
)
|
||||
|
||||
Notice that along with a filtered ``queryset``, we're also using a custom
|
||||
template name. If we didn't, the generic view would use the same template as the
|
||||
"vanilla" object list, which might not be what we want.
|
||||
|
||||
Also notice that this isn't a very elegant way of doing publisher-specific
|
||||
books. If we want to add another publisher page, we'd need another handful of
|
||||
lines in the URLconf, and more than a few publishers would get unreasonable.
|
||||
We'll deal with this problem in the next section.
|
||||
|
||||
.. note::
|
||||
|
||||
If you get a 404 when requesting ``/books/acme/``, check to ensure you
|
||||
actually have a Publisher with the name 'ACME Publishing'. Generic
|
||||
views have an ``allow_empty`` parameter for this case. See the
|
||||
:ref:`generic views reference<ref-generic-views>` for more details.
|
||||
|
||||
Complex filtering with wrapper functions
|
||||
----------------------------------------
|
||||
|
||||
Another common need is to filter down the objects given in a list page by some
|
||||
key in the URL. Earlier we hard-coded the publisher's name in the URLconf, but
|
||||
what if we wanted to write a view that displayed all the books by some arbitrary
|
||||
publisher? We can "wrap" the ``object_list`` generic view to avoid writing a lot
|
||||
of code by hand. As usual, we'll start by writing a URLconf:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
from mysite.books.views import books_by_publisher
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^publishers/$', list_detail.object_list, publisher_info),
|
||||
**(r'^books/(\w+)/$', books_by_publisher),**
|
||||
)
|
||||
|
||||
Next, we'll write the ``books_by_publisher`` view itself::
|
||||
|
||||
from django.http import Http404
|
||||
from django.views.generic import list_detail
|
||||
from mysite.books.models import Book, Publisher
|
||||
|
||||
def books_by_publisher(request, name):
|
||||
|
||||
# Look up the publisher (and raise a 404 if it can't be found).
|
||||
try:
|
||||
publisher = Publisher.objects.get(name__iexact=name)
|
||||
except Publisher.DoesNotExist:
|
||||
raise Http404
|
||||
|
||||
# Use the object_list view for the heavy lifting.
|
||||
return list_detail.object_list(
|
||||
request,
|
||||
queryset = Book.objects.filter(publisher=publisher),
|
||||
template_name = "books/books_by_publisher.html",
|
||||
template_object_name = "books",
|
||||
extra_context = {"publisher" : publisher}
|
||||
)
|
||||
|
||||
This works because there's really nothing special about generic views -- they're
|
||||
just Python functions. Like any view function, generic views expect a certain
|
||||
set of arguments and return ``HttpResponse`` objects. Thus, it's incredibly easy
|
||||
to wrap a small function around a generic view that does additional work before
|
||||
(or after; see the next section) handing things off to the generic view.
|
||||
|
||||
.. note::
|
||||
|
||||
Notice that in the preceding example we passed the current publisher being
|
||||
displayed in the ``extra_context``. This is usually a good idea in wrappers
|
||||
of this nature; it lets the template know which "parent" object is currently
|
||||
being browsed.
|
||||
|
||||
Performing extra work
|
||||
---------------------
|
||||
|
||||
The last common pattern we'll look at involves doing some extra work before
|
||||
or after calling the generic view.
|
||||
|
||||
Imagine we had a ``last_accessed`` field on our ``Author`` object that we were
|
||||
using to keep track of the last time anybody looked at that author::
|
||||
|
||||
# models.py
|
||||
|
||||
class Author(models.Model):
|
||||
salutation = models.CharField(max_length=10)
|
||||
first_name = models.CharField(max_length=30)
|
||||
last_name = models.CharField(max_length=40)
|
||||
email = models.EmailField()
|
||||
headshot = models.ImageField(upload_to='/tmp')
|
||||
last_accessed = models.DateTimeField()
|
||||
|
||||
The generic ``object_detail`` view, of course, wouldn't know anything about this
|
||||
field, but once again we could easily write a custom view to keep that field
|
||||
updated.
|
||||
|
||||
First, we'd need to add an author detail bit in the URLconf to point to a
|
||||
custom view:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
from mysite.books.views import author_detail
|
||||
|
||||
urlpatterns = patterns('',
|
||||
#...
|
||||
**(r'^authors/(?P<author_id>\d+)/$', author_detail),**
|
||||
)
|
||||
|
||||
Then we'd write our wrapper function::
|
||||
|
||||
import datetime
|
||||
from mysite.books.models import Author
|
||||
from django.views.generic import list_detail
|
||||
from django.shortcuts import get_object_or_404
|
||||
|
||||
def author_detail(request, author_id):
|
||||
# Look up the Author (and raise a 404 if she's not found)
|
||||
author = get_object_or_404(Author, pk=author_id)
|
||||
|
||||
# Record the last accessed date
|
||||
author.last_accessed = datetime.datetime.now()
|
||||
author.save()
|
||||
|
||||
# Show the detail page
|
||||
return list_detail.object_detail(
|
||||
request,
|
||||
queryset = Author.objects.all(),
|
||||
object_id = author_id,
|
||||
)
|
||||
|
||||
.. note::
|
||||
|
||||
This code won't actually work unless you create a
|
||||
``books/author_detail.html`` template.
|
||||
|
||||
We can use a similar idiom to alter the response returned by the generic view.
|
||||
If we wanted to provide a downloadable plain-text version of the list of
|
||||
authors, we could use a view like this::
|
||||
|
||||
def author_list_plaintext(request):
|
||||
response = list_detail.object_list(
|
||||
request,
|
||||
queryset = Author.objects.all(),
|
||||
mimetype = "text/plain",
|
||||
template_name = "books/author_list.txt"
|
||||
)
|
||||
response["Content-Disposition"] = "attachment; filename=authors.txt"
|
||||
return response
|
||||
|
||||
This works because the generic views return simple ``HttpResponse`` objects
|
||||
that can be treated like dictionaries to set HTTP headers. This
|
||||
``Content-Disposition`` business, by the way, instructs the browser to
|
||||
download and save the page instead of displaying it in the browser.
|
@ -107,15 +107,18 @@ middleware is always called on every response.
|
||||
``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is the
|
||||
:class:`~django.http. HttpResponse` object returned by a Django view.
|
||||
|
||||
``process_response()`` should return an :class:`~django.http. HttpResponse`
|
||||
``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`.
|
||||
|
||||
Remember that your middleware will not be called if another middleware object
|
||||
returns a response before you. But unlike ``process_request()`` and
|
||||
``process_view()``, 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.
|
||||
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:
|
||||
|
||||
|
@ -4,6 +4,9 @@
|
||||
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.
|
||||
|
@ -978,15 +978,17 @@ message files (``.po``). Translation work itself just involves editing existing
|
||||
files of this type, but if you want to create your own message files, or want to
|
||||
test or compile a changed message file, you will need the ``gettext`` utilities:
|
||||
|
||||
* Download the following zip files from
|
||||
http://sourceforge.net/projects/gettext
|
||||
* Download the following zip files from the GNOME servers
|
||||
http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/ or from one
|
||||
of its mirrors_
|
||||
|
||||
* ``gettext-runtime-X.bin.woe32.zip``
|
||||
* ``gettext-tools-X.bin.woe32.zip``
|
||||
* ``libiconv-X.bin.woe32.zip``
|
||||
* ``gettext-runtime-X.zip``
|
||||
* ``gettext-tools-X.zip``
|
||||
|
||||
* Extract the 3 files in the same folder (i.e. ``C:\Program
|
||||
Files\gettext-utils``)
|
||||
``X`` is the version number, we recomend using ``0.15`` or higher.
|
||||
|
||||
* Extract the contents of the ``bin\`` directories in both files to the
|
||||
same folder on your system (i.e. ``C:\Program Files\gettext-utils``)
|
||||
|
||||
* Update the system PATH:
|
||||
|
||||
@ -995,6 +997,8 @@ test or compile a changed message file, you will need the ``gettext`` utilities:
|
||||
* Add ``;C:\Program Files\gettext-utils\bin`` at the end of the
|
||||
``Variable value`` field
|
||||
|
||||
.. _mirrors: http://ftp.gnome.org/pub/GNOME/MIRRORS
|
||||
|
||||
You may also use ``gettext`` binaries you have obtained elsewhere, so long as
|
||||
the ``xgettext --version`` command works properly. Some version 0.14.4 binaries
|
||||
have been found to not support this command. Do not attempt to use Django
|
||||
|
@ -14,6 +14,7 @@ Introductions to all the key parts of Django you'll need to know:
|
||||
forms/index
|
||||
forms/modelforms
|
||||
templates
|
||||
generic-views
|
||||
files
|
||||
testing
|
||||
auth
|
||||
@ -25,3 +26,4 @@ Introductions to all the key parts of Django you'll need to know:
|
||||
serialization
|
||||
settings
|
||||
signals
|
||||
|
||||
|
@ -61,13 +61,27 @@ for each platform.
|
||||
Get your database running
|
||||
=========================
|
||||
|
||||
If you plan to use Django's database API functionality, you'll need to
|
||||
make sure a database server is running. Django works with PostgreSQL_,
|
||||
MySQL_, Oracle_ and SQLite_ (although SQLite doesn't require a separate server
|
||||
to be running).
|
||||
If you plan to use Django's database API functionality, you'll need to make
|
||||
sure a database server is running. Django supports many different database
|
||||
servers and is officially supported with PostgreSQL_, MySQL_, Oracle_ and
|
||||
SQLite_ (although SQLite doesn't require a separate server to be running).
|
||||
|
||||
Additionally, you'll need to make sure your Python database bindings are
|
||||
installed.
|
||||
In addition to the officially supported databases, there are backends provided
|
||||
by 3rd parties that allow you to use other databases with Django:
|
||||
|
||||
* `Sybase SQL Anywhere`_
|
||||
* `IBM DB2`_
|
||||
* `Microsoft SQL Server 2005`_
|
||||
* Firebird_
|
||||
* ODBC_
|
||||
|
||||
The Django versions and ORM features supported by these unofficial backends
|
||||
vary considerably. Queries regarding the specific capabilities of these
|
||||
unofficial backends, along with any support queries, should be directed to the
|
||||
support channels provided by each 3rd party project.
|
||||
|
||||
In addition to a database backend, you'll need to make sure your Python
|
||||
database bindings are installed.
|
||||
|
||||
* If you're using PostgreSQL, you'll need the psycopg_ package. Django supports
|
||||
both version 1 and 2. (When you configure Django's database layer, specify
|
||||
@ -89,6 +103,9 @@ installed.
|
||||
:ref:`Oracle backend <oracle-notes>` for important information
|
||||
regarding supported versions of both Oracle and ``cx_Oracle``.
|
||||
|
||||
* If you're using an unofficial 3rd party backend, please consult the
|
||||
documentation provided for any additional requirements.
|
||||
|
||||
If you plan to use Django's ``manage.py syncdb`` command to
|
||||
automatically create database tables for your models, you'll need to
|
||||
ensure that Django has permission to create and alter tables in the
|
||||
@ -111,7 +128,11 @@ Django will need permission to create a test database.
|
||||
.. _pysqlite: http://pysqlite.org/
|
||||
.. _cx_Oracle: http://cx-oracle.sourceforge.net/
|
||||
.. _Oracle: http://www.oracle.com/
|
||||
|
||||
.. _Sybase SQL Anywhere: http://code.google.com/p/sqlany-django/
|
||||
.. _IBM DB2: http://code.google.com/p/ibm-db/
|
||||
.. _Microsoft SQL Server 2005: http://code.google.com/p/django-mssql/
|
||||
.. _Firebird: http://code.google.com/p/django-firebird/
|
||||
.. _ODBC: http://code.google.com/p/django-pyodbc/
|
||||
.. _removing-old-versions-of-django:
|
||||
|
||||
Remove any old versions of Django
|
||||
|
@ -139,7 +139,7 @@ In the case of model tests, note that the test runner takes care of creating
|
||||
its own test database. That is, any test that accesses a database -- by
|
||||
creating and saving model instances, for example -- will not affect your
|
||||
production database. However, the database is not refreshed between doctests,
|
||||
so if your doctest requires a certain state you should consider flushin the
|
||||
so if your doctest requires a certain state you should consider flushing the
|
||||
database or loading a fixture. (See the section on fixtures, below, for more
|
||||
on this.) Note that to use this feature, the database user Django is connecting
|
||||
as must have ``CREATE DATABASE`` rights.
|
||||
@ -1042,7 +1042,7 @@ applications:
|
||||
Asserts that a ``Response`` instance produced the given ``status_code`` and
|
||||
that ``text`` does not appears in the content of the response.
|
||||
|
||||
.. method:: assertFormError(response, form, field, errors)
|
||||
.. method:: TestCase.assertFormError(response, form, field, errors)
|
||||
|
||||
Asserts that a field on a form raises the provided list of errors when
|
||||
rendered on the form.
|
||||
@ -1057,19 +1057,19 @@ applications:
|
||||
``errors`` is an error string, or a list of error strings, that are
|
||||
expected as a result of form validation.
|
||||
|
||||
.. method:: assertTemplateUsed(response, template_name)
|
||||
.. method:: TestCase.assertTemplateUsed(response, template_name)
|
||||
|
||||
Asserts that the template with the given name was used in rendering the
|
||||
response.
|
||||
|
||||
The name is a string such as ``'admin/index.html'``.
|
||||
|
||||
.. method:: assertTemplateNotUsed(response, template_name)
|
||||
.. method:: TestCase.assertTemplateNotUsed(response, template_name)
|
||||
|
||||
Asserts that the template with the given name was *not* used in rendering
|
||||
the response.
|
||||
|
||||
.. method:: assertRedirects(response, expected_url, status_code=302, target_status_code=200)
|
||||
.. method:: TestCase.assertRedirects(response, expected_url, status_code=302, target_status_code=200)
|
||||
|
||||
Asserts that the response return a ``status_code`` redirect status, it
|
||||
redirected to ``expected_url`` (including any GET data), and the final
|
||||
|
@ -629,7 +629,7 @@ class Templates(unittest.TestCase):
|
||||
|
||||
# Logically the same as above, just written with explicit
|
||||
# ifchanged for the day.
|
||||
'ifchanged-param04': ('{% for d in days %}{% ifchanged d.day %}{{ d.day }}{% endifchanged %}{% for h in d.hours %}{% ifchanged d.day h %}{{ h }}{% endifchanged %}{% endfor %}{% endfor %}', {'days':[{'day':1, 'hours':[1,2,3]},{'day':2, 'hours':[3]},] }, '112323'),
|
||||
'ifchanged-param05': ('{% for d in days %}{% ifchanged d.day %}{{ d.day }}{% endifchanged %}{% for h in d.hours %}{% ifchanged d.day h %}{{ h }}{% endifchanged %}{% endfor %}{% endfor %}', {'days':[{'day':1, 'hours':[1,2,3]},{'day':2, 'hours':[3]},] }, '112323'),
|
||||
|
||||
# Test the else clause of ifchanged.
|
||||
'ifchanged-else01': ('{% for id in ids %}{{ id }}{% ifchanged id %}-first{% else %}-other{% endifchanged %},{% endfor %}', {'ids': [1,1,2,2,2,3]}, '1-first,1-other,2-first,2-other,2-other,3-first,'),
|
||||
@ -1014,6 +1014,9 @@ class Templates(unittest.TestCase):
|
||||
# Regression test for #7460.
|
||||
'cache16': ('{% load cache %}{% cache 1 foo bar %}{% endcache %}', {'foo': 'foo', 'bar': 'with spaces'}, ''),
|
||||
|
||||
# Regression test for #11270.
|
||||
'cache17': ('{% load cache %}{% cache 10 long_cache_key poem %}Some Content{% endcache %}', {'poem': 'Oh freddled gruntbuggly/Thy micturations are to me/As plurdled gabbleblotchits/On a lurgid bee/That mordiously hath bitled out/Its earted jurtles/Into a rancid festering/Or else I shall rend thee in the gobberwarts with my blurglecruncheon/See if I dont.'}, 'Some Content'),
|
||||
|
||||
### AUTOESCAPE TAG ##############################################
|
||||
'autoescape-tag01': ("{% autoescape off %}hello{% endautoescape %}", {}, "hello"),
|
||||
'autoescape-tag02': ("{% autoescape off %}{{ first }}{% endautoescape %}", {"first": "<b>hello</b>"}, "<b>hello</b>"),
|
||||
|
Loading…
x
Reference in New Issue
Block a user