mirror of
https://github.com/django/django.git
synced 2025-10-23 21:59:11 +00:00
Massive reorganization of the docs. See the new docs online at http://docs.djangoproject.com/.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8506 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
122
docs/howto/apache-auth.txt
Normal file
122
docs/howto/apache-auth.txt
Normal file
@@ -0,0 +1,122 @@
|
||||
.. _howto-apache-auth:
|
||||
|
||||
=========================================================
|
||||
Authenticating against Django's user database from Apache
|
||||
=========================================================
|
||||
|
||||
Since keeping multiple authentication databases in sync is a common problem when
|
||||
dealing with Apache, you can configuring Apache to authenticate against Django's
|
||||
:ref:`authentication system <topics-auth>` directly. For example, you
|
||||
could:
|
||||
|
||||
* Serve static/media files directly from Apache only to authenticated users.
|
||||
|
||||
* Authenticate access to a Subversion_ repository against Django users with
|
||||
a certain permission.
|
||||
|
||||
* Allow certain users to connect to a WebDAV share created with mod_dav_.
|
||||
|
||||
.. _Subversion: http://subversion.tigris.org/
|
||||
.. _mod_dav: http://httpd.apache.org/docs/2.0/mod/mod_dav.html
|
||||
|
||||
Configuring Apache
|
||||
==================
|
||||
|
||||
To check against Django's authorization database from a Apache configuration
|
||||
file, you'll need to use mod_python's ``PythonAuthenHandler`` directive along
|
||||
with the standard ``Auth*`` and ``Require`` directives:
|
||||
|
||||
.. code-block:: apache
|
||||
|
||||
<Location /example/>
|
||||
AuthType Basic
|
||||
AuthName "example.com"
|
||||
Require valid-user
|
||||
|
||||
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
|
||||
PythonAuthenHandler django.contrib.auth.handlers.modpython
|
||||
</Location>
|
||||
|
||||
.. admonition:: Using the authentication handler with Apache 2.2
|
||||
|
||||
If you're using Apache 2.2, you'll need to take a couple extra steps.
|
||||
|
||||
You'll need to ensure that ``mod_auth_basic`` and ``mod_authz_user``
|
||||
are loaded. These might be compiled statically into Apache, or you might
|
||||
need to use ``LoadModule`` to load them dynamically (as shown in the
|
||||
example at the bottom of this note).
|
||||
|
||||
You'll also need to insert configuration directives that prevent Apache
|
||||
from trying to use other authentication modules, as well as specifying
|
||||
the ``AuthUserFile`` directive and pointing it to ``/dev/null``. Depending
|
||||
on which other authentication modules you have loaded, you might need one
|
||||
or more of the following directives::
|
||||
|
||||
.. code-block:: apache
|
||||
|
||||
AuthBasicAuthoritative Off
|
||||
AuthDefaultAuthoritative Off
|
||||
AuthzLDAPAuthoritative Off
|
||||
AuthzDBMAuthoritative Off
|
||||
AuthzDefaultAuthoritative Off
|
||||
AuthzGroupFileAuthoritative Off
|
||||
AuthzOwnerAuthoritative Off
|
||||
AuthzUserAuthoritative Off
|
||||
|
||||
A complete configuration, with differences between Apache 2.0 and
|
||||
Apache 2.2 marked in bold, would look something like:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
**LoadModule auth_basic_module modules/mod_auth_basic.so**
|
||||
**LoadModule authz_user_module modules/mod_authz_user.so**
|
||||
|
||||
...
|
||||
|
||||
<Location /example/>
|
||||
AuthType Basic
|
||||
AuthName "example.com"
|
||||
**AuthUserFile /dev/null**
|
||||
**AuthBasicAuthoritative Off**
|
||||
Require valid-user
|
||||
|
||||
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
|
||||
PythonAuthenHandler django.contrib.auth.handlers.modpython
|
||||
</Location>
|
||||
|
||||
By default, the authentication handler will limit access to the ``/example/``
|
||||
location to users marked as staff members. You can use a set of
|
||||
``PythonOption`` directives to modify this behavior:
|
||||
|
||||
================================ =========================================
|
||||
``PythonOption`` Explanation
|
||||
================================ =========================================
|
||||
``DjangoRequireStaffStatus`` If set to ``on`` only "staff" users (i.e.
|
||||
those with the ``is_staff`` flag set)
|
||||
will be allowed.
|
||||
|
||||
Defaults to ``on``.
|
||||
|
||||
``DjangoRequireSuperuserStatus`` If set to ``on`` only superusers (i.e.
|
||||
those with the ``is_superuser`` flag set)
|
||||
will be allowed.
|
||||
|
||||
Defaults to ``off``.
|
||||
|
||||
``DjangoPermissionName`` The name of a permission to require for
|
||||
access. See :ref:`custom permissions
|
||||
<custom-permissions>` for more
|
||||
information.
|
||||
|
||||
By default no specific permission will be
|
||||
required.
|
||||
================================ =========================================
|
||||
|
||||
Note that sometimes ``SetEnv`` doesn't play well in this mod_python
|
||||
configuration, for reasons unknown. If you're having problems getting
|
||||
mod_python to recognize your ``DJANGO_SETTINGS_MODULE``, you can set it using
|
||||
``PythonOption`` instead of ``SetEnv``. Therefore, these two Apache directives
|
||||
are equivalent::
|
||||
|
||||
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
|
||||
PythonOption DJANGO_SETTINGS_MODULE mysite.settings
|
||||
78
docs/howto/custom-file-storage.txt
Normal file
78
docs/howto/custom-file-storage.txt
Normal file
@@ -0,0 +1,78 @@
|
||||
.. _howto-custom-file-storage:
|
||||
|
||||
Writing a custom storage system
|
||||
===============================
|
||||
|
||||
If you need to provide custom file storage -- a common example is storing files
|
||||
on some remote system -- you can do so by defining a custom storage class.
|
||||
You'll need to follow these steps:
|
||||
|
||||
#. Your custom storage system must be a subclass of
|
||||
``django.core.files.storage.Storage``::
|
||||
|
||||
from django.core.files.storage import Storage
|
||||
|
||||
class MyStorage(Storage):
|
||||
...
|
||||
|
||||
#. Django must be able to instantiate your storage system without any arguments.
|
||||
This means that any settings should be taken from ``django.conf.settings``::
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.files.storage import Storage
|
||||
|
||||
class MyStorage(Storage):
|
||||
def __init__(self, option=None):
|
||||
if not option:
|
||||
option = settings.CUSTOM_STORAGE_OPTIONS
|
||||
...
|
||||
|
||||
#. Your storage class must implement the ``_open()`` and ``_save()`` methods,
|
||||
along with any other methods appropriate to your storage class. See below for
|
||||
more on these methods.
|
||||
|
||||
In addition, if your class provides local file storage, it must override
|
||||
the ``path()`` method.
|
||||
|
||||
Your custom storage system may override any of the storage methods explained in
|
||||
:ref:`ref-files-storage`. However, it's usually better to use the hooks
|
||||
specifically designed for custom storage objects. These are:
|
||||
|
||||
``_open(name, mode='rb')``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Required**.
|
||||
|
||||
Called by ``Storage.open()``, this is the actual mechanism the storage class
|
||||
uses to open the file. This must return a ``File`` object, though in most cases,
|
||||
you'll want to return some subclass here that implements logic specific to the
|
||||
backend storage system.
|
||||
|
||||
``_save(name, content)``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Called by ``Storage.save()``. The ``name`` will already have gone through
|
||||
``get_valid_name()`` and ``get_available_name()``, and the ``content`` will be a
|
||||
``File`` object itself. No return value is expected.
|
||||
|
||||
``get_valid_name(name)``
|
||||
------------------------
|
||||
|
||||
Returns a filename suitable for use with the underlying storage system. The
|
||||
``name`` argument passed to this method is the original filename sent to the
|
||||
server, after having any path information removed. Override this to customize
|
||||
how non-standard characters are converted to safe filenames.
|
||||
|
||||
The code provided on ``Storage`` retains only alpha-numeric characters, periods
|
||||
and underscores from the original filename, removing everything else.
|
||||
|
||||
``get_available_name(name)``
|
||||
----------------------------
|
||||
|
||||
Returns a filename that is available in the storage mechanism, possibly taking
|
||||
the provided filename into account. The ``name`` argument passed to this method
|
||||
will have already cleaned to a filename valid for the storage system, according
|
||||
to the ``get_valid_name()`` method described above.
|
||||
|
||||
The code provided on ``Storage`` simply appends underscores to the filename
|
||||
until it finds one that's available in the destination directory.
|
||||
33
docs/howto/custom-management-commands.txt
Normal file
33
docs/howto/custom-management-commands.txt
Normal file
@@ -0,0 +1,33 @@
|
||||
.. _howto-custom-management-commands:
|
||||
|
||||
Writing custom django-admin commands
|
||||
====================================
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
Applications can register their own actions with ``manage.py``. For example,
|
||||
you might want to add a ``manage.py`` action for a Django app that you're
|
||||
distributing.
|
||||
|
||||
To do this, just add a ``management/commands`` directory to your application.
|
||||
Each Python module in that directory will be auto-discovered and registered as
|
||||
a command that can be executed as an action when you run ``manage.py``::
|
||||
|
||||
blog/
|
||||
__init__.py
|
||||
models.py
|
||||
management/
|
||||
__init__.py
|
||||
commands/
|
||||
__init__.py
|
||||
explode.py
|
||||
views.py
|
||||
|
||||
In this example, the ``explode`` command will be made available to any project
|
||||
that includes the ``blog`` application in ``settings.INSTALLED_APPS``.
|
||||
|
||||
The ``explode.py`` module has only one requirement -- it must define a class
|
||||
called ``Command`` that extends ``django.core.management.base.BaseCommand``.
|
||||
|
||||
For more details on how to define your own commands, look at the code for the
|
||||
existing ``django-admin.py`` commands, in ``/django/core/management/commands``.
|
||||
658
docs/howto/custom-model-fields.txt
Normal file
658
docs/howto/custom-model-fields.txt
Normal file
@@ -0,0 +1,658 @@
|
||||
.. _howto-custom-model-fields:
|
||||
|
||||
===========================
|
||||
Writing custom model fields
|
||||
===========================
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
The :ref:`model reference <topics-db-models>` documentation explains how to use
|
||||
Django's standard field classes -- :class:`~django.db.models.CharField`,
|
||||
:class:`~django.db.models.DateField`, etc. For many purposes, those classes are
|
||||
all you'll need. Sometimes, though, the Django version won't meet your precise
|
||||
requirements, or you'll want to use a field that is entirely different from
|
||||
those shipped with Django.
|
||||
|
||||
Django's built-in field types don't cover every possible database column type --
|
||||
only the common types, such as ``VARCHAR`` and ``INTEGER``. For more obscure
|
||||
column types, such as geographic polygons or even user-created types such as
|
||||
`PostgreSQL custom types`_, you can define your own Django ``Field`` subclasses.
|
||||
|
||||
.. _PostgreSQL custom types: http://www.postgresql.org/docs/8.2/interactive/sql-createtype.html
|
||||
|
||||
Alternatively, you may have a complex Python object that can somehow be
|
||||
serialized to fit into a standard database column type. This is another case
|
||||
where a ``Field`` subclass will help you use your object with your models.
|
||||
|
||||
Our example object
|
||||
------------------
|
||||
|
||||
Creating custom fields requires a bit of attention to detail. To make things
|
||||
easier to follow, we'll use a consistent example throughout this document.
|
||||
Suppose you have a Python object representing the deal of cards in a hand of
|
||||
Bridge_. (Don't worry, you don't know how to play Bridge to follow this
|
||||
example. You only need to know that 52 cards are dealt out equally to four
|
||||
players, who are traditionally called *north*, *east*, *south* and *west*.)
|
||||
Our class looks something like this::
|
||||
|
||||
class Hand(object):
|
||||
def __init__(self, north, east, south, west):
|
||||
# Input parameters are lists of cards ('Ah', '9s', etc)
|
||||
self.north = north
|
||||
self.east = east
|
||||
self.south = south
|
||||
self.west = west
|
||||
|
||||
# ... (other possibly useful methods omitted) ...
|
||||
|
||||
.. _Bridge: http://en.wikipedia.org/wiki/Contract_bridge
|
||||
|
||||
This is just an ordinary Python class, with nothing Django-specific about it.
|
||||
We'd like to be able to do things like this in our models (we assume the
|
||||
``hand`` attribute on the model is an instance of ``Hand``)::
|
||||
|
||||
example = MyModel.objects.get(pk=1)
|
||||
print example.hand.north
|
||||
|
||||
new_hand = Hand(north, east, south, west)
|
||||
example.hand = new_hand
|
||||
example.save()
|
||||
|
||||
We assign to and retrieve from the ``hand`` attribute in our model just like
|
||||
any other Python class. The trick is to tell Django how to handle saving and
|
||||
loading such an object.
|
||||
|
||||
In order to use the ``Hand`` class in our models, we **do not** have to change
|
||||
this class at all. This is ideal, because it means you can easily write
|
||||
model support for existing classes where you cannot change the source code.
|
||||
|
||||
.. note::
|
||||
You might only be wanting to take advantage of custom database column
|
||||
types and deal with the data as standard Python types in your models;
|
||||
strings, or floats, for example. This case is similar to our ``Hand``
|
||||
example and we'll note any differences as we go along.
|
||||
|
||||
Background theory
|
||||
=================
|
||||
|
||||
Database storage
|
||||
----------------
|
||||
|
||||
The simplest way to think of a model field is that it provides a way to take a
|
||||
normal Python object -- string, boolean, ``datetime``, or something more
|
||||
complex like ``Hand`` -- and convert it to and from a format that is useful
|
||||
when dealing with the database (and serialization, but, as we'll see later,
|
||||
that falls out fairly naturally once you have the database side under control).
|
||||
|
||||
Fields in a model must somehow be converted to fit into an existing database
|
||||
column type. Different databases provide different sets of valid column types,
|
||||
but the rule is still the same: those are the only types you have to work
|
||||
with. Anything you want to store in the database must fit into one of
|
||||
those types.
|
||||
|
||||
Normally, you're either writing a Django field to match a particular database
|
||||
column type, or there's a fairly straightforward way to convert your data to,
|
||||
say, a string.
|
||||
|
||||
For our ``Hand`` example, we could convert the card data to a string of 104
|
||||
characters by concatenating all the cards together in a pre-determined order --
|
||||
say, all the *north* cards first, then the *east*, *south* and *west* cards. So
|
||||
``Hand`` objects can be saved to text or character columns in the database.
|
||||
|
||||
What does a field class do?
|
||||
---------------------------
|
||||
|
||||
All of Django's fields (and when we say *fields* in this document, we always
|
||||
mean model fields and not :ref:`form fields <ref-forms-fields>`) are subclasses
|
||||
of :class:`django.db.models.Field`. Most of the information that Django records
|
||||
about a field is common to all fields -- name, help text, validator lists,
|
||||
uniqueness and so forth. Storing all that information is handled by ``Field``.
|
||||
We'll get into the precise details of what ``Field`` can do later on; for now,
|
||||
suffice it to say that everything descends from ``Field`` and then customizes
|
||||
key pieces of the class behavior.
|
||||
|
||||
It's important to realize that a Django field class is not what is stored in
|
||||
your model attributes. The model attributes contain normal Python objects. The
|
||||
field classes you define in a model are actually stored in the ``Meta`` class
|
||||
when the model class is created (the precise details of how this is done are
|
||||
unimportant here). This is because the field classes aren't necessary when
|
||||
you're just creating and modifying attributes. Instead, they provide the
|
||||
machinery for converting between the attribute value and what is stored in the
|
||||
database or sent to the :ref:`serializer <topics-serialization>`.
|
||||
|
||||
Keep this in mind when creating your own custom fields. The Django ``Field``
|
||||
subclass you write provides the machinery for converting between your Python
|
||||
instances and the database/serializer values in various ways (there are
|
||||
differences between storing a value and using a value for lookups, for
|
||||
example). If this sounds a bit tricky, don't worry -- it will become clearer in
|
||||
the examples below. Just remember that you will often end up creating two
|
||||
classes when you want a custom field:
|
||||
|
||||
* The first class is the Python object that your users will manipulate.
|
||||
They will assign it to the model attribute, they will read from it for
|
||||
displaying purposes, things like that. This is the ``Hand`` class in our
|
||||
example.
|
||||
|
||||
* The second class is the ``Field`` subclass. This is the class that knows
|
||||
how to convert your first class back and forth between its permanent
|
||||
storage form and the Python form.
|
||||
|
||||
Writing a field subclass
|
||||
========================
|
||||
|
||||
When planning your :class:`~django.db.models.Field` subclass, first give some
|
||||
thought to which existing :class:`~django.db.models.Field` class your new field
|
||||
is most similar to. Can you subclass an existing Django field and save yourself
|
||||
some work? If not, you should subclass the :class:`~django.db.models.Field`
|
||||
class, from which everything is descended.
|
||||
|
||||
Initializing your new field is a matter of separating out any arguments that are
|
||||
specific to your case from the common arguments and passing the latter to the
|
||||
:meth:`~django.db.models.Field.__init__` method of
|
||||
:class:`~django.db.models.Field` (or your parent class).
|
||||
|
||||
In our example, we'll call our field ``HandField``. (It's a good idea to call
|
||||
your :class:`~django.db.models.Field` subclass ``<Something>Field``, so it's
|
||||
easily identifiable as a :class:`~django.db.models.Field` subclass.) It doesn't
|
||||
behave like any existing field, so we'll subclass directly from
|
||||
:class:`~django.db.models.Field`::
|
||||
|
||||
from django.db import models
|
||||
|
||||
class HandField(models.Field):
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs['max_length'] = 104
|
||||
super(HandField, self).__init__(*args, **kwargs)
|
||||
|
||||
Our ``HandField`` accept most of the standard field options (see the list
|
||||
below), but we ensure it has a fixed length, since it only needs to hold 52
|
||||
card values plus their suits; 104 characters in total.
|
||||
|
||||
.. note::
|
||||
Many of Django's model fields accept options that they don't do anything
|
||||
with. For example, you can pass both
|
||||
:attr:`~django.db.models.Field.editable` and
|
||||
:attr:`~django.db.models.Field.auto_now` to a
|
||||
:class:`django.db.models.DateField` and it will simply ignore the
|
||||
:attr:`~django.db.models.Field.editable` parameter
|
||||
(:attr:`~django.db.models.Field.auto_now` being set implies
|
||||
``editable=False``). No error is raised in this case.
|
||||
|
||||
This behavior simplifies the field classes, because they don't need to
|
||||
check for options that aren't necessary. They just pass all the options to
|
||||
the parent class and then don't use them later on. It's up to you whether
|
||||
you want your fields to be more strict about the options they select, or
|
||||
to use the simpler, more permissive behavior of the current fields.
|
||||
|
||||
The :meth:`~django.db.models.Field.__init__` method takes the following
|
||||
parameters:
|
||||
|
||||
* :attr:`~django.db.models.Field.verbose_name`
|
||||
* :attr:`~django.db.models.Field.name`
|
||||
* :attr:`~django.db.models.Field.primary_key`
|
||||
* :attr:`~django.db.models.Field.max_length`
|
||||
* :attr:`~django.db.models.Field.unique`
|
||||
* :attr:`~django.db.models.Field.blank`
|
||||
* :attr:`~django.db.models.Field.null`
|
||||
* :attr:`~django.db.models.Field.db_index`
|
||||
* :attr:`~django.db.models.Field.core`
|
||||
* :attr:`~django.db.models.Field.rel`: Used for related fields (like
|
||||
:attr:`~django.db.models.Field.ForeignKey`). For advanced use only.
|
||||
* :attr:`~django.db.models.Field.default`
|
||||
* :attr:`~django.db.models.Field.editable`
|
||||
* :attr:`~django.db.models.Field.serialize`: If
|
||||
:attr:`~django.db.models.Field.False`, the field will not be serialized
|
||||
when the model is passed to Django's :ref:`serializers
|
||||
<topics-serialization>`. Defaults to
|
||||
:attr:`~django.db.models.Field.True`.
|
||||
* :attr:`~django.db.models.Field.prepopulate_from`
|
||||
* :attr:`~django.db.models.Field.unique_for_date`
|
||||
* :attr:`~django.db.models.Field.unique_for_month`
|
||||
* :attr:`~django.db.models.Field.unique_for_year`
|
||||
* :attr:`~django.db.models.Field.validator_list`
|
||||
* :attr:`~django.db.models.Field.choices`
|
||||
* :attr:`~django.db.models.Field.help_text`
|
||||
* :attr:`~django.db.models.Field.db_column`
|
||||
* :attr:`~django.db.models.Field.db_tablespace`: Currently only used with
|
||||
the Oracle backend and only for index creation. You can usually ignore
|
||||
this option.
|
||||
|
||||
All of the options without an explanation in the above list have the same
|
||||
meaning they do for normal Django fields. See the :ref:`field documentation
|
||||
<ref-models-fields>` for examples and details.
|
||||
|
||||
The ``SubfieldBase`` metaclass
|
||||
------------------------------
|
||||
|
||||
As we indicated in the introduction_, field subclasses are often needed for
|
||||
two reasons: either to take advantage of a custom database column type, or to
|
||||
handle complex Python types. Obviously, a combination of the two is also
|
||||
possible. If you're only working with custom database column types and your
|
||||
model fields appear in Python as standard Python types direct from the
|
||||
database backend, you don't need to worry about this section.
|
||||
|
||||
If you're handling custom Python types, such as our ``Hand`` class, we need to
|
||||
make sure that when Django initializes an instance of our model and assigns a
|
||||
database value to our custom field attribute, we convert that value into the
|
||||
appropriate Python object. The details of how this happens internally are a
|
||||
little complex, but the code you need to write in your ``Field`` class is
|
||||
simple: make sure your field subclass uses a special metaclass:
|
||||
|
||||
.. class:: django.db.models.SubfieldBase
|
||||
|
||||
For example::
|
||||
|
||||
class HandField(models.Field):
|
||||
__metaclass__ = models.SubfieldBase
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
# ...
|
||||
|
||||
This ensures that the :meth:`to_python` method, documented below, will always be
|
||||
called when the attribute is initialized.
|
||||
|
||||
Useful methods
|
||||
--------------
|
||||
|
||||
Once you've created your :class:`~django.db.models.Field` subclass and set up up
|
||||
the ``__metaclass__``, you might consider overriding a few standard methods,
|
||||
depending on your field's behavior. The list of methods below is in
|
||||
approximately decreasing order of importance, so start from the top.
|
||||
|
||||
Custom database types
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. method:: db_type(self)
|
||||
|
||||
Returns the database column data type for the :class:`~django.db.models.Field`,
|
||||
taking into account the current :setting:`DATABASE_ENGINE` setting.
|
||||
|
||||
Say you've created a PostgreSQL custom type called ``mytype``. You can use this
|
||||
field with Django by subclassing ``Field`` and implementing the :meth:`db_type`
|
||||
method, like so::
|
||||
|
||||
from django.db import models
|
||||
|
||||
class MytypeField(models.Field):
|
||||
def db_type(self):
|
||||
return 'mytype'
|
||||
|
||||
Once you have ``MytypeField``, you can use it in any model, just like any other
|
||||
``Field`` type::
|
||||
|
||||
class Person(models.Model):
|
||||
name = models.CharField(max_length=80)
|
||||
gender = models.CharField(max_length=1)
|
||||
something_else = MytypeField()
|
||||
|
||||
If you aim to build a database-agnostic application, you should account for
|
||||
differences in database column types. For example, the date/time column type
|
||||
in PostgreSQL is called ``timestamp``, while the same column in MySQL is called
|
||||
``datetime``. The simplest way to handle this in a ``db_type()`` method is to
|
||||
import the Django settings module and check the :setting:`DATABASE_ENGINE` setting.
|
||||
For example::
|
||||
|
||||
class MyDateField(models.Field):
|
||||
def db_type(self):
|
||||
from django.conf import settings
|
||||
if settings.DATABASE_ENGINE == 'mysql':
|
||||
return 'datetime'
|
||||
else:
|
||||
return 'timestamp'
|
||||
|
||||
The :meth:`db_type` method is only called by Django when the framework
|
||||
constructs the ``CREATE TABLE`` statements for your application -- that is, when
|
||||
you first create your tables. It's not called at any other time, so it can
|
||||
afford to execute slightly complex code, such as the :setting:`DATABASE_ENGINE`
|
||||
check in the above example.
|
||||
|
||||
Some database column types accept parameters, such as ``CHAR(25)``, where the
|
||||
parameter ``25`` represents the maximum column length. In cases like these,
|
||||
it's more flexible if the parameter is specified in the model rather than being
|
||||
hard-coded in the ``db_type()`` method. For example, it wouldn't make much
|
||||
sense to have a ``CharMaxlength25Field``, shown here::
|
||||
|
||||
# This is a silly example of hard-coded parameters.
|
||||
class CharMaxlength25Field(models.Field):
|
||||
def db_type(self):
|
||||
return 'char(25)'
|
||||
|
||||
# In the model:
|
||||
class MyModel(models.Model):
|
||||
# ...
|
||||
my_field = CharMaxlength25Field()
|
||||
|
||||
The better way of doing this would be to make the parameter specifiable at run
|
||||
time -- i.e., when the class is instantiated. To do that, just implement
|
||||
:meth:`django.db.models.Field.__init__`, like so::
|
||||
|
||||
# This is a much more flexible example.
|
||||
class BetterCharField(models.Field):
|
||||
def __init__(self, max_length, *args, **kwargs):
|
||||
self.max_length = max_length
|
||||
super(BetterCharField, self).__init__(*args, **kwargs)
|
||||
|
||||
def db_type(self):
|
||||
return 'char(%s)' % self.max_length
|
||||
|
||||
# In the model:
|
||||
class MyModel(models.Model):
|
||||
# ...
|
||||
my_field = BetterCharField(25)
|
||||
|
||||
Finally, if your column requires truly complex SQL setup, return ``None`` from
|
||||
:meth:`db_type`. This will cause Django's SQL creation code to skip over this
|
||||
field. You are then responsible for creating the column in the right table in
|
||||
some other way, of course, but this gives you a way to tell Django to get out of
|
||||
the way.
|
||||
|
||||
Converting database values to Python objects
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. method:: to_python(self, value)
|
||||
|
||||
Converts a value as returned by your database (or a serializer) to a Python
|
||||
object.
|
||||
|
||||
The default implementation simply returns ``value``, for the common case in
|
||||
which the database backend already returns data in the correct format (as a
|
||||
Python string, for example).
|
||||
|
||||
If your custom :class:`~django.db.models.Field` class deals with data structures
|
||||
that are more complex than strings, dates, integers or floats, then you'll need
|
||||
to override this method. As a general rule, the method should deal gracefully
|
||||
with any of the following arguments:
|
||||
|
||||
* An instance of the correct type (e.g., ``Hand`` in our ongoing example).
|
||||
|
||||
* A string (e.g., from a deserializer).
|
||||
|
||||
* Whatever the database returns for the column type you're using.
|
||||
|
||||
In our ``HandField`` class, we're storing the data as a VARCHAR field in the
|
||||
database, so we need to be able to process strings and ``Hand`` instances in
|
||||
:meth:`to_python`::
|
||||
|
||||
import re
|
||||
|
||||
class HandField(models.Field):
|
||||
# ...
|
||||
|
||||
def to_python(self, value):
|
||||
if isinstance(value, Hand):
|
||||
return value
|
||||
|
||||
# The string case.
|
||||
p1 = re.compile('.{26}')
|
||||
p2 = re.compile('..')
|
||||
args = [p2.findall(x) for x in p1.findall(value)]
|
||||
return Hand(*args)
|
||||
|
||||
Notice that we always return a ``Hand`` instance from this method. That's the
|
||||
Python object type we want to store in the model's attribute.
|
||||
|
||||
**Remember:** If your custom field needs the :meth:`to_python` method to be
|
||||
called when it is created, you should be using `The SubfieldBase metaclass`_
|
||||
mentioned earlier. Otherwise :meth:`to_python` won't be called automatically.
|
||||
|
||||
Converting Python objects to database values
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. method:: get_db_prep_value(self, value)
|
||||
|
||||
This is the reverse of :meth:`to_python` when working with the database backends
|
||||
(as opposed to serialization). The ``value`` parameter is the current value of
|
||||
the model's attribute (a field has no reference to its containing model, so it
|
||||
cannot retrieve the value itself), and the method should return data in a format
|
||||
that can be used as a parameter in a query for the database backend.
|
||||
|
||||
For example::
|
||||
|
||||
class HandField(models.Field):
|
||||
# ...
|
||||
|
||||
def get_db_prep_value(self, value):
|
||||
return ''.join([''.join(l) for l in (value.north,
|
||||
value.east, value.south, value.west)])
|
||||
|
||||
.. method:: get_db_prep_save(self, value)
|
||||
|
||||
Same as the above, but called when the Field value must be *saved* to the
|
||||
database. As the default implementation just calls ``get_db_prep_value``, you
|
||||
shouldn't need to implement this method unless your custom field need a special
|
||||
conversion when being saved that is not the same as the used for normal query
|
||||
parameters (which is implemented by ``get_db_prep_value``).
|
||||
|
||||
Preprocessing values before saving
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. method:: pre_save(self, model_instance, add)
|
||||
|
||||
This method is called just prior to :meth:`get_db_prep_save` and should return
|
||||
the value of the appropriate attribute from ``model_instance`` for this field.
|
||||
The attribute name is in ``self.attname`` (this is set up by
|
||||
:class:`~django.db.models.Field`). If the model is being saved to the database
|
||||
for the first time, the ``add`` parameter will be ``True``, otherwise it will be
|
||||
``False``.
|
||||
|
||||
You only need to override this method if you want to preprocess the value
|
||||
somehow, just before saving. For example, Django's
|
||||
`:class:`~django.db.models.DateTimeField` uses this method to set the attribute
|
||||
correctly in the case of :attr:`~django.db.models.Field.auto_now` or
|
||||
:attr:`~django.db.models.Field.auto_now_add`.
|
||||
|
||||
If you do override this method, you must return the value of the attribute at
|
||||
the end. You should also update the model's attribute if you make any changes
|
||||
to the value so that code holding references to the model will always see the
|
||||
correct value.
|
||||
|
||||
Preparing values for use in database lookups
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. method:: get_db_prep_lookup(self, lookup_type, value)
|
||||
|
||||
Prepares the ``value`` for passing to the database when used in a lookup (a
|
||||
``WHERE`` constraint in SQL). The ``lookup_type`` will be one of the valid
|
||||
Django filter lookups: ``exact``, ``iexact``, ``contains``, ``icontains``,
|
||||
``gt``, ``gte``, ``lt``, ``lte``, ``in``, ``startswith``, ``istartswith``,
|
||||
``endswith``, ``iendswith``, ``range``, ``year``, ``month``, ``day``,
|
||||
``isnull``, ``search``, ``regex``, and ``iregex``.
|
||||
|
||||
Your method must be prepared to handle all of these ``lookup_type`` values and
|
||||
should raise either a ``ValueError`` if the ``value`` is of the wrong sort (a
|
||||
list when you were expecting an object, for example) or a ``TypeError`` if
|
||||
your field does not support that type of lookup. For many fields, you can get
|
||||
by with handling the lookup types that need special handling for your field
|
||||
and pass the rest of the :meth:`get_db_prep_lookup` method of the parent class.
|
||||
|
||||
If you needed to implement ``get_db_prep_save()``, you will usually need to
|
||||
implement ``get_db_prep_lookup()``. If you don't, ``get_db_prep_value`` will be
|
||||
called by the default implementation, to manage ``exact``, ``gt``, ``gte``,
|
||||
``lt``, ``lte``, ``in`` and ``range`` lookups.
|
||||
|
||||
You may also want to implement this method to limit the lookup types that could
|
||||
be used with your custom field type.
|
||||
|
||||
Note that, for ``range`` and ``in`` lookups, ``get_db_prep_lookup`` will receive
|
||||
a list of objects (presumably of the right type) and will need to convert them
|
||||
to a list of things of the right type for passing to the database. Most of the
|
||||
time, you can reuse ``get_db_prep_value()``, or at least factor out some common
|
||||
pieces.
|
||||
|
||||
For example, the following code implements ``get_db_prep_lookup`` to limit the
|
||||
accepted lookup types to ``exact`` and ``in``::
|
||||
|
||||
class HandField(models.Field):
|
||||
# ...
|
||||
|
||||
def get_db_prep_lookup(self, lookup_type, value):
|
||||
# We only handle 'exact' and 'in'. All others are errors.
|
||||
if lookup_type == 'exact':
|
||||
return self.get_db_prep_value(value)
|
||||
elif lookup_type == 'in':
|
||||
return [self.get_db_prep_value(v) for v in value]
|
||||
else:
|
||||
raise TypeError('Lookup type %r not supported.' % lookup_type)
|
||||
|
||||
Specifying the form field for a model field
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. method:: formfield(self, form_class=forms.CharField, **kwargs)
|
||||
|
||||
Returns the default form field to use when this field is displayed in a model.
|
||||
This method is called by the :class:`~django.forms.ModelForm` helper.
|
||||
|
||||
All of the ``kwargs`` dictionary is passed directly to the form field's
|
||||
:meth:`~django.forms.Field__init__` method. Normally, all you need to do is
|
||||
set up a good default for the ``form_class`` argument and then delegate further
|
||||
handling to the parent class. This might require you to write a custom form
|
||||
field (and even a form widget). See the :ref:`forms documentation
|
||||
<topics-forms-index>` for information about this, and take a look at the code in
|
||||
:mod:`django.contrib.localflavor` for some examples of custom widgets.
|
||||
|
||||
Continuing our ongoing example, we can write the :meth:`formfield` method as::
|
||||
|
||||
class HandField(models.Field):
|
||||
# ...
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
# This is a fairly standard way to set up some defaults
|
||||
# while letting the caller override them.
|
||||
defaults = {'form_class': MyFormField}
|
||||
defaults.update(kwargs)
|
||||
return super(HandField, self).formfield(**defaults)
|
||||
|
||||
This assumes we're imported a ``MyFormField`` field class (which has its own
|
||||
default widget). This document doesn't cover the details of writing custom form
|
||||
fields.
|
||||
|
||||
.. _helper functions: ../forms/#generating-forms-for-models
|
||||
.. _forms documentation: ../forms/
|
||||
|
||||
Emulating built-in field types
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. method:: get_internal_type(self)
|
||||
|
||||
Returns a string giving the name of the :class:`~django.db.models.Field`
|
||||
subclass we are emulating at the database level. This is used to determine the
|
||||
type of database column for simple cases.
|
||||
|
||||
If you have created a :meth:`db_type` method, you don't need to worry about
|
||||
:meth:`get_internal_type` -- it won't be used much. Sometimes, though, your
|
||||
database storage is similar in type to some other field, so you can use that
|
||||
other field's logic to create the right column.
|
||||
|
||||
For example::
|
||||
|
||||
class HandField(models.Field):
|
||||
# ...
|
||||
|
||||
def get_internal_type(self):
|
||||
return 'CharField'
|
||||
|
||||
No matter which database backend we are using, this will mean that ``syncdb``
|
||||
and other SQL commands create the right column type for storing a string.
|
||||
|
||||
If :meth:`get_internal_type` returns a string that is not known to Django for
|
||||
the database backend you are using -- that is, it doesn't appear in
|
||||
``django.db.backends.<db_name>.creation.DATA_TYPES`` -- the string will still be
|
||||
used by the serializer, but the default :meth:`db_type` method will return
|
||||
``None``. See the documentation of :meth:`db_type` for reasons why this might be
|
||||
useful. Putting a descriptive string in as the type of the field for the
|
||||
serializer is a useful idea if you're ever going to be using the serializer
|
||||
output in some other place, outside of Django.
|
||||
|
||||
Converting field data for serialization
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. method:: flatten_data(self, follow, obj=None)
|
||||
|
||||
.. admonition:: Subject to change
|
||||
|
||||
Although implementing this method is necessary to allow field
|
||||
serialization, the API might change in the future.
|
||||
|
||||
Returns a dictionary, mapping the field's attribute name to a flattened string
|
||||
version of the data. This method has some internal uses that aren't of interest
|
||||
to use here (mostly having to do with forms). For our purposes, it's sufficient
|
||||
to return a one item dictionary that maps the attribute name to a string.
|
||||
|
||||
This method is used by the serializers to convert the field into a string for
|
||||
output. You can ignore the input parameters for serialization purposes, although
|
||||
calling :meth:`Field._get_val_from_obj(obj)
|
||||
<django.db.models.Field._get_val_from_obj>` is the best way to get the value to
|
||||
serialize.
|
||||
|
||||
For example, since our ``HandField`` uses strings for its data storage anyway,
|
||||
we can reuse some existing conversion code::
|
||||
|
||||
class HandField(models.Field):
|
||||
# ...
|
||||
|
||||
def flatten_data(self, follow, obj=None):
|
||||
value = self._get_val_from_obj(obj)
|
||||
return {self.attname: self.get_db_prep_value(value)}
|
||||
|
||||
Some general advice
|
||||
--------------------
|
||||
|
||||
Writing a custom field can be a tricky process, particularly if you're doing
|
||||
complex conversions between your Python types and your database and
|
||||
serialization formats. Here are a couple of tips to make things go more
|
||||
smoothly:
|
||||
|
||||
1. Look at the existing Django fields (in
|
||||
:file:`django/db/models/fields/__init__.py`) for inspiration. Try to find
|
||||
a field that's similar to what you want and extend it a little bit,
|
||||
instead of creating an entirely new field from scratch.
|
||||
|
||||
2. Put a :meth:`__str__` or :meth:`__unicode__` method on the class you're
|
||||
wrapping up as a field. There are a lot of places where the default
|
||||
behavior of the field code is to call
|
||||
:func:`~django.utils.encoding.force_unicode` on the value. (In our
|
||||
examples in this document, ``value`` would be a ``Hand`` instance, not a
|
||||
``HandField``). So if your :meth:`__unicode__` method automatically
|
||||
converts to the string form of your Python object, you can save yourself
|
||||
a lot of work.
|
||||
|
||||
|
||||
Writing a ``FileField`` subclass
|
||||
=================================
|
||||
|
||||
In addition to the above methods, fields that deal with files have a few other
|
||||
special requirements which must be taken into account. The majority of the
|
||||
mechanics provided by ``FileField``, such as controlling database storage and
|
||||
retrieval, can remain unchanged, leaving subclasses to deal with the challenge
|
||||
of supporting a particular type of file.
|
||||
|
||||
Django provides a ``File`` class, which is used as a proxy to the file's
|
||||
contents and operations. This can be subclassed to customize how the file is
|
||||
accessed, and what methods are available. It lives at
|
||||
``django.db.models.fields.files``, and its default behavior is explained in the
|
||||
:ref:`file documentation <ref-files-file>`.
|
||||
|
||||
Once a subclass of ``File`` is created, the new ``FileField`` subclass must be
|
||||
told to use it. To do so, simply assign the new ``File`` subclass to the special
|
||||
``attr_class`` attribute of the ``FileField`` subclass.
|
||||
|
||||
A few suggestions
|
||||
------------------
|
||||
|
||||
In addition to the above details, there are a few guidelines which can greatly
|
||||
improve the efficiency and readability of the field's code.
|
||||
|
||||
1. The source for Django's own ``ImageField`` (in
|
||||
``django/db/models/fields/files.py``) is a great example of how to
|
||||
subclass ``FileField`` to support a particular type of file, as it
|
||||
incorporates all of the techniques described above.
|
||||
|
||||
2. Cache file attributes wherever possible. Since files may be stored in
|
||||
remote storage systems, retrieving them may cost extra time, or even
|
||||
money, that isn't always necessary. Once a file is retrieved to obtain
|
||||
some data about its content, cache as much of that data as possible to
|
||||
reduce the number of times the file must be retrieved on subsequent
|
||||
calls for that information.
|
||||
877
docs/howto/custom-template-tags.txt
Normal file
877
docs/howto/custom-template-tags.txt
Normal file
@@ -0,0 +1,877 @@
|
||||
.. _howto-custom-template-tags:
|
||||
|
||||
================================
|
||||
Custom template tags and filters
|
||||
================================
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
Django's template system comes a wide variety of :ref:`built-in tags and filters
|
||||
<ref-templates-builtins>` designed to address the presentation logic needs of
|
||||
your application. Nevertheless, you may find yourself needing functionality that
|
||||
is not covered by the core set of template primitives. You can extend the
|
||||
template engine by defining custom tags and filters using Python, and then make
|
||||
them available to your templates using the ``{% load %}`` tag.
|
||||
|
||||
Code layout
|
||||
-----------
|
||||
|
||||
Custom template tags and filters must live inside a Django app. If they relate
|
||||
to an existing app it makes sense to bundle them there; otherwise, you should
|
||||
create a new app to hold them.
|
||||
|
||||
The app should contain a ``templatetags`` directory, at the same level as
|
||||
``models.py``, ``views.py``, etc. If this doesn't already exist, create it -
|
||||
don't forget the ``__init__.py`` file to ensure the directory is treated as a
|
||||
Python package.
|
||||
|
||||
Your custom tags and filters will live in a module inside the ``templatetags``
|
||||
directory. The name of the module file is the name you'll use to load the tags
|
||||
later, so be careful to pick a name that won't clash with custom tags and
|
||||
filters in another app.
|
||||
|
||||
For example, if your custom tags/filters are in a file called
|
||||
``poll_extras.py``, your app layout might look like this::
|
||||
|
||||
polls/
|
||||
models.py
|
||||
templatetags/
|
||||
__init__.py
|
||||
poll_extras.py
|
||||
views.py
|
||||
|
||||
And in your template you would use the following:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{% load poll_extras %}
|
||||
|
||||
The app that contains the custom tags must be in :setting:`INSTALLED_APPS` in
|
||||
order for the ``{% load %}`` tag to work. This is a security feature: It allows
|
||||
you to host Python code for many template libraries on a single host machine
|
||||
without enabling access to all of them for every Django installation.
|
||||
|
||||
There's no limit on how many modules you put in the ``templatetags`` package.
|
||||
Just keep in mind that a ``{% load %}`` statement will load tags/filters for
|
||||
the given Python module name, not the name of the app.
|
||||
|
||||
To be a valid tag library, the module must contain a module-level variable
|
||||
named ``register`` that is a ``template.Library`` instance, in which all the
|
||||
tags and filters are registered. So, near the top of your module, put the
|
||||
following::
|
||||
|
||||
from django import template
|
||||
|
||||
register = template.Library()
|
||||
|
||||
.. admonition:: Behind the scenes
|
||||
|
||||
For a ton of examples, read the source code for Django's default filters
|
||||
and tags. They're in ``django/template/defaultfilters.py`` and
|
||||
``django/template/defaulttags.py``, respectively.
|
||||
|
||||
Writing custom template filters
|
||||
-------------------------------
|
||||
|
||||
Custom filters are just Python functions that take one or two arguments:
|
||||
|
||||
* The value of the variable (input) -- not necessarily a string.
|
||||
* The value of the argument -- this can have a default value, or be left
|
||||
out altogether.
|
||||
|
||||
For example, in the filter ``{{ var|foo:"bar" }}``, the filter ``foo`` would be
|
||||
passed the variable ``var`` and the argument ``"bar"``.
|
||||
|
||||
Filter functions should always return something. They shouldn't raise
|
||||
exceptions. They should fail silently. In case of error, they should return
|
||||
either the original input or an empty string -- whichever makes more sense.
|
||||
|
||||
Here's an example filter definition::
|
||||
|
||||
def cut(value, arg):
|
||||
"Removes all values of arg from the given string"
|
||||
return value.replace(arg, '')
|
||||
|
||||
And here's an example of how that filter would be used:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{{ somevariable|cut:"0" }}
|
||||
|
||||
Most filters don't take arguments. In this case, just leave the argument out of
|
||||
your function. Example::
|
||||
|
||||
def lower(value): # Only one argument.
|
||||
"Converts a string into all lowercase"
|
||||
return value.lower()
|
||||
|
||||
Template filters that expect strings
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you're writing a template filter that only expects a string as the first
|
||||
argument, you should use the decorator ``stringfilter``. This will
|
||||
convert an object to its string value before being passed to your function::
|
||||
|
||||
from django.template.defaultfilters import stringfilter
|
||||
|
||||
@stringfilter
|
||||
def lower(value):
|
||||
return value.lower()
|
||||
|
||||
This way, you'll be able to pass, say, an integer to this filter, and it
|
||||
won't cause an ``AttributeError`` (because integers don't have ``lower()``
|
||||
methods).
|
||||
|
||||
Registering custom filters
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Once you've written your filter definition, you need to register it with
|
||||
your ``Library`` instance, to make it available to Django's template language::
|
||||
|
||||
register.filter('cut', cut)
|
||||
register.filter('lower', lower)
|
||||
|
||||
The ``Library.filter()`` method takes two arguments:
|
||||
|
||||
1. The name of the filter -- a string.
|
||||
2. The compilation function -- a Python function (not the name of the
|
||||
function as a string).
|
||||
|
||||
If you're using Python 2.4 or above, you can use ``register.filter()`` as a
|
||||
decorator instead::
|
||||
|
||||
@register.filter(name='cut')
|
||||
@stringfilter
|
||||
def cut(value, arg):
|
||||
return value.replace(arg, '')
|
||||
|
||||
@register.filter
|
||||
@stringfilter
|
||||
def lower(value):
|
||||
return value.lower()
|
||||
|
||||
If you leave off the ``name`` argument, as in the second example above, Django
|
||||
will use the function's name as the filter name.
|
||||
|
||||
Filters and auto-escaping
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
When writing a custom filter, give some thought to how the filter will interact
|
||||
with Django's auto-escaping behavior. Note that three types of strings can be
|
||||
passed around inside the template code:
|
||||
|
||||
* **Raw strings** are the native Python ``str`` or ``unicode`` types. On
|
||||
output, they're escaped if auto-escaping is in effect and presented
|
||||
unchanged, otherwise.
|
||||
|
||||
* **Safe strings** are strings that have been marked safe from further
|
||||
escaping at output time. Any necessary escaping has already been done.
|
||||
They're commonly used for output that contains raw HTML that is intended
|
||||
to be interpreted as-is on the client side.
|
||||
|
||||
Internally, these strings are of type ``SafeString`` or ``SafeUnicode``.
|
||||
They share a common base class of ``SafeData``, so you can test
|
||||
for them using code like::
|
||||
|
||||
if isinstance(value, SafeData):
|
||||
# Do something with the "safe" string.
|
||||
|
||||
* **Strings marked as "needing escaping"** are *always* escaped on
|
||||
output, regardless of whether they are in an ``autoescape`` block or not.
|
||||
These strings are only escaped once, however, even if auto-escaping
|
||||
applies.
|
||||
|
||||
Internally, these strings are of type ``EscapeString`` or
|
||||
``EscapeUnicode``. Generally you don't have to worry about these; they
|
||||
exist for the implementation of the ``escape`` filter.
|
||||
|
||||
Template filter code falls into one of two situations:
|
||||
|
||||
1. Your filter does not introduce any HTML-unsafe characters (``<``, ``>``,
|
||||
``'``, ``"`` or ``&``) into the result that were not already present. In
|
||||
this case, you can let Django take care of all the auto-escaping
|
||||
handling for you. All you need to do is put the ``is_safe`` attribute on
|
||||
your filter function and set it to ``True``, like so::
|
||||
|
||||
@register.filter
|
||||
def myfilter(value):
|
||||
return value
|
||||
myfilter.is_safe = True
|
||||
|
||||
This attribute tells Django that if a "safe" string is passed into your
|
||||
filter, the result will still be "safe" and if a non-safe string is
|
||||
passed in, Django will automatically escape it, if necessary.
|
||||
|
||||
You can think of this as meaning "this filter is safe -- it doesn't
|
||||
introduce any possibility of unsafe HTML."
|
||||
|
||||
The reason ``is_safe`` is necessary is because there are plenty of
|
||||
normal string operations that will turn a ``SafeData`` object back into
|
||||
a normal ``str`` or ``unicode`` object and, rather than try to catch
|
||||
them all, which would be very difficult, Django repairs the damage after
|
||||
the filter has completed.
|
||||
|
||||
For example, suppose you have a filter that adds the string ``xx`` to the
|
||||
end of any input. Since this introduces no dangerous HTML characters to
|
||||
the result (aside from any that were already present), you should mark
|
||||
your filter with ``is_safe``::
|
||||
|
||||
@register.filter
|
||||
def add_xx(value):
|
||||
return '%sxx' % value
|
||||
add_xx.is_safe = True
|
||||
|
||||
When this filter is used in a template where auto-escaping is enabled,
|
||||
Django will escape the output whenever the input is not already marked as
|
||||
"safe".
|
||||
|
||||
By default, ``is_safe`` defaults to ``False``, and you can omit it from
|
||||
any filters where it isn't required.
|
||||
|
||||
Be careful when deciding if your filter really does leave safe strings
|
||||
as safe. If you're *removing* characters, you might inadvertently leave
|
||||
unbalanced HTML tags or entities in the result. For example, removing a
|
||||
``>`` from the input might turn ``<a>`` into ``<a``, which would need to
|
||||
be escaped on output to avoid causing problems. Similarly, removing a
|
||||
semicolon (``;``) can turn ``&`` into ``&``, which is no longer a
|
||||
valid entity and thus needs further escaping. Most cases won't be nearly
|
||||
this tricky, but keep an eye out for any problems like that when
|
||||
reviewing your code.
|
||||
|
||||
2. Alternatively, your filter code can manually take care of any necessary
|
||||
escaping. This is necessary when you're introducing new HTML markup into
|
||||
the result. You want to mark the output as safe from further
|
||||
escaping so that your HTML markup isn't escaped further, so you'll need
|
||||
to handle the input yourself.
|
||||
|
||||
To mark the output as a safe string, use
|
||||
:func:`django.utils.safestring.mark_safe`.
|
||||
|
||||
Be careful, though. You need to do more than just mark the output as
|
||||
safe. You need to ensure it really *is* safe, and what you do depends on
|
||||
whether auto-escaping is in effect. The idea is to write filters than
|
||||
can operate in templates where auto-escaping is either on or off in
|
||||
order to make things easier for your template authors.
|
||||
|
||||
In order for your filter to know the current auto-escaping state, set
|
||||
the ``needs_autoescape`` attribute to ``True`` on your function. (If you
|
||||
don't specify this attribute, it defaults to ``False``). This attribute
|
||||
tells Django that your filter function wants to be passed an extra
|
||||
keyword argument, called ``autoescape``, that is ``True`` if
|
||||
auto-escaping is in effect and ``False`` otherwise.
|
||||
|
||||
For example, let's write a filter that emphasizes the first character of
|
||||
a string::
|
||||
|
||||
from django.utils.html import conditional_escape
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
def initial_letter_filter(text, autoescape=None):
|
||||
first, other = text[0], text[1:]
|
||||
if autoescape:
|
||||
esc = conditional_escape
|
||||
else:
|
||||
esc = lambda x: x
|
||||
result = '<strong>%s</strong>%s' % (esc(first), esc(other))
|
||||
return mark_safe(result)
|
||||
initial_letter_filter.needs_autoescape = True
|
||||
|
||||
The ``needs_autoescape`` attribute on the filter function and the
|
||||
``autoescape`` keyword argument mean that our function will know whether
|
||||
automatic escaping is in effect when the filter is called. We use
|
||||
``autoescape`` to decide whether the input data needs to be passed
|
||||
through ``django.utils.html.conditional_escape`` or not. (In the latter
|
||||
case, we just use the identity function as the "escape" function.) The
|
||||
``conditional_escape()`` function is like ``escape()`` except it only
|
||||
escapes input that is **not** a ``SafeData`` instance. If a ``SafeData``
|
||||
instance is passed to ``conditional_escape()``, the data is returned
|
||||
unchanged.
|
||||
|
||||
Finally, in the above example, we remember to mark the result as safe
|
||||
so that our HTML is inserted directly into the template without further
|
||||
escaping.
|
||||
|
||||
There's no need to worry about the ``is_safe`` attribute in this case
|
||||
(although including it wouldn't hurt anything). Whenever you manually
|
||||
handle the auto-escaping issues and return a safe string, the
|
||||
``is_safe`` attribute won't change anything either way.
|
||||
|
||||
Writing custom template tags
|
||||
----------------------------
|
||||
|
||||
Tags are more complex than filters, because tags can do anything.
|
||||
|
||||
A quick overview
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Above, this document explained that the template system works in a two-step
|
||||
process: compiling and rendering. To define a custom template tag, you specify
|
||||
how the compilation works and how the rendering works.
|
||||
|
||||
When Django compiles a template, it splits the raw template text into
|
||||
''nodes''. Each node is an instance of ``django.template.Node`` and has
|
||||
a ``render()`` method. A compiled template is, simply, a list of ``Node``
|
||||
objects. When you call ``render()`` on a compiled template object, the template
|
||||
calls ``render()`` on each ``Node`` in its node list, with the given context.
|
||||
The results are all concatenated together to form the output of the template.
|
||||
|
||||
Thus, to define a custom template tag, you specify how the raw template tag is
|
||||
converted into a ``Node`` (the compilation function), and what the node's
|
||||
``render()`` method does.
|
||||
|
||||
Writing the compilation function
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
For each template tag the template parser encounters, it calls a Python
|
||||
function with the tag contents and the parser object itself. This function is
|
||||
responsible for returning a ``Node`` instance based on the contents of the tag.
|
||||
|
||||
For example, let's write a template tag, ``{% current_time %}``, that displays
|
||||
the current date/time, formatted according to a parameter given in the tag, in
|
||||
`strftime syntax`_. It's a good idea to decide the tag syntax before anything
|
||||
else. In our case, let's say the tag should be used like this:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
<p>The time is {% current_time "%Y-%m-%d %I:%M %p" %}.</p>
|
||||
|
||||
.. _`strftime syntax`: http://www.python.org/doc/current/lib/module-time.html#l2h-1941
|
||||
|
||||
The parser for this function should grab the parameter and create a ``Node``
|
||||
object::
|
||||
|
||||
from django import template
|
||||
def do_current_time(parser, token):
|
||||
try:
|
||||
# split_contents() knows not to split quoted strings.
|
||||
tag_name, format_string = token.split_contents()
|
||||
except ValueError:
|
||||
raise template.TemplateSyntaxError, "%r tag requires a single argument" % token.contents.split()[0]
|
||||
if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
|
||||
raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name
|
||||
return CurrentTimeNode(format_string[1:-1])
|
||||
|
||||
Notes:
|
||||
|
||||
* ``parser`` is the template parser object. We don't need it in this
|
||||
example.
|
||||
|
||||
* ``token.contents`` is a string of the raw contents of the tag. In our
|
||||
example, it's ``'current_time "%Y-%m-%d %I:%M %p"'``.
|
||||
|
||||
* The ``token.split_contents()`` method separates the arguments on spaces
|
||||
while keeping quoted strings together. The more straightforward
|
||||
``token.contents.split()`` wouldn't be as robust, as it would naively
|
||||
split on *all* spaces, including those within quoted strings. It's a good
|
||||
idea to always use ``token.split_contents()``.
|
||||
|
||||
* This function is responsible for raising
|
||||
``django.template.TemplateSyntaxError``, with helpful messages, for
|
||||
any syntax error.
|
||||
|
||||
* The ``TemplateSyntaxError`` exceptions use the ``tag_name`` variable.
|
||||
Don't hard-code the tag's name in your error messages, because that
|
||||
couples the tag's name to your function. ``token.contents.split()[0]``
|
||||
will ''always'' be the name of your tag -- even when the tag has no
|
||||
arguments.
|
||||
|
||||
* The function returns a ``CurrentTimeNode`` with everything the node needs
|
||||
to know about this tag. In this case, it just passes the argument --
|
||||
``"%Y-%m-%d %I:%M %p"``. The leading and trailing quotes from the
|
||||
template tag are removed in ``format_string[1:-1]``.
|
||||
|
||||
* The parsing is very low-level. The Django developers have experimented
|
||||
with writing small frameworks on top of this parsing system, using
|
||||
techniques such as EBNF grammars, but those experiments made the template
|
||||
engine too slow. It's low-level because that's fastest.
|
||||
|
||||
Writing the renderer
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The second step in writing custom tags is to define a ``Node`` subclass that
|
||||
has a ``render()`` method.
|
||||
|
||||
Continuing the above example, we need to define ``CurrentTimeNode``::
|
||||
|
||||
from django import template
|
||||
import datetime
|
||||
class CurrentTimeNode(template.Node):
|
||||
def __init__(self, format_string):
|
||||
self.format_string = format_string
|
||||
def render(self, context):
|
||||
return datetime.datetime.now().strftime(self.format_string)
|
||||
|
||||
Notes:
|
||||
|
||||
* ``__init__()`` gets the ``format_string`` from ``do_current_time()``.
|
||||
Always pass any options/parameters/arguments to a ``Node`` via its
|
||||
``__init__()``.
|
||||
|
||||
* The ``render()`` method is where the work actually happens.
|
||||
|
||||
* ``render()`` should never raise ``TemplateSyntaxError`` or any other
|
||||
exception. It should fail silently, just as template filters should.
|
||||
|
||||
Ultimately, this decoupling of compilation and rendering results in an
|
||||
efficient template system, because a template can render multiple contexts
|
||||
without having to be parsed multiple times.
|
||||
|
||||
Auto-escaping considerations
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
The output from template tags is **not** automatically run through the
|
||||
auto-escaping filters. However, there are still a couple of things you should
|
||||
keep in mind when writing a template tag.
|
||||
|
||||
If the ``render()`` function of your template stores the result in a context
|
||||
variable (rather than returning the result in a string), it should take care
|
||||
to call ``mark_safe()`` if appropriate. When the variable is ultimately
|
||||
rendered, it will be affected by the auto-escape setting in effect at the
|
||||
time, so content that should be safe from further escaping needs to be marked
|
||||
as such.
|
||||
|
||||
Also, if your template tag creates a new context for performing some
|
||||
sub-rendering, set the auto-escape attribute to the current context's value.
|
||||
The ``__init__`` method for the ``Context`` class takes a parameter called
|
||||
``autoescape`` that you can use for this purpose. For example::
|
||||
|
||||
def render(self, context):
|
||||
# ...
|
||||
new_context = Context({'var': obj}, autoescape=context.autoescape)
|
||||
# ... Do something with new_context ...
|
||||
|
||||
This is not a very common situation, but it's useful if you're rendering a
|
||||
template yourself. For example::
|
||||
|
||||
def render(self, context):
|
||||
t = template.loader.get_template('small_fragment.html')
|
||||
return t.render(Context({'var': obj}, autoescape=context.autoescape))
|
||||
|
||||
If we had neglected to pass in the current ``context.autoescape`` value to our
|
||||
new ``Context`` in this example, the results would have *always* been
|
||||
automatically escaped, which may not be the desired behavior if the template
|
||||
tag is used inside a ``{% autoescape off %}`` block.
|
||||
|
||||
Registering the tag
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Finally, register the tag with your module's ``Library`` instance, as explained
|
||||
in "Writing custom template filters" above. Example::
|
||||
|
||||
register.tag('current_time', do_current_time)
|
||||
|
||||
The ``tag()`` method takes two arguments:
|
||||
|
||||
1. The name of the template tag -- a string. If this is left out, the
|
||||
name of the compilation function will be used.
|
||||
2. The compilation function -- a Python function (not the name of the
|
||||
function as a string).
|
||||
|
||||
As with filter registration, it is also possible to use this as a decorator, in
|
||||
Python 2.4 and above::
|
||||
|
||||
@register.tag(name="current_time")
|
||||
def do_current_time(parser, token):
|
||||
# ...
|
||||
|
||||
@register.tag
|
||||
def shout(parser, token):
|
||||
# ...
|
||||
|
||||
If you leave off the ``name`` argument, as in the second example above, Django
|
||||
will use the function's name as the tag name.
|
||||
|
||||
Passing template variables to the tag
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Although you can pass any number of arguments to a template tag using
|
||||
``token.split_contents()``, the arguments are all unpacked as
|
||||
string literals. A little more work is required in order to pass dynamic
|
||||
content (a template variable) to a template tag as an argument.
|
||||
|
||||
While the previous examples have formatted the current time into a string and
|
||||
returned the string, suppose you wanted to pass in a ``DateTimeField`` from an
|
||||
object and have the template tag format that date-time:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
<p>This post was last updated at {% format_time blog_entry.date_updated "%Y-%m-%d %I:%M %p" %}.</p>
|
||||
|
||||
Initially, ``token.split_contents()`` will return three values:
|
||||
|
||||
1. The tag name ``format_time``.
|
||||
2. The string "blog_entry.date_updated" (without the surrounding quotes).
|
||||
3. The formatting string "%Y-%m-%d %I:%M %p". The return value from
|
||||
``split_contents()`` will include the leading and trailing quotes for
|
||||
string literals like this.
|
||||
|
||||
Now your tag should begin to look like this::
|
||||
|
||||
from django import template
|
||||
def do_format_time(parser, token):
|
||||
try:
|
||||
# split_contents() knows not to split quoted strings.
|
||||
tag_name, date_to_be_formatted, format_string = token.split_contents()
|
||||
except ValueError:
|
||||
raise template.TemplateSyntaxError, "%r tag requires exactly two arguments" % token.contents.split()[0]
|
||||
if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
|
||||
raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name
|
||||
return FormatTimeNode(date_to_be_formatted, format_string[1:-1])
|
||||
|
||||
You also have to change the renderer to retrieve the actual contents of the
|
||||
``date_updated`` property of the ``blog_entry`` object. This can be
|
||||
accomplished by using the ``resolve_variable()`` function in
|
||||
``django.template``. You pass ``resolve_variable()`` the variable name and the
|
||||
current context, available in the ``render`` method::
|
||||
|
||||
from django import template
|
||||
from django.template import resolve_variable
|
||||
import datetime
|
||||
class FormatTimeNode(template.Node):
|
||||
def __init__(self, date_to_be_formatted, format_string):
|
||||
self.date_to_be_formatted = date_to_be_formatted
|
||||
self.format_string = format_string
|
||||
|
||||
def render(self, context):
|
||||
try:
|
||||
actual_date = resolve_variable(self.date_to_be_formatted, context)
|
||||
return actual_date.strftime(self.format_string)
|
||||
except template.VariableDoesNotExist:
|
||||
return ''
|
||||
|
||||
``resolve_variable`` will try to resolve ``blog_entry.date_updated`` and then
|
||||
format it accordingly.
|
||||
|
||||
.. admonition:: New in development version:
|
||||
|
||||
Variable resolution has changed in the development version of Django.
|
||||
``template.resolve_variable()`` is still available, but has been deprecated
|
||||
in favor of a new ``template.Variable`` class. Using this class will usually
|
||||
be more efficient than calling ``template.resolve_variable``
|
||||
|
||||
To use the ``Variable`` class, simply instantiate it with the name of the
|
||||
variable to be resolved, and then call ``variable.resolve(context)``. So,
|
||||
in the development version, the above example would be more correctly
|
||||
written as:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
class FormatTimeNode(template.Node):
|
||||
def __init__(self, date_to_be_formatted, format_string):
|
||||
self.date_to_be_formatted = **Variable(date_to_be_formatted)**
|
||||
self.format_string = format_string
|
||||
|
||||
def render(self, context):
|
||||
try:
|
||||
actual_date = **self.date_to_be_formatted.resolve(context)**
|
||||
return actual_date.strftime(self.format_string)
|
||||
except template.VariableDoesNotExist:
|
||||
return ''
|
||||
|
||||
Changes are highlighted in bold.
|
||||
|
||||
Variable resolution will throw a ``VariableDoesNotExist`` exception if it cannot
|
||||
resolve the string passed to it in the current context of the page.
|
||||
|
||||
Shortcut for simple tags
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Many template tags take a number of arguments -- strings or a template variables
|
||||
-- and return a string after doing some processing based solely on
|
||||
the input argument and some external information. For example, the
|
||||
``current_time`` tag we wrote above is of this variety: we give it a format
|
||||
string, it returns the time as a string.
|
||||
|
||||
To ease the creation of the types of tags, Django provides a helper function,
|
||||
``simple_tag``. This function, which is a method of
|
||||
``django.template.Library``, takes a function that accepts any number of
|
||||
arguments, wraps it in a ``render`` function and the other necessary bits
|
||||
mentioned above and registers it with the template system.
|
||||
|
||||
Our earlier ``current_time`` function could thus be written like this::
|
||||
|
||||
def current_time(format_string):
|
||||
return datetime.datetime.now().strftime(format_string)
|
||||
|
||||
register.simple_tag(current_time)
|
||||
|
||||
In Python 2.4, the decorator syntax also works::
|
||||
|
||||
@register.simple_tag
|
||||
def current_time(format_string):
|
||||
...
|
||||
|
||||
A couple of things to note about the ``simple_tag`` helper function:
|
||||
|
||||
* Checking for the required number of arguments, etc., has already been
|
||||
done by the time our function is called, so we don't need to do that.
|
||||
* The quotes around the argument (if any) have already been stripped away,
|
||||
so we just receive a plain string.
|
||||
* If the argument was a template variable, our function is passed the
|
||||
current value of the variable, not the variable itself.
|
||||
|
||||
When your template tag does not need access to the current context, writing a
|
||||
function to work with the input values and using the ``simple_tag`` helper is
|
||||
the easiest way to create a new tag.
|
||||
|
||||
Inclusion tags
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Another common type of template tag is the type that displays some data by
|
||||
rendering *another* template. For example, Django's admin interface uses custom
|
||||
template tags to display the buttons along the bottom of the "add/change" form
|
||||
pages. Those buttons always look the same, but the link targets change depending
|
||||
on the object being edited -- so they're a perfect case for using a small
|
||||
template that is filled with details from the current object. (In the admin's
|
||||
case, this is the ``submit_row`` tag.)
|
||||
|
||||
These sorts of tags are called "inclusion tags".
|
||||
|
||||
Writing inclusion tags is probably best demonstrated by example. Let's write a
|
||||
tag that outputs a list of choices for a given ``Poll`` object, such as was
|
||||
created in the :ref:`tutorials <creating-models>`. We'll use the tag like this:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{% show_results poll %}
|
||||
|
||||
...and the output will be something like this:
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<ul>
|
||||
<li>First choice</li>
|
||||
<li>Second choice</li>
|
||||
<li>Third choice</li>
|
||||
</ul>
|
||||
|
||||
First, define the function that takes the argument and produces a dictionary of
|
||||
data for the result. The important point here is we only need to return a
|
||||
dictionary, not anything more complex. This will be used as a template context
|
||||
for the template fragment. Example::
|
||||
|
||||
def show_results(poll):
|
||||
choices = poll.choice_set.all()
|
||||
return {'choices': choices}
|
||||
|
||||
Next, create the template used to render the tag's output. This template is a
|
||||
fixed feature of the tag: the tag writer specifies it, not the template
|
||||
designer. Following our example, the template is very simple:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
<ul>
|
||||
{% for choice in choices %}
|
||||
<li> {{ choice }} </li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
Now, create and register the inclusion tag by calling the ``inclusion_tag()``
|
||||
method on a ``Library`` object. Following our example, if the above template is
|
||||
in a file called ``results.html`` in a directory that's searched by the template
|
||||
loader, we'd register the tag like this::
|
||||
|
||||
# Here, register is a django.template.Library instance, as before
|
||||
register.inclusion_tag('results.html')(show_results)
|
||||
|
||||
As always, Python 2.4 decorator syntax works as well, so we could have
|
||||
written::
|
||||
|
||||
@register.inclusion_tag('results.html')
|
||||
def show_results(poll):
|
||||
...
|
||||
|
||||
...when first creating the function.
|
||||
|
||||
Sometimes, your inclusion tags might require a large number of arguments,
|
||||
making it a pain for template authors to pass in all the arguments and remember
|
||||
their order. To solve this, Django provides a ``takes_context`` option for
|
||||
inclusion tags. If you specify ``takes_context`` in creating a template tag,
|
||||
the tag will have no required arguments, and the underlying Python function
|
||||
will have one argument -- the template context as of when the tag was called.
|
||||
|
||||
For example, say you're writing an inclusion tag that will always be used in a
|
||||
context that contains ``home_link`` and ``home_title`` variables that point
|
||||
back to the main page. Here's what the Python function would look like::
|
||||
|
||||
# The first argument *must* be called "context" here.
|
||||
def jump_link(context):
|
||||
return {
|
||||
'link': context['home_link'],
|
||||
'title': context['home_title'],
|
||||
}
|
||||
# Register the custom tag as an inclusion tag with takes_context=True.
|
||||
register.inclusion_tag('link.html', takes_context=True)(jump_link)
|
||||
|
||||
(Note that the first parameter to the function *must* be called ``context``.)
|
||||
|
||||
In that ``register.inclusion_tag()`` line, we specified ``takes_context=True``
|
||||
and the name of the template. Here's what the template ``link.html`` might look
|
||||
like:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
Jump directly to <a href="{{ link }}">{{ title }}</a>.
|
||||
|
||||
Then, any time you want to use that custom tag, load its library and call it
|
||||
without any arguments, like so::
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{% jump_link %}
|
||||
|
||||
Note that when you're using ``takes_context=True``, there's no need to pass
|
||||
arguments to the template tag. It automatically gets access to the context.
|
||||
|
||||
The ``takes_context`` parameter defaults to ``False``. When it's set to *True*,
|
||||
the tag is passed the context object, as in this example. That's the only
|
||||
difference between this case and the previous ``inclusion_tag`` example.
|
||||
|
||||
Setting a variable in the context
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The above example simply output a value. Generally, it's more flexible if your
|
||||
template tags set template variables instead of outputting values. That way,
|
||||
template authors can reuse the values that your template tags create.
|
||||
|
||||
To set a variable in the context, just use dictionary assignment on the context
|
||||
object in the ``render()`` method. Here's an updated version of
|
||||
``CurrentTimeNode`` that sets a template variable ``current_time`` instead of
|
||||
outputting it::
|
||||
|
||||
class CurrentTimeNode2(template.Node):
|
||||
def __init__(self, format_string):
|
||||
self.format_string = format_string
|
||||
def render(self, context):
|
||||
context['current_time'] = datetime.datetime.now().strftime(self.format_string)
|
||||
return ''
|
||||
|
||||
Note that ``render()`` returns the empty string. ``render()`` should always
|
||||
return string output. If all the template tag does is set a variable,
|
||||
``render()`` should return the empty string.
|
||||
|
||||
Here's how you'd use this new version of the tag:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{% current_time "%Y-%M-%d %I:%M %p" %}<p>The time is {{ current_time }}.</p>
|
||||
|
||||
But, there's a problem with ``CurrentTimeNode2``: The variable name
|
||||
``current_time`` is hard-coded. This means you'll need to make sure your
|
||||
template doesn't use ``{{ current_time }}`` anywhere else, because the
|
||||
``{% current_time %}`` will blindly overwrite that variable's value. A cleaner
|
||||
solution is to make the template tag specify the name of the output variable,
|
||||
like so:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{% get_current_time "%Y-%M-%d %I:%M %p" as my_current_time %}
|
||||
<p>The current time is {{ my_current_time }}.</p>
|
||||
|
||||
To do that, you'll need to refactor both the compilation function and ``Node``
|
||||
class, like so::
|
||||
|
||||
class CurrentTimeNode3(template.Node):
|
||||
def __init__(self, format_string, var_name):
|
||||
self.format_string = format_string
|
||||
self.var_name = var_name
|
||||
def render(self, context):
|
||||
context[self.var_name] = datetime.datetime.now().strftime(self.format_string)
|
||||
return ''
|
||||
|
||||
import re
|
||||
def do_current_time(parser, token):
|
||||
# This version uses a regular expression to parse tag contents.
|
||||
try:
|
||||
# Splitting by None == splitting by spaces.
|
||||
tag_name, arg = token.contents.split(None, 1)
|
||||
except ValueError:
|
||||
raise template.TemplateSyntaxError, "%r tag requires arguments" % token.contents.split()[0]
|
||||
m = re.search(r'(.*?) as (\w+)', arg)
|
||||
if not m:
|
||||
raise template.TemplateSyntaxError, "%r tag had invalid arguments" % tag_name
|
||||
format_string, var_name = m.groups()
|
||||
if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
|
||||
raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name
|
||||
return CurrentTimeNode3(format_string[1:-1], var_name)
|
||||
|
||||
The difference here is that ``do_current_time()`` grabs the format string and
|
||||
the variable name, passing both to ``CurrentTimeNode3``.
|
||||
|
||||
Parsing until another block tag
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Template tags can work in tandem. For instance, the standard ``{% comment %}``
|
||||
tag hides everything until ``{% endcomment %}``. To create a template tag such
|
||||
as this, use ``parser.parse()`` in your compilation function.
|
||||
|
||||
Here's how the standard ``{% comment %}`` tag is implemented::
|
||||
|
||||
def do_comment(parser, token):
|
||||
nodelist = parser.parse(('endcomment',))
|
||||
parser.delete_first_token()
|
||||
return CommentNode()
|
||||
|
||||
class CommentNode(template.Node):
|
||||
def render(self, context):
|
||||
return ''
|
||||
|
||||
``parser.parse()`` takes a tuple of names of block tags ''to parse until''. It
|
||||
returns an instance of ``django.template.NodeList``, which is a list of
|
||||
all ``Node`` objects that the parser encountered ''before'' it encountered
|
||||
any of the tags named in the tuple.
|
||||
|
||||
In ``"nodelist = parser.parse(('endcomment',))"`` in the above example,
|
||||
``nodelist`` is a list of all nodes between the ``{% comment %}`` and
|
||||
``{% endcomment %}``, not counting ``{% comment %}`` and ``{% endcomment %}``
|
||||
themselves.
|
||||
|
||||
After ``parser.parse()`` is called, the parser hasn't yet "consumed" the
|
||||
``{% endcomment %}`` tag, so the code needs to explicitly call
|
||||
``parser.delete_first_token()``.
|
||||
|
||||
``CommentNode.render()`` simply returns an empty string. Anything between
|
||||
``{% comment %}`` and ``{% endcomment %}`` is ignored.
|
||||
|
||||
Parsing until another block tag, and saving contents
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In the previous example, ``do_comment()`` discarded everything between
|
||||
``{% comment %}`` and ``{% endcomment %}``. Instead of doing that, it's
|
||||
possible to do something with the code between block tags.
|
||||
|
||||
For example, here's a custom template tag, ``{% upper %}``, that capitalizes
|
||||
everything between itself and ``{% endupper %}``.
|
||||
|
||||
Usage:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{% upper %}This will appear in uppercase, {{ your_name }}.{% endupper %}
|
||||
|
||||
As in the previous example, we'll use ``parser.parse()``. But this time, we
|
||||
pass the resulting ``nodelist`` to the ``Node``::
|
||||
|
||||
def do_upper(parser, token):
|
||||
nodelist = parser.parse(('endupper',))
|
||||
parser.delete_first_token()
|
||||
return UpperNode(nodelist)
|
||||
|
||||
class UpperNode(template.Node):
|
||||
def __init__(self, nodelist):
|
||||
self.nodelist = nodelist
|
||||
def render(self, context):
|
||||
output = self.nodelist.render(context)
|
||||
return output.upper()
|
||||
|
||||
The only new concept here is the ``self.nodelist.render(context)`` in
|
||||
``UpperNode.render()``.
|
||||
|
||||
For more examples of complex rendering, see the source code for ``{% if %}``,
|
||||
``{% for %}``, ``{% ifequal %}`` and ``{% ifchanged %}``. They live in
|
||||
``django/template/defaulttags.py``.
|
||||
383
docs/howto/deployment/fastcgi.txt
Normal file
383
docs/howto/deployment/fastcgi.txt
Normal file
@@ -0,0 +1,383 @@
|
||||
.. _howto-deployment-fastcgi:
|
||||
|
||||
===========================================
|
||||
How to use Django with FastCGI, SCGI or AJP
|
||||
===========================================
|
||||
|
||||
.. highlight:: bash
|
||||
|
||||
Although the current preferred setup for running Django is :ref:`Apache with
|
||||
mod_python <howto-deployment-modpython>`, many people use shared hosting, on
|
||||
which protocols such as FastCGI, SCGI or AJP are the only viable options. In
|
||||
some setups, these protocols also allow better security -- and, possibly, better
|
||||
performance -- than mod_python_.
|
||||
|
||||
.. admonition:: Note
|
||||
|
||||
This document primarily focuses on FastCGI. Other protocols, such as SCGI
|
||||
and AJP, are also supported, through the ``flup`` Python package. See the
|
||||
Protocols_ section below for specifics about SCGI and AJP.
|
||||
|
||||
Essentially, FastCGI is an efficient way of letting an external application
|
||||
serve pages to a Web server. The Web server delegates the incoming Web requests
|
||||
(via a socket) to FastCGI, which executes the code and passes the response back
|
||||
to the Web server, which, in turn, passes it back to the client's Web browser.
|
||||
|
||||
Like mod_python, FastCGI allows code to stay in memory, allowing requests to be
|
||||
served with no startup time. Unlike mod_python_ (or `mod_perl`_), a FastCGI
|
||||
process doesn't run inside the Web server process, but in a separate,
|
||||
persistent process.
|
||||
|
||||
.. _mod_python: http://www.modpython.org/
|
||||
.. _mod_perl: http://perl.apache.org/
|
||||
|
||||
.. admonition:: Why run code in a separate process?
|
||||
|
||||
The traditional ``mod_*`` arrangements in Apache embed various scripting
|
||||
languages (most notably PHP, Python and Perl) inside the process space of
|
||||
your Web server. Although this lowers startup time -- because code doesn't
|
||||
have to be read off disk for every request -- it comes at the cost of
|
||||
memory use. For mod_python, for example, every Apache process gets its own
|
||||
Python interpreter, which uses up a considerable amount of RAM.
|
||||
|
||||
Due to the nature of FastCGI, it's even possible to have processes that run
|
||||
under a different user account than the Web server process. That's a nice
|
||||
security benefit on shared systems, because it means you can secure your
|
||||
code from other users.
|
||||
|
||||
Prerequisite: flup
|
||||
==================
|
||||
|
||||
Before you can start using FastCGI with Django, you'll need to install flup_, a
|
||||
Python library for dealing with FastCGI. Version 0.5 or newer should work fine.
|
||||
|
||||
.. _flup: http://www.saddi.com/software/flup/
|
||||
|
||||
Starting your FastCGI server
|
||||
============================
|
||||
|
||||
FastCGI operates on a client-server model, and in most cases you'll be starting
|
||||
the FastCGI process on your own. Your Web server (be it Apache, lighttpd, or
|
||||
otherwise) only contacts your Django-FastCGI process when the server needs a
|
||||
dynamic page to be loaded. Because the daemon is already running with the code
|
||||
in memory, it's able to serve the response very quickly.
|
||||
|
||||
.. admonition:: Note
|
||||
|
||||
If you're on a shared hosting system, you'll probably be forced to use
|
||||
Web server-managed FastCGI processes. See the section below on running
|
||||
Django with Web server-managed processes for more information.
|
||||
|
||||
A Web server can connect to a FastCGI server in one of two ways: It can use
|
||||
either a Unix domain socket (a "named pipe" on Win32 systems), or it can use a
|
||||
TCP socket. What you choose is a manner of preference; a TCP socket is usually
|
||||
easier due to permissions issues.
|
||||
|
||||
To start your server, first change into the directory of your project (wherever
|
||||
your :ref:`manage.py <ref-django-admin>` is), and then run the
|
||||
:djadmin:`runfcgi` command::
|
||||
|
||||
./manage.py runfcgi [options]
|
||||
|
||||
If you specify ``help`` as the only option after :djadmin:`runfcgi`, it'll
|
||||
display a list of all the available options.
|
||||
|
||||
You'll need to specify either a ``socket``, a ``protocol`` or both ``host`` and
|
||||
``port``. Then, when you set up your Web server, you'll just need to point it at
|
||||
the host/port or socket you specified when starting the FastCGI server. See the
|
||||
examples_, below.
|
||||
|
||||
Protocols
|
||||
---------
|
||||
|
||||
Django supports all the protocols that flup_ does, namely fastcgi_, `SCGI`_ and
|
||||
`AJP1.3`_ (the Apache JServ Protocol, version 1.3). Select your preferred
|
||||
protocol by using the ``protocol=<protocol_name>`` option with ``./manage.py
|
||||
runfcgi`` -- where ``<protocol_name>`` may be one of: ``fcgi`` (the default),
|
||||
``scgi`` or ``ajp``. For example::
|
||||
|
||||
./manage.py runfcgi protocol=scgi
|
||||
|
||||
.. _flup: http://www.saddi.com/software/flup/
|
||||
.. _fastcgi: http://www.fastcgi.com/
|
||||
.. _SCGI: http://python.ca/scgi/protocol.txt
|
||||
.. _AJP1.3: http://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Running a threaded server on a TCP port::
|
||||
|
||||
./manage.py runfcgi method=threaded host=127.0.0.1 port=3033
|
||||
|
||||
Running a preforked server on a Unix domain socket::
|
||||
|
||||
./manage.py runfcgi method=prefork socket=/home/user/mysite.sock pidfile=django.pid
|
||||
|
||||
Run without daemonizing (backgrounding) the process (good for debugging)::
|
||||
|
||||
./manage.py runfcgi daemonize=false socket=/tmp/mysite.sock maxrequests=1
|
||||
|
||||
Stopping the FastCGI daemon
|
||||
---------------------------
|
||||
|
||||
If you have the process running in the foreground, it's easy enough to stop it:
|
||||
Simply hitting ``Ctrl-C`` will stop and quit the FastCGI server. However, when
|
||||
you're dealing with background processes, you'll need to resort to the Unix
|
||||
``kill`` command.
|
||||
|
||||
If you specify the ``pidfile`` option to :djadmin:`runfcgi`, you can kill the
|
||||
running FastCGI daemon like this::
|
||||
|
||||
kill `cat $PIDFILE`
|
||||
|
||||
...where ``$PIDFILE`` is the ``pidfile`` you specified.
|
||||
|
||||
To easily restart your FastCGI daemon on Unix, try this small shell script::
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
# Replace these three settings.
|
||||
PROJDIR="/home/user/myproject"
|
||||
PIDFILE="$PROJDIR/mysite.pid"
|
||||
SOCKET="$PROJDIR/mysite.sock"
|
||||
|
||||
cd $PROJDIR
|
||||
if [ -f $PIDFILE ]; then
|
||||
kill `cat -- $PIDFILE`
|
||||
rm -f -- $PIDFILE
|
||||
fi
|
||||
|
||||
exec /usr/bin/env - \
|
||||
PYTHONPATH="../python:.." \
|
||||
./manage.py runfcgi socket=$SOCKET pidfile=$PIDFILE
|
||||
|
||||
Apache setup
|
||||
============
|
||||
|
||||
To use Django with Apache and FastCGI, you'll need Apache installed and
|
||||
configured, with `mod_fastcgi`_ installed and enabled. Consult the Apache
|
||||
documentation for instructions.
|
||||
|
||||
Once you've got that set up, point Apache at your Django FastCGI instance by
|
||||
editing the ``httpd.conf`` (Apache configuration) file. You'll need to do two
|
||||
things:
|
||||
|
||||
* Use the ``FastCGIExternalServer`` directive to specify the location of
|
||||
your FastCGI server.
|
||||
* Use ``mod_rewrite`` to point URLs at FastCGI as appropriate.
|
||||
|
||||
.. _mod_fastcgi: http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html
|
||||
|
||||
Specifying the location of the FastCGI server
|
||||
---------------------------------------------
|
||||
|
||||
The ``FastCGIExternalServer`` directive tells Apache how to find your FastCGI
|
||||
server. As the `FastCGIExternalServer docs`_ explain, you can specify either a
|
||||
``socket`` or a ``host``. Here are examples of both:
|
||||
|
||||
.. code-block:: apache
|
||||
|
||||
# Connect to FastCGI via a socket / named pipe.
|
||||
FastCGIExternalServer /home/user/public_html/mysite.fcgi -socket /home/user/mysite.sock
|
||||
|
||||
# Connect to FastCGI via a TCP host/port.
|
||||
FastCGIExternalServer /home/user/public_html/mysite.fcgi -host 127.0.0.1:3033
|
||||
|
||||
In either case, the file ``/home/user/public_html/mysite.fcgi`` doesn't
|
||||
actually have to exist. It's just a URL used by the Web server internally -- a
|
||||
hook for signifying which requests at a URL should be handled by FastCGI. (More
|
||||
on this in the next section.)
|
||||
|
||||
.. _FastCGIExternalServer docs: http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html#FastCgiExternalServer
|
||||
|
||||
Using mod_rewrite to point URLs at FastCGI
|
||||
------------------------------------------
|
||||
|
||||
The second step is telling Apache to use FastCGI for URLs that match a certain
|
||||
pattern. To do this, use the `mod_rewrite`_ module and rewrite URLs to
|
||||
``mysite.fcgi`` (or whatever you specified in the ``FastCGIExternalServer``
|
||||
directive, as explained in the previous section).
|
||||
|
||||
In this example, we tell Apache to use FastCGI to handle any request that
|
||||
doesn't represent a file on the filesystem and doesn't start with ``/media/``.
|
||||
This is probably the most common case, if you're using Django's admin site:
|
||||
|
||||
.. code-block:: apache
|
||||
|
||||
<VirtualHost 12.34.56.78>
|
||||
ServerName example.com
|
||||
DocumentRoot /home/user/public_html
|
||||
Alias /media /home/user/python/django/contrib/admin/media
|
||||
RewriteEngine On
|
||||
RewriteRule ^/(media.*)$ /$1 [QSA,L,PT]
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L]
|
||||
</VirtualHost>
|
||||
|
||||
.. _mod_rewrite: http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html
|
||||
|
||||
Django will automatically use the pre-rewrite version of the URL when
|
||||
constructing URLs with the ``{% url %}`` template tag (and similar methods).
|
||||
|
||||
lighttpd setup
|
||||
==============
|
||||
|
||||
lighttpd_ is a lightweight Web server commonly used for serving static files. It
|
||||
supports FastCGI natively and, thus, is a good choice for serving both static
|
||||
and dynamic pages, if your site doesn't have any Apache-specific needs.
|
||||
|
||||
.. _lighttpd: http://www.lighttpd.net/
|
||||
|
||||
Make sure ``mod_fastcgi`` is in your modules list, somewhere after
|
||||
``mod_rewrite`` and ``mod_access``, but not after ``mod_accesslog``. You'll
|
||||
probably want ``mod_alias`` as well, for serving admin media.
|
||||
|
||||
Add the following to your lighttpd config file:
|
||||
|
||||
.. code-block:: lua
|
||||
|
||||
server.document-root = "/home/user/public_html"
|
||||
fastcgi.server = (
|
||||
"/mysite.fcgi" => (
|
||||
"main" => (
|
||||
# Use host / port instead of socket for TCP fastcgi
|
||||
# "host" => "127.0.0.1",
|
||||
# "port" => 3033,
|
||||
"socket" => "/home/user/mysite.sock",
|
||||
"check-local" => "disable",
|
||||
)
|
||||
),
|
||||
)
|
||||
alias.url = (
|
||||
"/media/" => "/home/user/django/contrib/admin/media/",
|
||||
)
|
||||
|
||||
url.rewrite-once = (
|
||||
"^(/media.*)$" => "$1",
|
||||
"^/favicon\.ico$" => "/media/favicon.ico",
|
||||
"^(/.*)$" => "/mysite.fcgi$1",
|
||||
)
|
||||
|
||||
Running multiple Django sites on one lighttpd
|
||||
---------------------------------------------
|
||||
|
||||
lighttpd lets you use "conditional configuration" to allow configuration to be
|
||||
customized per host. To specify multiple FastCGI sites, just add a conditional
|
||||
block around your FastCGI config for each site::
|
||||
|
||||
# If the hostname is 'www.example1.com'...
|
||||
$HTTP["host"] == "www.example1.com" {
|
||||
server.document-root = "/foo/site1"
|
||||
fastcgi.server = (
|
||||
...
|
||||
)
|
||||
...
|
||||
}
|
||||
|
||||
# If the hostname is 'www.example2.com'...
|
||||
$HTTP["host"] == "www.example2.com" {
|
||||
server.document-root = "/foo/site2"
|
||||
fastcgi.server = (
|
||||
...
|
||||
)
|
||||
...
|
||||
}
|
||||
|
||||
You can also run multiple Django installations on the same site simply by
|
||||
specifying multiple entries in the ``fastcgi.server`` directive. Add one
|
||||
FastCGI host for each.
|
||||
|
||||
Running Django on a shared-hosting provider with Apache
|
||||
=======================================================
|
||||
|
||||
Many shared-hosting providers don't allow you to run your own server daemons or
|
||||
edit the ``httpd.conf`` file. In these cases, it's still possible to run Django
|
||||
using Web server-spawned processes.
|
||||
|
||||
.. admonition:: Note
|
||||
|
||||
If you're using Web server-spawned processes, as explained in this section,
|
||||
there's no need for you to start the FastCGI server on your own. Apache
|
||||
will spawn a number of processes, scaling as it needs to.
|
||||
|
||||
In your Web root directory, add this to a file named ``.htaccess``:
|
||||
|
||||
.. code-block:: apache
|
||||
|
||||
AddHandler fastcgi-script .fcgi
|
||||
RewriteEngine On
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^(.*)$ mysite.fcgi/$1 [QSA,L]
|
||||
|
||||
Then, create a small script that tells Apache how to spawn your FastCGI
|
||||
program. Create a file ``mysite.fcgi`` and place it in your Web directory, and
|
||||
be sure to make it executable:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
#!/usr/bin/python
|
||||
import sys, os
|
||||
|
||||
# Add a custom Python path.
|
||||
sys.path.insert(0, "/home/user/python")
|
||||
|
||||
# Switch to the directory of your project. (Optional.)
|
||||
# os.chdir("/home/user/myproject")
|
||||
|
||||
# Set the DJANGO_SETTINGS_MODULE environment variable.
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = "myproject.settings"
|
||||
|
||||
from django.core.servers.fastcgi import runfastcgi
|
||||
runfastcgi(method="threaded", daemonize="false")
|
||||
|
||||
Restarting the spawned server
|
||||
-----------------------------
|
||||
|
||||
If you change any Python code on your site, you'll need to tell FastCGI the
|
||||
code has changed. But there's no need to restart Apache in this case. Rather,
|
||||
just reupload ``mysite.fcgi``, or edit the file, so that the timestamp on the
|
||||
file will change. When Apache sees the file has been updated, it will restart
|
||||
your Django application for you.
|
||||
|
||||
If you have access to a command shell on a Unix system, you can accomplish this
|
||||
easily by using the ``touch`` command::
|
||||
|
||||
touch mysite.fcgi
|
||||
|
||||
Serving admin media files
|
||||
=========================
|
||||
|
||||
Regardless of the server and configuration you eventually decide to use, you
|
||||
will also need to give some thought to how to serve the admin media files. The
|
||||
advice given in the :ref:`modpython <serving-the-admin-files>` documentation
|
||||
is also applicable in the setups detailed above.
|
||||
|
||||
Forcing the URL prefix to a particular value
|
||||
============================================
|
||||
|
||||
Because many of these fastcgi-based solutions require rewriting the URL at
|
||||
some point inside the webserver, the path information that Django sees may not
|
||||
resemble the original URL that was passed in. This is a problem if the Django
|
||||
application is being served from under a particular prefix and you want your
|
||||
URLs from the ``{% url %}`` tag to look like the prefix, rather than the
|
||||
rewritten version, which might contain, for example, ``mysite.fcgi``.
|
||||
|
||||
Django makes a good attempt to work out what the real script name prefix
|
||||
should be. In particular, if the webserver sets the ``SCRIPT_URL`` (specific
|
||||
to Apache's mod_rewrite), or ``REDIRECT_URL`` (set by a few servers, including
|
||||
Apache + mod_rewrite in some situations), Django will work out the original
|
||||
prefix automatically.
|
||||
|
||||
In the cases where Django cannot work out the prefix correctly and where you
|
||||
want the original value to be used in URLs, you can set the
|
||||
``FORCE_SCRIPT_NAME`` setting in your main ``settings`` file. This sets the
|
||||
script name uniformly for every URL served via that settings file. Thus you'll
|
||||
need to use different settings files if you want different sets of URLs to
|
||||
have different script names in this case, but that is a rare situation.
|
||||
|
||||
As an example of how to use it, if your Django configuration is serving all of
|
||||
the URLs under ``'/'`` and you wanted to use this setting, you would set
|
||||
``FORCE_SCRIPT_NAME = ''`` in your settings file.
|
||||
|
||||
|
||||
33
docs/howto/deployment/index.txt
Normal file
33
docs/howto/deployment/index.txt
Normal file
@@ -0,0 +1,33 @@
|
||||
.. _howto-deployment-index:
|
||||
|
||||
Deploying Django
|
||||
================
|
||||
|
||||
Django's chock-full of shortcuts to make web developer's lives easier, but all
|
||||
those tools are of no use if you can't easily deploy your sites. Since Django's
|
||||
inception, ease of deployment has been a major goal. There's a number of good
|
||||
ways to easily deploy Django:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
modpython
|
||||
fastcgi
|
||||
|
||||
:ref:`Deploying under mod_python <howto-deployment-modpython>` is the
|
||||
recommended deployment method; start there if you're not sure which path you'd
|
||||
like to go down.
|
||||
|
||||
.. seealso::
|
||||
|
||||
* `Chapter 20 of The Django Book`_ discusses deployment and especially
|
||||
scaling in more detail.
|
||||
|
||||
* `mod_wsgi`_ is a newcomer to the Python deployment world, but it's rapidly
|
||||
gaining traction. Currently there's a few hoops you have to jump through to
|
||||
`use mod_wsgi with Django`_, but mod_wsgi tends to get rave reviews from
|
||||
those who use it.
|
||||
|
||||
.. _chapter 20 of the django book: http://djangobook.com/en/1.0/chapter20/
|
||||
.. _mod_wsgi: http://code.google.com/p/modwsgi/
|
||||
.. _use mod_wsgi with Django: http://code.google.com/p/modwsgi/wiki/IntegrationWithDjango
|
||||
361
docs/howto/deployment/modpython.txt
Normal file
361
docs/howto/deployment/modpython.txt
Normal file
@@ -0,0 +1,361 @@
|
||||
.. _howto-deployment-modpython:
|
||||
|
||||
============================================
|
||||
How to use Django with Apache and mod_python
|
||||
============================================
|
||||
|
||||
.. highlight:: apache
|
||||
|
||||
Apache_ with `mod_python`_ currently is the preferred setup for using Django
|
||||
on a production server.
|
||||
|
||||
mod_python is similar to (and inspired by) `mod_perl`_ : It embeds Python within
|
||||
Apache and loads Python code into memory when the server starts. Code stays in
|
||||
memory throughout the life of an Apache process, which leads to significant
|
||||
performance gains over other server arrangements.
|
||||
|
||||
Django requires Apache 2.x and mod_python 3.x, and you should use Apache's
|
||||
`prefork MPM`_, as opposed to the `worker MPM`_.
|
||||
|
||||
You may also be interested in :ref:`How to use Django with FastCGI, SCGI or AJP
|
||||
<howto-deployment-fastcgi>` (which also covers SCGI and AJP).
|
||||
|
||||
.. _Apache: http://httpd.apache.org/
|
||||
.. _mod_python: http://www.modpython.org/
|
||||
.. _mod_perl: http://perl.apache.org/
|
||||
.. _prefork MPM: http://httpd.apache.org/docs/2.2/mod/prefork.html
|
||||
.. _worker MPM: http://httpd.apache.org/docs/2.2/mod/worker.html
|
||||
|
||||
Basic configuration
|
||||
===================
|
||||
|
||||
To configure Django with mod_python, first make sure you have Apache installed,
|
||||
with the mod_python module activated.
|
||||
|
||||
Then edit your ``httpd.conf`` file and add the following::
|
||||
|
||||
<Location "/mysite/">
|
||||
SetHandler python-program
|
||||
PythonHandler django.core.handlers.modpython
|
||||
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
|
||||
PythonOption django.root /mysite
|
||||
PythonDebug On
|
||||
</Location>
|
||||
|
||||
...and replace ``mysite.settings`` with the Python import path to your Django
|
||||
project's settings file.
|
||||
|
||||
This tells Apache: "Use mod_python for any URL at or under '/mysite/', using the
|
||||
Django mod_python handler." It passes the value of :ref:`DJANGO_SETTINGS_MODULE
|
||||
<django-settings-module>` so mod_python knows which settings to use.
|
||||
|
||||
**New in Django development version:** Because mod_python does not know we are
|
||||
serving this site from underneath the ``/mysite/`` prefix, this value needs to
|
||||
be passed through to the mod_python handler in Django, via the ``PythonOption
|
||||
django.root ...`` line. The value set on that line (the last item) should
|
||||
match the string given in the ``<Location ...>`` directive. The effect of this
|
||||
is that Django will automatically strip the ``/mysite`` string from the front
|
||||
of any URLs before matching them against your ``URLConf`` patterns. If you
|
||||
later move your site to live under ``/mysite2``, you will not have to change
|
||||
anything except the ``django.root`` option in the config file.
|
||||
|
||||
When using ``django.root`` you should make sure that what's left, after the
|
||||
prefix has been removed, begins with a slash. Your URLConf patterns that are
|
||||
expecting an initial slash will then work correctly. In the above example,
|
||||
since we want to send things like ``/mysite/admin/`` to ``/admin/``, we need
|
||||
to remove the string ``/mysite`` from the beginning, so that is the
|
||||
``django.root`` value. It would be an error to use ``/mysite/`` (with a
|
||||
trailing slash) in this case.
|
||||
|
||||
Note that we're using the ``<Location>`` directive, not the ``<Directory>``
|
||||
directive. The latter is used for pointing at places on your filesystem,
|
||||
whereas ``<Location>`` points at places in the URL structure of a Web site.
|
||||
``<Directory>`` would be meaningless here.
|
||||
|
||||
Also, if your Django project is not on the default ``PYTHONPATH`` for your
|
||||
computer, you'll have to tell mod_python where your project can be found:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
<Location "/mysite/">
|
||||
SetHandler python-program
|
||||
PythonHandler django.core.handlers.modpython
|
||||
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
|
||||
PythonOption django.root /mysite
|
||||
PythonDebug On
|
||||
**PythonPath "['/path/to/project'] + sys.path"**
|
||||
</Location>
|
||||
|
||||
The value you use for ``PythonPath`` should include the parent directories of
|
||||
all the modules you are going to import in your application. It should also
|
||||
include the parent directory of the :ref:`DJANGO_SETTINGS_MODULE
|
||||
<django-settings-module>` location. This is exactly the same situation as
|
||||
setting the Python path for interactive usage. Whenever you try to import
|
||||
something, Python will run through all the directories in ``sys.path`` in turn,
|
||||
from first to last, and try to import from each directory until one succeeds.
|
||||
|
||||
An example might make this clearer. Suppose you have some applications under
|
||||
``/usr/local/django-apps/`` (for example, ``/usr/local/django-apps/weblog/`` and
|
||||
so forth), your settings file is at ``/var/www/mysite/settings.py`` and you have
|
||||
specified :ref:`DJANGO_SETTINGS_MODULE <django-settings-module>` as in the above
|
||||
example. In this case, you would need to write your ``PythonPath`` directive
|
||||
as::
|
||||
|
||||
PythonPath "['/usr/local/django-apps/', '/var/www'] + sys.path"
|
||||
|
||||
With this path, ``import weblog`` and ``import mysite.settings`` will both
|
||||
work. If you had ``import blogroll`` in your code somewhere and ``blogroll``
|
||||
lived under the ``weblog/`` directory, you would *also* need to add
|
||||
``/usr/local/django-apps/weblog/`` to your ``PythonPath``. Remember: the
|
||||
**parent directories** of anything you import directly must be on the Python
|
||||
path.
|
||||
|
||||
.. note::
|
||||
|
||||
If you're using Windows, we still recommended that you use forward
|
||||
slashes in the pathnames, even though Windows normally uses the backslash
|
||||
character as its native separator. Apache knows how to convert from the
|
||||
forward slash format to the native format, so this approach is portable and
|
||||
easier to read. (It avoids tricky problems with having to double-escape
|
||||
backslashes.)
|
||||
|
||||
This is valid even on a Windows system::
|
||||
|
||||
PythonPath "['c:/path/to/project'] + sys.path"
|
||||
|
||||
You can also add directives such as ``PythonAutoReload Off`` for performance.
|
||||
See the `mod_python documentation`_ for a full list of options.
|
||||
|
||||
Note that you should set ``PythonDebug Off`` on a production server. If you
|
||||
leave ``PythonDebug On``, your users would see ugly (and revealing) Python
|
||||
tracebacks if something goes wrong within mod_python.
|
||||
|
||||
Restart Apache, and any request to ``/mysite/`` or below will be served by
|
||||
Django. Note that Django's URLconfs won't trim the "/mysite/" -- they get passed
|
||||
the full URL.
|
||||
|
||||
When deploying Django sites on mod_python, you'll need to restart Apache each
|
||||
time you make changes to your Python code.
|
||||
|
||||
Multiple Django installations on the same Apache
|
||||
================================================
|
||||
|
||||
It's entirely possible to run multiple Django installations on the same Apache
|
||||
instance. Just use ``VirtualHost`` for that, like so::
|
||||
|
||||
NameVirtualHost *
|
||||
|
||||
<VirtualHost *>
|
||||
ServerName www.example.com
|
||||
# ...
|
||||
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
|
||||
</VirtualHost>
|
||||
|
||||
<VirtualHost *>
|
||||
ServerName www2.example.com
|
||||
# ...
|
||||
SetEnv DJANGO_SETTINGS_MODULE mysite.other_settings
|
||||
</VirtualHost>
|
||||
|
||||
If you need to put two Django installations within the same ``VirtualHost``,
|
||||
you'll need to take a special precaution to ensure mod_python's cache doesn't
|
||||
mess things up. Use the ``PythonInterpreter`` directive to give different
|
||||
``<Location>`` directives separate interpreters::
|
||||
|
||||
<VirtualHost *>
|
||||
ServerName www.example.com
|
||||
# ...
|
||||
<Location "/something">
|
||||
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
|
||||
PythonInterpreter mysite
|
||||
</Location>
|
||||
|
||||
<Location "/otherthing">
|
||||
SetEnv DJANGO_SETTINGS_MODULE mysite.other_settings
|
||||
PythonInterpreter othersite
|
||||
</Location>
|
||||
</VirtualHost>
|
||||
|
||||
The values of ``PythonInterpreter`` don't really matter, as long as they're
|
||||
different between the two ``Location`` blocks.
|
||||
|
||||
Running a development server with mod_python
|
||||
============================================
|
||||
|
||||
If you use mod_python for your development server, you can avoid the hassle of
|
||||
having to restart the server each time you make code changes. Just set
|
||||
``MaxRequestsPerChild 1`` in your ``httpd.conf`` file to force Apache to reload
|
||||
everything for each request. But don't do that on a production server, or we'll
|
||||
revoke your Django privileges.
|
||||
|
||||
If you're the type of programmer who debugs using scattered ``print``
|
||||
statements, note that ``print`` statements have no effect in mod_python; they
|
||||
don't appear in the Apache log, as one might expect. If you have the need to
|
||||
print debugging information in a mod_python setup, either do this::
|
||||
|
||||
assert False, the_value_i_want_to_see
|
||||
|
||||
Or add the debugging information to the template of your page.
|
||||
|
||||
.. _mod_python documentation: http://modpython.org/live/current/doc-html/directives.html
|
||||
|
||||
.. _serving-media-files:
|
||||
|
||||
Serving media files
|
||||
===================
|
||||
|
||||
Django doesn't serve media files itself; it leaves that job to whichever Web
|
||||
server you choose.
|
||||
|
||||
We recommend using a separate Web server -- i.e., one that's not also running
|
||||
Django -- for serving media. Here are some good choices:
|
||||
|
||||
* lighttpd_
|
||||
* TUX_
|
||||
* A stripped-down version of Apache_
|
||||
|
||||
If, however, you have no option but to serve media files on the same Apache
|
||||
``VirtualHost`` as Django, here's how you can turn off mod_python for a
|
||||
particular part of the site::
|
||||
|
||||
<Location "/media">
|
||||
SetHandler None
|
||||
</Location>
|
||||
|
||||
Just change ``Location`` to the root URL of your media files. You can also use
|
||||
``<LocationMatch>`` to match a regular expression.
|
||||
|
||||
This example sets up Django at the site root but explicitly disables Django for
|
||||
the ``media`` subdirectory and any URL that ends with ``.jpg``, ``.gif`` or
|
||||
``.png``::
|
||||
|
||||
<Location "/">
|
||||
SetHandler python-program
|
||||
PythonHandler django.core.handlers.modpython
|
||||
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
|
||||
</Location>
|
||||
|
||||
<Location "/media">
|
||||
SetHandler None
|
||||
</Location>
|
||||
|
||||
<LocationMatch "\.(jpg|gif|png)$">
|
||||
SetHandler None
|
||||
</LocationMatch>
|
||||
|
||||
|
||||
.. _lighttpd: http://www.lighttpd.net/
|
||||
.. _TUX: http://en.wikipedia.org/wiki/TUX_web_server
|
||||
.. _Apache: http://httpd.apache.org/
|
||||
|
||||
.. _howto-deployment-modpython-serving-the-admin-files:
|
||||
|
||||
.. _serving-the-admin-files:
|
||||
|
||||
Serving the admin files
|
||||
=======================
|
||||
|
||||
Note that the Django development server automagically serves admin media files,
|
||||
but this is not the case when you use any other server arrangement. You're
|
||||
responsible for setting up Apache, or whichever media server you're using, to
|
||||
serve the admin files.
|
||||
|
||||
The admin files live in (:file:`django/contrib/admin/media`) of the Django
|
||||
distribution.
|
||||
|
||||
Here are two recommended approaches:
|
||||
|
||||
1. Create a symbolic link to the admin media files from within your
|
||||
document root. This way, all of your Django-related files -- code **and**
|
||||
templates -- stay in one place, and you'll still be able to ``svn
|
||||
update`` your code to get the latest admin templates, if they change.
|
||||
|
||||
2. Or, copy the admin media files so that they live within your Apache
|
||||
document root.
|
||||
|
||||
Using "eggs" with mod_python
|
||||
============================
|
||||
|
||||
If you installed Django from a Python egg_ or are using eggs in your Django
|
||||
project, some extra configuration is required. Create an extra file in your
|
||||
project (or somewhere else) that contains something like the following:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import os
|
||||
os.environ['PYTHON_EGG_CACHE'] = '/some/directory'
|
||||
|
||||
Here, ``/some/directory`` is a directory that the Apache webserver process can
|
||||
write to. It will be used as the location for any unpacking of code the eggs
|
||||
need to do.
|
||||
|
||||
Then you have to tell mod_python to import this file before doing anything
|
||||
else. This is done using the PythonImport_ directive to mod_python. You need
|
||||
to ensure that you have specified the ``PythonInterpreter`` directive to
|
||||
mod_python as described above__ (you need to do this even if you aren't
|
||||
serving multiple installations in this case). Then add the ``PythonImport``
|
||||
line in the main server configuration (i.e., outside the ``Location`` or
|
||||
``VirtualHost`` sections). For example::
|
||||
|
||||
PythonInterpreter my_django
|
||||
PythonImport /path/to/my/project/file.py my_django
|
||||
|
||||
Note that you can use an absolute path here (or a normal dotted import path),
|
||||
as described in the `mod_python manual`_. We use an absolute path in the
|
||||
above example because if any Python path modifications are required to access
|
||||
your project, they will not have been done at the time the ``PythonImport``
|
||||
line is processed.
|
||||
|
||||
.. _Egg: http://peak.telecommunity.com/DevCenter/PythonEggs
|
||||
.. _PythonImport: http://www.modpython.org/live/current/doc-html/dir-other-pimp.html
|
||||
.. _mod_python manual: PythonImport_
|
||||
__ `Multiple Django installations on the same Apache`_
|
||||
|
||||
Error handling
|
||||
==============
|
||||
|
||||
When you use Apache/mod_python, errors will be caught by Django -- in other
|
||||
words, they won't propagate to the Apache level and won't appear in the Apache
|
||||
``error_log``.
|
||||
|
||||
The exception for this is if something is really wonky in your Django setup. In
|
||||
that case, you'll see an "Internal Server Error" page in your browser and the
|
||||
full Python traceback in your Apache ``error_log`` file. The ``error_log``
|
||||
traceback is spread over multiple lines. (Yes, this is ugly and rather hard to
|
||||
read, but it's how mod_python does things.)
|
||||
|
||||
If you get a segmentation fault
|
||||
===============================
|
||||
|
||||
If Apache causes a segmentation fault, there are two probable causes, neither
|
||||
of which has to do with Django itself.
|
||||
|
||||
1. It may be because your Python code is importing the "pyexpat" module,
|
||||
which may conflict with the version embedded in Apache. For full
|
||||
information, see `Expat Causing Apache Crash`_.
|
||||
|
||||
2. It may be because you're running mod_python and mod_php in the same
|
||||
Apache instance, with MySQL as your database backend. In some cases,
|
||||
this causes a known mod_python issue due to version conflicts in PHP and
|
||||
the Python MySQL backend. There's full information in the
|
||||
`mod_python FAQ entry`_.
|
||||
|
||||
If you continue to have problems setting up mod_python, a good thing to do is
|
||||
get a barebones mod_python site working, without the Django framework. This is
|
||||
an easy way to isolate mod_python-specific problems. `Getting mod_python Working`_
|
||||
details this procedure.
|
||||
|
||||
The next step should be to edit your test code and add an import of any
|
||||
Django-specific code you're using -- your views, your models, your URLconf,
|
||||
your RSS configuration, etc. Put these imports in your test handler function
|
||||
and access your test URL in a browser. If this causes a crash, you've confirmed
|
||||
it's the importing of Django code that causes the problem. Gradually reduce the
|
||||
set of imports until it stops crashing, so as to find the specific module that
|
||||
causes the problem. Drop down further into modules and look into their imports,
|
||||
as necessary.
|
||||
|
||||
.. _Expat Causing Apache Crash: http://www.dscpl.com.au/articles/modpython-006.html
|
||||
.. _mod_python FAQ entry: http://modpython.org/FAQ/faqw.py?req=show&file=faq02.013.htp
|
||||
.. _Getting mod_python Working: http://www.dscpl.com.au/articles/modpython-001.html
|
||||
|
||||
|
||||
65
docs/howto/error-reporting.txt
Normal file
65
docs/howto/error-reporting.txt
Normal file
@@ -0,0 +1,65 @@
|
||||
.. _howto-error-reporting:
|
||||
|
||||
Error reporting via e-mail
|
||||
==========================
|
||||
|
||||
When you're running a public site you should always turn off the
|
||||
:setting:`DEBUG` setting. That will make your server run much faster, and will
|
||||
also prevent malicious users from seeing details of your application that can be
|
||||
revealed by the error pages.
|
||||
|
||||
However, running with :setting:`DEBUG` set to ``False`` means you'll never see
|
||||
errors generated by your site -- everyone will just see your public error pages.
|
||||
You need to keep track of errors that occur in deployed sites, so Django can be
|
||||
configured to email you details of those errors.
|
||||
|
||||
Server errors
|
||||
-------------
|
||||
|
||||
When :setting:`DEBUG` is ``False``, Django will e-mail the users listed in the
|
||||
:setting:`ADMIN` setting whenever your code raises an unhandled exception and
|
||||
results in an internal server error (HTTP status code 500). This gives the
|
||||
administrators immediate notification of any errors. The :setting:`ADMINS` will
|
||||
get a description of the error, a complete Python traceback, and details about
|
||||
the HTTP request that caused the error.
|
||||
|
||||
To disable this behavior, just remove all entries from the :setting:`ADMINS`
|
||||
setting.
|
||||
|
||||
404 errors
|
||||
----------
|
||||
|
||||
Django can also be configured to email errors about broken links (404 "page
|
||||
not found" errors). Django sends emails about 404 errors when:
|
||||
|
||||
* :setting:`DEBUG` is ``False``
|
||||
|
||||
* :setting:`SEND_BROKEN_LINK_EMAILS` is ``True``
|
||||
|
||||
* Your :setting:`MIDDLEWARE_CLASSES` setting includes ``CommonMiddleware``
|
||||
(which it does by default).
|
||||
|
||||
If those conditions are met, Django will e-mail the users listed in the
|
||||
:setting:`MANAGERS` setting whenever your code raises a 404 and the request has
|
||||
a referer. (It doesn't bother to e-mail for 404s that don't have a referer --
|
||||
those are usually just people typing in broken URLs or broken web 'bots).
|
||||
|
||||
You can tell Django to stop reporting particular 404s by tweaking the
|
||||
:setting:`IGNORABLE_404_ENDS` and :setting:`IGNORABLE_404_STARTS` settings. Both
|
||||
should be a tuple of strings. For example::
|
||||
|
||||
IGNORABLE_404_ENDS = ('.php', '.cgi')
|
||||
IGNORABLE_404_STARTS = ('/phpmyadmin/',)
|
||||
|
||||
In this example, a 404 to any URL ending with ``.php`` or ``.cgi`` will *not* be
|
||||
reported. Neither will any URL starting with ``/phpmyadmin/``.
|
||||
|
||||
The best way to disable this behavior is to set
|
||||
:setting:`SEND_BROKEN_LINK_EMAILS` to ``False``.
|
||||
|
||||
.. seealso::
|
||||
|
||||
You can also set up custom error reporting by writing a custom piece of
|
||||
:ref:`exception middleware <exception-middleware>`. If you do write custom
|
||||
error handling, it's a good idea to emulate Django's built-in error handling
|
||||
and only report/log errors if :setting:`DEBUG` is ``False``.
|
||||
33
docs/howto/index.txt
Normal file
33
docs/howto/index.txt
Normal file
@@ -0,0 +1,33 @@
|
||||
.. _howto-index:
|
||||
|
||||
"How-to" guides
|
||||
===============
|
||||
|
||||
Here you'll find short answers to "How do I....?" types of questions. These
|
||||
how-to guides don't cover topics in depth -- you'll find that material in the
|
||||
:ref:`topics-index` and the :ref:`ref-index`. However, these guides will help
|
||||
you quickly accomplish common tasks.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
apache-auth
|
||||
custom-management-commands
|
||||
custom-model-fields
|
||||
custom-template-tags
|
||||
custom-file-storage
|
||||
deployment/index
|
||||
error-reporting
|
||||
initial-data
|
||||
legacy-databases
|
||||
outputting-csv
|
||||
outputting-pdf
|
||||
static-files
|
||||
|
||||
.. seealso::
|
||||
|
||||
The `Django community aggregator`_, where we aggregate content from the
|
||||
global Django community. Many writers in the aggregator write this sort of
|
||||
how-to material.
|
||||
|
||||
.. _django community aggregator: http://www.djangoproject.com/community/
|
||||
140
docs/howto/initial-data.txt
Normal file
140
docs/howto/initial-data.txt
Normal file
@@ -0,0 +1,140 @@
|
||||
.. _howto-initial-data:
|
||||
|
||||
=================================
|
||||
Providing initial data for models
|
||||
=================================
|
||||
|
||||
It's sometimes useful to pre-populate your database with hard-coded data when
|
||||
you're first setting up an app. There's a couple of ways you can have Django
|
||||
automatically create this data: you can provide `initial data via fixtures`_, or
|
||||
you can provide `initial data as SQL`_.
|
||||
|
||||
In general, using a fixture is a cleaner method since it's database-agnostic,
|
||||
but initial SQL is also quite a bit more flexible.
|
||||
|
||||
.. _initial data as sql: `providing initial sql data`_
|
||||
.. _initial data via fixtures: `providing initial data with fixtures`_
|
||||
|
||||
Providing initial data with fixtures
|
||||
====================================
|
||||
|
||||
A fixture is a collection of data that Django knows how to import into a
|
||||
database. The most straightforward way of creating a fixture if you've already
|
||||
got some data is to use the :djadmin:`manage.py dumpdata` command. Or, you can
|
||||
write fixtures by hand; fixtures can be written as XML, YAML, or JSON documents.
|
||||
The :ref:`serialization documentation <topics-serialization>` has more details
|
||||
about each of these supported :ref:`serialization formats
|
||||
<serialization-formats>`.
|
||||
|
||||
As an example, though, here's what a fixture for a simple ``Person`` model might
|
||||
look like in JSON:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
[
|
||||
{
|
||||
"model": "myapp.person",
|
||||
"pk": 1,
|
||||
"fields": {
|
||||
"first_name": "John",
|
||||
"last_name": "Lennon",
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "myapp.person",
|
||||
"pk": 2,
|
||||
"fields": {
|
||||
"first_name": "Paul",
|
||||
"last_name": "McCartney",
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
And here's that same fixture as YAML:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
- model: myapp.person
|
||||
pk: 1
|
||||
fields:
|
||||
first_name: John
|
||||
last_name: Lennon
|
||||
- model: myapp.person
|
||||
pk: 1
|
||||
fields:
|
||||
first_name: Paul
|
||||
last_name: McCartney
|
||||
|
||||
You'll store this data in a ``fixtures`` directory inside you app.
|
||||
|
||||
Loading data is easy: just call :djadmin:`manage.py loaddata fixturename
|
||||
<loaddata>`, where *fixturename* is the name of the fixture file you've created.
|
||||
Every time you run :djadmin:`loaddata` the data will be read from the fixture
|
||||
and re-loaded into the database. Note that this means that if you change one of
|
||||
the rows created by a fixture and the run :djadmin:`loaddata` again you'll wipe
|
||||
out any changes you've made.
|
||||
|
||||
Automatically loading initial data fixtures
|
||||
-------------------------------------------
|
||||
|
||||
If you create a fixture named ``initial_data.[xml/yml/json]``, that fixture will
|
||||
be loaded every time you run :djadmin:`syncdb`. This is extremely convenient,
|
||||
but be careful: remember that the data will be refreshed *every time* you run
|
||||
:djadmin:`syncdb`. So don't use ``initial_data`` for data you'll want to edit.
|
||||
|
||||
.. seealso::
|
||||
|
||||
Fixtures are also used by the :ref:`testing framework
|
||||
<topics-testing-fixtures>` to help set up a consistent test environment.
|
||||
|
||||
.. _initial-sql:
|
||||
|
||||
Providing initial SQL data
|
||||
==========================
|
||||
|
||||
Django provides a hook for passing the database arbitrary SQL that's executed
|
||||
just after the CREATE TABLE statements when you run :djadmin:`syncdb`. You can
|
||||
use this hook to populate default records, or you could also create SQL
|
||||
functions, views, triggers, etc.
|
||||
|
||||
The hook is simple: Django just looks for a file called ``sql/<modelname>.sql``,
|
||||
in your app directory, where ``<modelname>`` is the model's name in lowercase.
|
||||
|
||||
So, if you had a ``Person`` model in an app called ``myapp``, you could add
|
||||
arbitrary SQL to the file ``sql/person.sql`` inside your ``myapp`` directory.
|
||||
Here's an example of what the file might contain:
|
||||
|
||||
.. code-block:: sql
|
||||
|
||||
INSERT INTO myapp_person (first_name, last_name) VALUES ('John', 'Lennon');
|
||||
INSERT INTO myapp_person (first_name, last_name) VALUES ('Paul', 'McCartney');
|
||||
|
||||
Each SQL file, if given, is expected to contain valid SQL statements
|
||||
which will insert the desired data (e.g., properly-formatted
|
||||
``INSERT`` statements separated by semicolons).
|
||||
|
||||
The SQL files are read by the :djadmin:`sqlcustom`, :djadmin:`sqlreset`,
|
||||
:djadmin:`sqlall` and :djadmin:`reset` commands in :ref:`manage.py
|
||||
<ref-django-admin>`. Refer to the :ref:`manage.py documentation
|
||||
<ref-django-admin>` for more information.
|
||||
|
||||
Note that if you have multiple SQL data files, there's no guarantee of the order
|
||||
in which they're executed. The only thing you can assume is that, by the time
|
||||
your custom data files are executed, all the database tables already will have
|
||||
been created.
|
||||
|
||||
Database-backend-specific SQL data
|
||||
----------------------------------
|
||||
|
||||
There's also a hook for backend-specific SQL data. For example, you can have
|
||||
separate initial-data files for PostgreSQL and MySQL. For each app, Django
|
||||
looks for a file called ``<appname>/sql/<modelname>.<backend>.sql``, where
|
||||
``<appname>`` is your app directory, ``<modelname>`` is the model's name in
|
||||
lowercase and ``<backend>`` is the value of :setting:`DATABASE_ENGINE` in your
|
||||
settings file (e.g., ``postgresql``, ``mysql``).
|
||||
|
||||
Backend-specific SQL data is executed before non-backend-specific SQL data. For
|
||||
example, if your app contains the files ``sql/person.sql`` and
|
||||
``sql/person.postgresql.sql`` and you're installing the app on PostgreSQL,
|
||||
Django will execute the contents of ``sql/person.postgresql.sql`` first, then
|
||||
``sql/person.sql``.
|
||||
67
docs/howto/legacy-databases.txt
Normal file
67
docs/howto/legacy-databases.txt
Normal file
@@ -0,0 +1,67 @@
|
||||
.. _howto-legacy-databases:
|
||||
|
||||
=========================================
|
||||
Integrating Django with a legacy database
|
||||
=========================================
|
||||
|
||||
While Django is best suited for developing new applications, it's quite
|
||||
possible to integrate it into legacy databases. Django includes a couple of
|
||||
utilities to automate as much of this process as possible.
|
||||
|
||||
This document assumes you know the Django basics, as covered in the
|
||||
:ref:`tutorial <intro-tutorial01>`.
|
||||
|
||||
Once you've got Django set up, you'll follow this general process to integrate
|
||||
with an existing database.
|
||||
|
||||
Give Django your database parameters
|
||||
====================================
|
||||
|
||||
You'll need to tell Django what your database connection parameters are, and
|
||||
what the name of the database is. Do that by editing these settings in your
|
||||
:ref:`settings file <topics-settings>`:
|
||||
|
||||
* :setting:`DATABASE_NAME`
|
||||
* :setting:`DATABASE_ENGINE`
|
||||
* :setting:`DATABASE_USER`
|
||||
* :setting:`DATABASE_PASSWORD`
|
||||
* :setting:`DATABASE_HOST`
|
||||
* :setting:`DATABASE_PORT`
|
||||
|
||||
Auto-generate the models
|
||||
========================
|
||||
|
||||
.. highlight:: bash
|
||||
|
||||
Django comes with a utility called :djadmin:`inspectdb` that can create models
|
||||
by introspecting an existing database. You can view the output by running this
|
||||
command::
|
||||
|
||||
python manage.py inspectdb
|
||||
|
||||
Save this as a file by using standard Unix output redirection::
|
||||
|
||||
python manage.py inspectdb > models.py
|
||||
|
||||
This feature is meant as a shortcut, not as definitive model generation. See the
|
||||
:djadmin:`documentation of inspectdb <inspectdb>` for more information.
|
||||
|
||||
Once you've cleaned up your models, name the file ``models.py`` and put it in
|
||||
the Python package that holds your app. Then add the app to your
|
||||
:setting:`INSTALLED_APPS` setting.
|
||||
|
||||
Install the core Django tables
|
||||
==============================
|
||||
|
||||
Next, run the :djadmin:`syncdb` command to install any extra needed database
|
||||
records such as admin permissions and content types::
|
||||
|
||||
python manage.py syncdb
|
||||
|
||||
Test and tweak
|
||||
==============
|
||||
|
||||
Those are the basic steps -- from here you'll want to tweak the models Django
|
||||
generated until they work the way you'd like. Try accessing your data via the
|
||||
Django database API, and try editing objects via Django's admin site, and edit
|
||||
the models file accordingly.
|
||||
116
docs/howto/outputting-csv.txt
Normal file
116
docs/howto/outputting-csv.txt
Normal file
@@ -0,0 +1,116 @@
|
||||
.. _howto-outputting-csv:
|
||||
|
||||
==========================
|
||||
Outputting CSV with Django
|
||||
==========================
|
||||
|
||||
This document explains how to output CSV (Comma Separated Values) dynamically
|
||||
using Django views. To do this, you can either use the `Python CSV library`_ or
|
||||
the Django template system.
|
||||
|
||||
.. _Python CSV library: http://www.python.org/doc/current/lib/module-csv.html
|
||||
|
||||
Using the Python CSV library
|
||||
============================
|
||||
|
||||
Python comes with a CSV library, ``csv``. The key to using it with Django is
|
||||
that the ``csv`` module's CSV-creation capability acts on file-like objects, and
|
||||
Django's :class:`~django.http.HttpResponse` objects are file-like objects.
|
||||
|
||||
Here's an example::
|
||||
|
||||
import csv
|
||||
from django.http import HttpResponse
|
||||
|
||||
def some_view(request):
|
||||
# Create the HttpResponse object with the appropriate CSV header.
|
||||
response = HttpResponse(mimetype='text/csv')
|
||||
response['Content-Disposition'] = 'attachment; filename=somefilename.csv'
|
||||
|
||||
writer = csv.writer(response)
|
||||
writer.writerow(['First row', 'Foo', 'Bar', 'Baz'])
|
||||
writer.writerow(['Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"])
|
||||
|
||||
return response
|
||||
|
||||
The code and comments should be self-explanatory, but a few things deserve a
|
||||
mention:
|
||||
|
||||
* The response gets a special MIME type, ``text/csv``. This tells
|
||||
browsers that the document is a CSV file, rather than an HTML file. If
|
||||
you leave this off, browsers will probably interpret the output as HTML,
|
||||
which will result in ugly, scary gobbledygook in the browser window.
|
||||
|
||||
* The response gets an additional ``Content-Disposition`` header, which
|
||||
contains the name of the CSV file. This filename is arbitrary; call it
|
||||
whatever you want. It'll be used by browsers in the "Save as..."
|
||||
dialogue, etc.
|
||||
|
||||
* Hooking into the CSV-generation API is easy: Just pass ``response`` as the
|
||||
first argument to ``csv.writer``. The ``csv.writer`` function expects a
|
||||
file-like object, and :class:`~django.http.HttpResponse` objects fit the
|
||||
bill.
|
||||
|
||||
* For each row in your CSV file, call ``writer.writerow``, passing it an
|
||||
iterable object such as a list or tuple.
|
||||
|
||||
* The CSV module takes care of quoting for you, so you don't have to worry
|
||||
about escaping strings with quotes or commas in them. Just pass
|
||||
``writerow()`` your raw strings, and it'll do the right thing.
|
||||
|
||||
Using the template system
|
||||
=========================
|
||||
|
||||
Alternatively, you can use the :ref:`Django template system <topics-templates>`
|
||||
to generate CSV. This is lower-level than using the convenient CSV, but the
|
||||
solution is presented here for completeness.
|
||||
|
||||
The idea here is to pass a list of items to your template, and have the
|
||||
template output the commas in a :ttag:`for` loop.
|
||||
|
||||
Here's an example, which generates the same CSV file as above::
|
||||
|
||||
from django.http import HttpResponse
|
||||
from django.template import loader, Context
|
||||
|
||||
def some_view(request):
|
||||
# Create the HttpResponse object with the appropriate CSV header.
|
||||
response = HttpResponse(mimetype='text/csv')
|
||||
response['Content-Disposition'] = 'attachment; filename=somefilename.csv'
|
||||
|
||||
# The data is hard-coded here, but you could load it from a database or
|
||||
# some other source.
|
||||
csv_data = (
|
||||
('First row', 'Foo', 'Bar', 'Baz'),
|
||||
('Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"),
|
||||
)
|
||||
|
||||
t = loader.get_template('my_template_name.txt')
|
||||
c = Context({
|
||||
'data': csv_data,
|
||||
})
|
||||
response.write(t.render(c))
|
||||
return response
|
||||
|
||||
The only difference between this example and the previous example is that this
|
||||
one uses template loading instead of the CSV module. The rest of the code --
|
||||
such as the ``mimetype='text/csv'`` -- is the same.
|
||||
|
||||
Then, create the template ``my_template_name.txt``, with this template code:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{% for row in data %}"{{ row.0|addslashes }}", "{{ row.1|addslashes }}", "{{ row.2|addslashes }}", "{{ row.3|addslashes }}", "{{ row.4|addslashes }}"
|
||||
{% endfor %}
|
||||
|
||||
This template is quite basic. It just iterates over the given data and displays
|
||||
a line of CSV for each row. It uses the :tfilter:`addslashes` template filter to
|
||||
ensure there aren't any problems with quotes.
|
||||
|
||||
Other text-based formats
|
||||
========================
|
||||
|
||||
Notice that there isn't very much specific to CSV here -- just the specific
|
||||
output format. You can use either of these techniques to output any text-based
|
||||
format you can dream of. You can also use a similar technique to generate
|
||||
arbitrary binary data; see :ref:`howto-outputting-pdf` for an example.
|
||||
160
docs/howto/outputting-pdf.txt
Normal file
160
docs/howto/outputting-pdf.txt
Normal file
@@ -0,0 +1,160 @@
|
||||
.. _howto-outputting-pdf:
|
||||
|
||||
===========================
|
||||
Outputting PDFs with Django
|
||||
===========================
|
||||
|
||||
This document explains how to output PDF files dynamically using Django views.
|
||||
This is made possible by the excellent, open-source ReportLab_ Python PDF
|
||||
library.
|
||||
|
||||
The advantage of generating PDF files dynamically is that you can create
|
||||
customized PDFs for different purposes -- say, for different users or different
|
||||
pieces of content.
|
||||
|
||||
For example, Django was used at kusports.com_ to generate customized,
|
||||
printer-friendly NCAA tournament brackets, as PDF files, for people
|
||||
participating in a March Madness contest.
|
||||
|
||||
.. _ReportLab: http://www.reportlab.org/rl_toolkit.html
|
||||
.. _kusports.com: http://www.kusports.com/
|
||||
|
||||
Install ReportLab
|
||||
=================
|
||||
|
||||
Download and install the ReportLab library from http://www.reportlab.org/downloads.html.
|
||||
The `user guide`_ (not coincidentally, a PDF file) explains how to install it.
|
||||
|
||||
Test your installation by importing it in the Python interactive interpreter::
|
||||
|
||||
>>> import reportlab
|
||||
|
||||
If that command doesn't raise any errors, the installation worked.
|
||||
|
||||
.. _user guide: http://www.reportlab.com/docs/userguide.pdf
|
||||
|
||||
Write your view
|
||||
===============
|
||||
|
||||
The key to generating PDFs dynamically with Django is that the ReportLab API
|
||||
acts on file-like objects, and Django's :class:`~django.http.HttpResponse`
|
||||
objects are file-like objects.
|
||||
|
||||
Here's a "Hello World" example::
|
||||
|
||||
from reportlab.pdfgen import canvas
|
||||
from django.http import HttpResponse
|
||||
|
||||
def some_view(request):
|
||||
# Create the HttpResponse object with the appropriate PDF headers.
|
||||
response = HttpResponse(mimetype='application/pdf')
|
||||
response['Content-Disposition'] = 'attachment; filename=somefilename.pdf'
|
||||
|
||||
# Create the PDF object, using the response object as its "file."
|
||||
p = canvas.Canvas(response)
|
||||
|
||||
# Draw things on the PDF. Here's where the PDF generation happens.
|
||||
# See the ReportLab documentation for the full list of functionality.
|
||||
p.drawString(100, 100, "Hello world.")
|
||||
|
||||
# Close the PDF object cleanly, and we're done.
|
||||
p.showPage()
|
||||
p.save()
|
||||
return response
|
||||
|
||||
The code and comments should be self-explanatory, but a few things deserve a
|
||||
mention:
|
||||
|
||||
* The response gets a special MIME type, ``application/pdf``. This tells
|
||||
browsers that the document is a PDF file, rather than an HTML file. If
|
||||
you leave this off, browsers will probably interpret the output as HTML,
|
||||
which would result in ugly, scary gobbledygook in the browser window.
|
||||
|
||||
* The response gets an additional ``Content-Disposition`` header, which
|
||||
contains the name of the PDF file. This filename is arbitrary: Call it
|
||||
whatever you want. It'll be used by browsers in the "Save as..."
|
||||
dialogue, etc.
|
||||
|
||||
* The ``Content-Disposition`` header starts with ``'attachment; '`` in this
|
||||
example. This forces Web browsers to pop-up a dialog box
|
||||
prompting/confirming how to handle the document even if a default is set
|
||||
on the machine. If you leave off ``'attachment;'``, browsers will handle
|
||||
the PDF using whatever program/plugin they've been configured to use for
|
||||
PDFs. Here's what that code would look like::
|
||||
|
||||
response['Content-Disposition'] = 'filename=somefilename.pdf'
|
||||
|
||||
* Hooking into the ReportLab API is easy: Just pass ``response`` as the
|
||||
first argument to ``canvas.Canvas``. The ``Canvas`` class expects a
|
||||
file-like object, and :class:`~django.http.HttpResponse` objects fit the
|
||||
bill.
|
||||
|
||||
* Note that all subsequent PDF-generation methods are called on the PDF
|
||||
object (in this case, ``p``) -- not on ``response``.
|
||||
|
||||
* Finally, it's important to call ``showPage()`` and ``save()`` on the PDF
|
||||
file.
|
||||
|
||||
Complex PDFs
|
||||
============
|
||||
|
||||
If you're creating a complex PDF document with ReportLab, consider using the
|
||||
cStringIO_ library as a temporary holding place for your PDF file. The cStringIO
|
||||
library provides a file-like object interface that is particularly efficient.
|
||||
Here's the above "Hello World" example rewritten to use ``cStringIO``::
|
||||
|
||||
from cStringIO import StringIO
|
||||
from reportlab.pdfgen import canvas
|
||||
from django.http import HttpResponse
|
||||
|
||||
def some_view(request):
|
||||
# Create the HttpResponse object with the appropriate PDF headers.
|
||||
response = HttpResponse(mimetype='application/pdf')
|
||||
response['Content-Disposition'] = 'attachment; filename=somefilename.pdf'
|
||||
|
||||
buffer = StringIO()
|
||||
|
||||
# Create the PDF object, using the StringIO object as its "file."
|
||||
p = canvas.Canvas(buffer)
|
||||
|
||||
# Draw things on the PDF. Here's where the PDF generation happens.
|
||||
# See the ReportLab documentation for the full list of functionality.
|
||||
p.drawString(100, 100, "Hello world.")
|
||||
|
||||
# Close the PDF object cleanly.
|
||||
p.showPage()
|
||||
p.save()
|
||||
|
||||
# Get the value of the StringIO buffer and write it to the response.
|
||||
pdf = buffer.getvalue()
|
||||
buffer.close()
|
||||
response.write(pdf)
|
||||
return response
|
||||
|
||||
.. _cStringIO: http://www.python.org/doc/current/lib/module-cStringIO.html
|
||||
|
||||
Further resources
|
||||
=================
|
||||
|
||||
* PDFlib_ is another PDF-generation library that has Python bindings. To
|
||||
use it with Django, just use the same concepts explained in this article.
|
||||
* `Pisa HTML2PDF`_ is yet another PDF-generation library. Pisa ships with
|
||||
an example of how to integrate Pisa with Django.
|
||||
* HTMLdoc_ is a command-line script that can convert HTML to PDF. It
|
||||
doesn't have a Python interface, but you can escape out to the shell
|
||||
using ``system`` or ``popen`` and retrieve the output in Python.
|
||||
* `forge_fdf in Python`_ is a library that fills in PDF forms.
|
||||
|
||||
.. _PDFlib: http://www.pdflib.org/
|
||||
.. _`Pisa HTML2PDF`: http://www.htmltopdf.org/
|
||||
.. _HTMLdoc: http://www.htmldoc.org/
|
||||
.. _forge_fdf in Python: http://www.accesspdf.com/article.php/20050421092951834
|
||||
|
||||
Other formats
|
||||
=============
|
||||
|
||||
Notice that there isn't a lot in these examples that's PDF-specific -- just the
|
||||
bits using ``reportlab``. You can use a similar technique to generate any
|
||||
arbitrary format that you can find a Python library for. Also see
|
||||
:ref:`howto-outputting-csv` for another example and some techniques you can use
|
||||
when generated text-based formats.
|
||||
131
docs/howto/static-files.txt
Normal file
131
docs/howto/static-files.txt
Normal file
@@ -0,0 +1,131 @@
|
||||
.. _howto-static-files:
|
||||
|
||||
=========================
|
||||
How to serve static files
|
||||
=========================
|
||||
|
||||
.. module:: django.views.static
|
||||
:synopsis: Serving of static files during development.
|
||||
|
||||
Django itself doesn't serve static (media) files, such as images, style sheets,
|
||||
or video. It leaves that job to whichever Web server you choose.
|
||||
|
||||
The reasoning here is that standard Web servers, such as Apache_ and lighttpd_,
|
||||
are much more fine-tuned at serving static files than a Web application
|
||||
framework.
|
||||
|
||||
With that said, Django does support static files **during development**. You can
|
||||
use the :func:`django.views.static.serve` view to serve media files.
|
||||
|
||||
.. _Apache: http://httpd.apache.org/
|
||||
.. _lighttpd: http://www.lighttpd.net/
|
||||
|
||||
The big, fat disclaimer
|
||||
=======================
|
||||
|
||||
Using this method is **inefficient** and **insecure**. Do not use this in a
|
||||
production setting. Use this only for development.
|
||||
|
||||
For information on serving static files in an Apache production environment,
|
||||
see the :ref:`Django mod_python documentation <serving-media-files>`.
|
||||
|
||||
How to do it
|
||||
============
|
||||
|
||||
Here's the formal definition of the :func:`~django.views.static.serve` view:
|
||||
|
||||
.. function:: def serve(request, path, document_root, show_indexes=False):
|
||||
|
||||
To use it, just put this in your :ref:`URLconf <topics-http-urls>`::
|
||||
|
||||
(r'^site_media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': '/path/to/media'}),
|
||||
|
||||
...where ``site_media`` is the URL where your media will be rooted, and
|
||||
``/path/to/media`` is the filesystem root for your media. This will call the
|
||||
:func:`~django.views.static.serve` view, passing in the path from the URLconf
|
||||
and the (required) ``document_root`` parameter.
|
||||
|
||||
Given the above URLconf:
|
||||
|
||||
* The file ``/path/to/media/foo.jpg`` will be made available at the URL
|
||||
``/site_media/foo.jpg``.
|
||||
|
||||
* The file ``/path/to/media/css/mystyles.css`` will be made available
|
||||
at the URL ``/site_media/css/mystyles.css``.
|
||||
|
||||
* The file ``/path/bar.jpg`` will not be accessible, because it doesn't
|
||||
fall under the document root.
|
||||
|
||||
|
||||
Directory listings
|
||||
==================
|
||||
|
||||
Optionally, you can pass the ``show_indexes`` parameter to the
|
||||
:func:`~django.views.static.serve` view. This is ``False`` by default. If it's
|
||||
``True``, Django will display file listings for directories.
|
||||
|
||||
For example::
|
||||
|
||||
(r'^site_media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': '/path/to/media', 'show_indexes': True}),
|
||||
|
||||
You can customize the index view by creating a template called
|
||||
``static/directory_index.html``. That template gets two objects in its context:
|
||||
|
||||
* ``directory`` -- the directory name (a string)
|
||||
* ``file_list`` -- a list of file names (as strings) in the directory
|
||||
|
||||
Here's the default ``static/directory_index`` template:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="Content-Language" content="en-us" />
|
||||
<meta name="robots" content="NONE,NOARCHIVE" />
|
||||
<title>Index of {{ directory }}</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Index of {{ directory }}</h1>
|
||||
<ul>
|
||||
{% for f in file_list %}
|
||||
<li><a href="{{ f }}">{{ f }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Limiting use to DEBUG=True
|
||||
==========================
|
||||
|
||||
Because URLconfs are just plain Python modules, you can use Python logic to
|
||||
make the static-media view available only in development mode. This is a handy
|
||||
trick to make sure the static-serving view doesn't slip into a production
|
||||
setting by mistake.
|
||||
|
||||
Do this by wrapping an ``if DEBUG`` statement around the
|
||||
:func:`django.views.static.serve` inclusion. Here's a full example URLconf::
|
||||
|
||||
from django.conf.urls.defaults import *
|
||||
from django.conf import settings
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^articles/2003/$', 'news.views.special_case_2003'),
|
||||
(r'^articles/(?P<year>\d{4})/$', 'news.views.year_archive'),
|
||||
(r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', 'news.views.month_archive'),
|
||||
(r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d+)/$', 'news.views.article_detail'),
|
||||
)
|
||||
|
||||
if settings.DEBUG:
|
||||
urlpatterns += patterns('',
|
||||
(r'^site_media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': '/path/to/media'}),
|
||||
)
|
||||
|
||||
This code is straightforward. It imports the settings and checks the value of
|
||||
the :setting:`DEBUG` setting. If it evaluates to ``True``, then ``site_media``
|
||||
will be associated with the ``django.views.static.serve`` view. If not, then the
|
||||
view won't be made available.
|
||||
|
||||
Of course, the catch here is that you'll have to remember to set ``DEBUG=False``
|
||||
in your production settings file. But you should be doing that anyway.
|
||||
Reference in New Issue
Block a user