mirror of
https://github.com/django/django.git
synced 2025-07-04 09:49:12 +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>
|
Ian G. Kelly <ian.g.kelly@gmail.com>
|
||||||
Ryan Kelly <ryan@rfk.id.au>
|
Ryan Kelly <ryan@rfk.id.au>
|
||||||
Thomas Kerpe <thomas@kerpe.net>
|
Thomas Kerpe <thomas@kerpe.net>
|
||||||
|
Wiley Kestner <wiley.kestner@gmail.com>
|
||||||
Ossama M. Khayat <okhayat@yahoo.com>
|
Ossama M. Khayat <okhayat@yahoo.com>
|
||||||
Ben Khoo <khoobks@westnet.com.au>
|
Ben Khoo <khoobks@westnet.com.au>
|
||||||
Garth Kidd <http://www.deadlybloodyserious.com/>
|
Garth Kidd <http://www.deadlybloodyserious.com/>
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
<ul>
|
<ul>
|
||||||
{% regroup models by app_label as grouped_models %}
|
{% regroup models by app_label as grouped_models %}
|
||||||
{% for group in 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 %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -37,6 +37,9 @@ def post_comment(request, next=None):
|
|||||||
if not data.get('email', ''):
|
if not data.get('email', ''):
|
||||||
data["email"] = request.user.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
|
# Look up the object we're trying to comment about
|
||||||
ctype = data.get("content_type")
|
ctype = data.get("content_type")
|
||||||
object_pk = data.get("object_pk")
|
object_pk = data.get("object_pk")
|
||||||
|
@ -3,6 +3,7 @@ from django.template import resolve_variable
|
|||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_unicode
|
||||||
from django.utils.http import urlquote
|
from django.utils.http import urlquote
|
||||||
|
from django.utils.hashcompat import md5_constructor
|
||||||
|
|
||||||
register = Library()
|
register = Library()
|
||||||
|
|
||||||
@ -23,7 +24,8 @@ class CacheNode(Node):
|
|||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
raise TemplateSyntaxError('"cache" tag got a non-integer timeout value: %r' % expire_time)
|
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.
|
# 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)
|
value = cache.get(cache_key)
|
||||||
if value is None:
|
if value is None:
|
||||||
value = self.nodelist.render(context)
|
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
|
you don't need to have a separate Web server installed; Django comes with its
|
||||||
own lightweight development server. For a production environment, Django
|
own lightweight development server. For a production environment, Django
|
||||||
follows the WSGI_ spec, which means it can run on a variety of server
|
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
|
popular alternatives. Also, the `server arrangements wiki page`_ contains
|
||||||
details for several deployment strategies.
|
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')
|
sys.path.append('/usr/local/django')
|
||||||
|
|
||||||
just above the ``import`` line to place your project on the path. Remember to
|
just above the final ``import`` line to place your project on the path. Remember to
|
||||||
replace 'mysite.settings' with your correct settings file.
|
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
|
See the :ref:`Apache/mod_python documentation<howto-deployment-modpython>` for
|
||||||
directions on serving static media, and the `mod_wsgi documentation`_ for an
|
directions on serving static media, and the `mod_wsgi documentation`_ for an
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
.. _index:
|
.. _index:
|
||||||
|
|
||||||
====================
|
====================
|
||||||
@ -99,8 +100,11 @@ The view layer
|
|||||||
:ref:`Managing files <topics-files>` |
|
:ref:`Managing files <topics-files>` |
|
||||||
:ref:`Custom storage <howto-custom-file-storage>`
|
:ref:`Custom storage <howto-custom-file-storage>`
|
||||||
|
|
||||||
|
* **Generic views:**
|
||||||
|
:ref:`Overview<topics-generic-views>` |
|
||||||
|
:ref:`Built-in generic views<ref-generic-views>`
|
||||||
|
|
||||||
* **Advanced:**
|
* **Advanced:**
|
||||||
:ref:`Generic views <ref-generic-views>` |
|
|
||||||
:ref:`Generating CSV <howto-outputting-csv>` |
|
:ref:`Generating CSV <howto-outputting-csv>` |
|
||||||
:ref:`Generating PDF <howto-outputting-pdf>`
|
: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.
|
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
|
* Change the "Added/changed in development version" callouts to proper
|
||||||
Sphinx ``.. versionadded::`` or ``.. versionchanged::`` directives.
|
Sphinx ``.. versionadded::`` or ``.. versionchanged::`` directives.
|
||||||
|
|
||||||
|
@ -238,8 +238,8 @@ the admin page doesn't display choices.
|
|||||||
|
|
||||||
Yet.
|
Yet.
|
||||||
|
|
||||||
There are two ways to solve this problem. The first register ``Choice`` with the
|
There are two ways to solve this problem. The first is to register ``Choice``
|
||||||
admin just as we did with ``Poll``. That's easy::
|
with the admin just as we did with ``Poll``. That's easy::
|
||||||
|
|
||||||
from mysite.polls.models import Choice
|
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:`ref-request-response`. For more details on URLconfs, see the
|
||||||
:ref:`topics-http-urls`.
|
: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
|
Tutorial 1, it created a default URLconf in ``mysite/urls.py``. It also
|
||||||
automatically set your :setting:`ROOT_URLCONF` setting (in ``settings.py``) to
|
automatically set your :setting:`ROOT_URLCONF` setting (in ``settings.py``) to
|
||||||
point at that file::
|
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.conf.urls.defaults import *
|
||||||
|
|
||||||
|
from django.contrib import admin
|
||||||
|
admin.autodiscover()
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('',
|
||||||
(r'^polls/$', 'mysite.polls.views.index'),
|
(r'^polls/$', 'mysite.polls.views.index'),
|
||||||
(r'^polls/(?P<poll_id>\d+)/$', 'mysite.polls.views.detail'),
|
(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``
|
the :setting:`ROOT_URLCONF` setting. It finds the variable named ``urlpatterns``
|
||||||
and traverses the regular expressions in order. When it finds a regular
|
and traverses the regular expressions in order. When it finds a regular
|
||||||
expression that matches -- ``r'^polls/(?P<poll_id>\d+)/$'`` -- it loads the
|
expression that matches -- ``r'^polls/(?P<poll_id>\d+)/$'`` -- it loads the
|
||||||
associated Python package/module: ``mysite.polls.views.detail``. That
|
function ``detail()`` from ``mysite/polls/views.py``. Finally,
|
||||||
corresponds to the function ``detail()`` in ``mysite/polls/views.py``. Finally,
|
|
||||||
it calls that ``detail()`` function like so::
|
it calls that ``detail()`` function like so::
|
||||||
|
|
||||||
detail(request=<HttpRequest object>, poll_id='23')
|
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
|
``mysite/urls.py`` to remove the poll-specific URLs and insert an
|
||||||
:func:`~django.conf.urls.defaults.include`::
|
:func:`~django.conf.urls.defaults.include`::
|
||||||
|
|
||||||
|
...
|
||||||
|
urlpatterns = patterns('',
|
||||||
(r'^polls/', include('mysite.polls.urls')),
|
(r'^polls/', include('mysite.polls.urls')),
|
||||||
|
...
|
||||||
|
|
||||||
:func:`~django.conf.urls.defaults.include`, simply, references another URLconf.
|
:func:`~django.conf.urls.defaults.include`, simply, references another URLconf.
|
||||||
Note that the regular expression doesn't have a ``$`` (end-of-string match
|
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.
|
further processing.
|
||||||
|
|
||||||
Now that we've decoupled that, we need to decouple the 'mysite.polls.urls'
|
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',
|
urlpatterns = patterns('mysite.polls.views',
|
||||||
(r'^$', 'index'),
|
(r'^$', 'index'),
|
||||||
|
@ -347,7 +347,7 @@ A few special cases to note about ``list_display``:
|
|||||||
birthday = models.DateField()
|
birthday = models.DateField()
|
||||||
|
|
||||||
def born_in_fifties(self):
|
def born_in_fifties(self):
|
||||||
return self.birthday.strftime('%Y')[:3] == 5
|
return self.birthday.strftime('%Y')[:3] == '195'
|
||||||
born_in_fifties.boolean = True
|
born_in_fifties.boolean = True
|
||||||
|
|
||||||
class PersonAdmin(admin.ModelAdmin):
|
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;
|
changelist displays actions at the top of the page (``actions_on_top = True;
|
||||||
actions_on_bottom = False``).
|
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
|
``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
|
This uses the ``HttpRequest`` instance to filter the ``Car`` foreign key field
|
||||||
to only the cars owned by the ``User`` instance.
|
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
|
``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
|
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::
|
the ability define your own form::
|
||||||
|
|
||||||
class ArticleAdmin(admin.ModelAdmin):
|
class ArticleAdmin(admin.ModelAdmin):
|
||||||
@ -803,7 +890,9 @@ any field::
|
|||||||
|
|
||||||
It is important you use a ``ModelForm`` here otherwise things can break. See the
|
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 <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:
|
.. _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
|
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 or per model. The following can:
|
||||||
|
|
||||||
* ``app_index.html``
|
* ``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
|
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``
|
your own ``AdminSite`` instance (see below), and changing the :attr:`AdminSite.index_template`
|
||||||
or ``login_template`` properties.
|
or :attr:`AdminSite.login_template` properties.
|
||||||
|
|
||||||
``AdminSite`` objects
|
``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
|
Python class), and register your models and ``ModelAdmin`` subclasses
|
||||||
with it instead of using the default.
|
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
|
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
|
Oracle. A workaround to this is to keep ``TextField`` columns out of any
|
||||||
models that you foresee performing ``distinct()`` queries on, and to
|
models that you foresee performing ``distinct()`` queries on, and to
|
||||||
include the ``TextField`` in a related model instead.
|
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).
|
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>
|
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
|
abstracted into "generic views" that let you quickly provide common views of
|
||||||
an object without actually needing to write any Python code.
|
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.
|
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
|
||||||
* A set of views for year/month/day archive pages and associated
|
arguments may either come from the URL pattern or from the ``extra_context``
|
||||||
detail and "latest" pages (for example, the Django weblog's year_,
|
additional-information dictionary.
|
||||||
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.).
|
|
||||||
|
|
||||||
Most generic views require the ``queryset`` key, which is a ``QuerySet``
|
Most generic views require the ``queryset`` key, which is a ``QuerySet``
|
||||||
instance; see :ref:`topics-db-queries` for more information about ``QuerySet``
|
instance; see :ref:`topics-db-queries` for more information about ``QuerySet``
|
||||||
objects.
|
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
|
"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
|
variable's name depends on the ``template_object_name`` parameter, which
|
||||||
is ``'object'`` by default. If ``template_object_name`` is ``'foo'``,
|
is ``'object'`` by default. If ``template_object_name`` is ``'foo'``,
|
||||||
this variable's name will be ``foo``.
|
this variable's name will be ``foo``.
|
||||||
|
|
||||||
|
@ -20,3 +20,4 @@ API Reference
|
|||||||
signals
|
signals
|
||||||
templates/index
|
templates/index
|
||||||
unicode
|
unicode
|
||||||
|
|
||||||
|
@ -616,6 +616,8 @@ call, since they are conflicting options.
|
|||||||
Both the ``depth`` argument and the ability to specify field names in the call
|
Both the ``depth`` argument and the ability to specify field names in the call
|
||||||
to ``select_related()`` are new in Django version 1.0.
|
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)``
|
``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_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
|
Default file storage class to be used for any file-related operations that don't
|
||||||
specify a particular storage system. See :ref:`topics-files`.
|
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('flush', verbosity=0, interactive=False)
|
||||||
management.call_command('loaddata', 'test_data', verbosity=0)
|
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
|
``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.
|
Removes all objects from the related object set.
|
||||||
|
|
||||||
To assign the members of a related set in one fell swoop, just assign to it
|
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 = Blog.objects.get(id=1)
|
||||||
b.entry_set = [e1, e2]
|
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
|
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
|
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*
|
case, a list) are added to the set. If the ``clear()`` method is *not*
|
||||||
|
@ -29,6 +29,45 @@ is required. For example::
|
|||||||
|
|
||||||
return row
|
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`_
|
``connection`` and ``cursor`` mostly implement the standard `Python DB-API`_
|
||||||
(except when it comes to :ref:`transaction handling <topics-db-transactions>`).
|
(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
|
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
|
``"?"`` placeholder, which is used by the SQLite Python bindings. This is for
|
||||||
the sake of consistency and sanity.)
|
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
|
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
|
use the ``where``, ``tables`` and ``params`` arguments to the
|
||||||
API.
|
:ref:`extra clause <extra>` in the standard queryset API.
|
||||||
|
|
||||||
.. _Python DB-API: http://www.python.org/peps/pep-0249.html
|
.. _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
|
... model = Book
|
||||||
... fields = ['title', 'author']
|
... fields = ['title', 'author']
|
||||||
|
|
||||||
|
.. _overriding-modelform-clean-method:
|
||||||
|
|
||||||
Overriding the clean() method
|
Overriding the clean() method
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
You can override the ``clean()`` method on a model form to provide additional
|
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
|
validation in the same way you can on a normal form.
|
||||||
``clean()`` method validates the uniqueness of fields that are marked as
|
|
||||||
``unique``, ``unique_together`` or ``unique_for_date|month|year`` on the model.
|
In this regard, model forms have two specific characteristics when compared to
|
||||||
Therefore, if you would like to override the ``clean()`` method and maintain the
|
forms:
|
||||||
default validation, you must call the parent class's ``clean()`` method.
|
|
||||||
|
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
|
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
|
the unique constraints on your model (either ``unique``, ``unique_together`` or
|
||||||
``unique_for_date|month|year``). If you want to overide the ``clean()`` method
|
``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
|
on a ``model_formset`` and maintain this validation, you must call the parent
|
||||||
classes ``clean`` method::
|
class's ``clean`` method::
|
||||||
|
|
||||||
class MyModelFormSet(BaseModelFormSet):
|
class MyModelFormSet(BaseModelFormSet):
|
||||||
def clean(self):
|
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
|
``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is the
|
||||||
:class:`~django.http. HttpResponse` object returned by a Django view.
|
: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
|
object. It could alter the given ``response``, or it could create and return a
|
||||||
brand-new :class:`~django.http. HttpResponse`.
|
brand-new :class:`~django.http. HttpResponse`.
|
||||||
|
|
||||||
Remember that your middleware will not be called if another middleware object
|
Unlike the ``process_request()`` and ``process_view()`` methods, the
|
||||||
returns a response before you. But unlike ``process_request()`` and
|
``process_response()`` method is always called, even if the ``process_request()``
|
||||||
``process_view()``, during the response phase the classes are applied in reverse
|
and ``process_view()`` methods of the same middleware class were skipped because
|
||||||
order, from the bottom up. This means classes defined at the end of
|
an earlier middleware method returned an :class:`~django.http. HttpResponse`
|
||||||
:setting:`MIDDLEWARE_CLASSES` will be run first.
|
(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:
|
.. _exception-middleware:
|
||||||
|
|
||||||
|
@ -4,6 +4,9 @@
|
|||||||
How to use sessions
|
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
|
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
|
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.
|
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
|
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:
|
test or compile a changed message file, you will need the ``gettext`` utilities:
|
||||||
|
|
||||||
* Download the following zip files from
|
* Download the following zip files from the GNOME servers
|
||||||
http://sourceforge.net/projects/gettext
|
http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/ or from one
|
||||||
|
of its mirrors_
|
||||||
|
|
||||||
* ``gettext-runtime-X.bin.woe32.zip``
|
* ``gettext-runtime-X.zip``
|
||||||
* ``gettext-tools-X.bin.woe32.zip``
|
* ``gettext-tools-X.zip``
|
||||||
* ``libiconv-X.bin.woe32.zip``
|
|
||||||
|
|
||||||
* Extract the 3 files in the same folder (i.e. ``C:\Program
|
``X`` is the version number, we recomend using ``0.15`` or higher.
|
||||||
Files\gettext-utils``)
|
|
||||||
|
* 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:
|
* 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
|
* Add ``;C:\Program Files\gettext-utils\bin`` at the end of the
|
||||||
``Variable value`` field
|
``Variable value`` field
|
||||||
|
|
||||||
|
.. _mirrors: http://ftp.gnome.org/pub/GNOME/MIRRORS
|
||||||
|
|
||||||
You may also use ``gettext`` binaries you have obtained elsewhere, so long as
|
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
|
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
|
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/index
|
||||||
forms/modelforms
|
forms/modelforms
|
||||||
templates
|
templates
|
||||||
|
generic-views
|
||||||
files
|
files
|
||||||
testing
|
testing
|
||||||
auth
|
auth
|
||||||
@ -25,3 +26,4 @@ Introductions to all the key parts of Django you'll need to know:
|
|||||||
serialization
|
serialization
|
||||||
settings
|
settings
|
||||||
signals
|
signals
|
||||||
|
|
||||||
|
@ -61,13 +61,27 @@ for each platform.
|
|||||||
Get your database running
|
Get your database running
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
If you plan to use Django's database API functionality, you'll need to
|
If you plan to use Django's database API functionality, you'll need to make
|
||||||
make sure a database server is running. Django works with PostgreSQL_,
|
sure a database server is running. Django supports many different database
|
||||||
MySQL_, Oracle_ and SQLite_ (although SQLite doesn't require a separate server
|
servers and is officially supported with PostgreSQL_, MySQL_, Oracle_ and
|
||||||
to be running).
|
SQLite_ (although SQLite doesn't require a separate server to be running).
|
||||||
|
|
||||||
Additionally, you'll need to make sure your Python database bindings are
|
In addition to the officially supported databases, there are backends provided
|
||||||
installed.
|
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
|
* 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
|
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
|
:ref:`Oracle backend <oracle-notes>` for important information
|
||||||
regarding supported versions of both Oracle and ``cx_Oracle``.
|
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
|
If you plan to use Django's ``manage.py syncdb`` command to
|
||||||
automatically create database tables for your models, you'll need to
|
automatically create database tables for your models, you'll need to
|
||||||
ensure that Django has permission to create and alter tables in the
|
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/
|
.. _pysqlite: http://pysqlite.org/
|
||||||
.. _cx_Oracle: http://cx-oracle.sourceforge.net/
|
.. _cx_Oracle: http://cx-oracle.sourceforge.net/
|
||||||
.. _Oracle: http://www.oracle.com/
|
.. _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:
|
.. _removing-old-versions-of-django:
|
||||||
|
|
||||||
Remove any 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
|
its own test database. That is, any test that accesses a database -- by
|
||||||
creating and saving model instances, for example -- will not affect your
|
creating and saving model instances, for example -- will not affect your
|
||||||
production database. However, the database is not refreshed between doctests,
|
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
|
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
|
on this.) Note that to use this feature, the database user Django is connecting
|
||||||
as must have ``CREATE DATABASE`` rights.
|
as must have ``CREATE DATABASE`` rights.
|
||||||
@ -1042,7 +1042,7 @@ applications:
|
|||||||
Asserts that a ``Response`` instance produced the given ``status_code`` and
|
Asserts that a ``Response`` instance produced the given ``status_code`` and
|
||||||
that ``text`` does not appears in the content of the response.
|
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
|
Asserts that a field on a form raises the provided list of errors when
|
||||||
rendered on the form.
|
rendered on the form.
|
||||||
@ -1057,19 +1057,19 @@ applications:
|
|||||||
``errors`` is an error string, or a list of error strings, that are
|
``errors`` is an error string, or a list of error strings, that are
|
||||||
expected as a result of form validation.
|
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
|
Asserts that the template with the given name was used in rendering the
|
||||||
response.
|
response.
|
||||||
|
|
||||||
The name is a string such as ``'admin/index.html'``.
|
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
|
Asserts that the template with the given name was *not* used in rendering
|
||||||
the response.
|
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
|
Asserts that the response return a ``status_code`` redirect status, it
|
||||||
redirected to ``expected_url`` (including any GET data), and the final
|
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
|
# Logically the same as above, just written with explicit
|
||||||
# ifchanged for the day.
|
# 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.
|
# 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,'),
|
'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.
|
# Regression test for #7460.
|
||||||
'cache16': ('{% load cache %}{% cache 1 foo bar %}{% endcache %}', {'foo': 'foo', 'bar': 'with spaces'}, ''),
|
'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 TAG ##############################################
|
||||||
'autoescape-tag01': ("{% autoescape off %}hello{% endautoescape %}", {}, "hello"),
|
'autoescape-tag01': ("{% autoescape off %}hello{% endautoescape %}", {}, "hello"),
|
||||||
'autoescape-tag02': ("{% autoescape off %}{{ first }}{% endautoescape %}", {"first": "<b>hello</b>"}, "<b>hello</b>"),
|
'autoescape-tag02': ("{% autoescape off %}{{ first }}{% endautoescape %}", {"first": "<b>hello</b>"}, "<b>hello</b>"),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user