summaryrefslogtreecommitdiff
path: root/docs/howto
diff options
context:
space:
mode:
authorHonza Král <honza.kral@gmail.com>2009-12-28 16:35:23 +0000
committerHonza Král <honza.kral@gmail.com>2009-12-28 16:35:23 +0000
commitf911df19a455246198b0c8c81ab96bf2abec04f8 (patch)
tree0c0bfb72d622994419492db943d9d37857224f97 /docs/howto
parent695de8cc9145e139c2b22e05aa44f5ac04da6f85 (diff)
[soc2009/model-validation] Merget to trunk at r12009
git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/model-validation@12014 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'docs/howto')
-rw-r--r--docs/howto/auth-remote-user.txt2
-rw-r--r--docs/howto/custom-model-fields.txt148
-rw-r--r--docs/howto/custom-template-tags.txt79
-rw-r--r--docs/howto/deployment/modpython.txt4
-rw-r--r--docs/howto/initial-data.txt34
-rw-r--r--docs/howto/legacy-databases.txt17
-rw-r--r--docs/howto/outputting-pdf.txt10
7 files changed, 229 insertions, 65 deletions
diff --git a/docs/howto/auth-remote-user.txt b/docs/howto/auth-remote-user.txt
index 05532da0b0..b7987e14a7 100644
--- a/docs/howto/auth-remote-user.txt
+++ b/docs/howto/auth-remote-user.txt
@@ -12,7 +12,7 @@ Windows Authentication or Apache and `mod_authnz_ldap`_, `CAS`_, `Cosign`_,
`WebAuth`_, `mod_auth_sspi`_, etc.
.. _mod_authnz_ldap: http://httpd.apache.org/docs/2.2/mod/mod_authnz_ldap.html
-.. _CAS: http://www.ja-sig.org/products/cas/
+.. _CAS: http://www.jasig.org/cas
.. _Cosign: http://weblogin.org
.. _WebAuth: http://www.stanford.edu/services/webauth/
.. _mod_auth_sspi: http://sourceforge.net/projects/mod-auth-sspi
diff --git a/docs/howto/custom-model-fields.txt b/docs/howto/custom-model-fields.txt
index 9f798f14d5..169f5114b8 100644
--- a/docs/howto/custom-model-fields.txt
+++ b/docs/howto/custom-model-fields.txt
@@ -5,6 +5,7 @@ Writing custom model fields
===========================
.. versionadded:: 1.0
+.. currentmodule:: django.db.models
Introduction
============
@@ -39,6 +40,8 @@ are traditionally called *north*, *east*, *south* and *west*. Our class looks
something like this::
class Hand(object):
+ """A hand of cards (bridge style)"""
+
def __init__(self, north, east, south, west):
# Input parameters are lists of cards ('Ah', '9s', etc)
self.north = north
@@ -163,6 +166,9 @@ behave like any existing field, so we'll subclass directly from
from django.db import models
class HandField(models.Field):
+
+ description = "A hand of cards (bridge style)"
+
def __init__(self, *args, **kwargs):
kwargs['max_length'] = 104
super(HandField, self).__init__(*args, **kwargs)
@@ -244,6 +250,9 @@ simple: make sure your field subclass uses a special metaclass:
For example::
class HandField(models.Field):
+
+ description = "A hand of cards (bridge style)"
+
__metaclass__ = models.SubfieldBase
def __init__(self, *args, **kwargs):
@@ -252,6 +261,22 @@ For example::
This ensures that the :meth:`to_python` method, documented below, will always be
called when the attribute is initialized.
+
+Documenting your Custom Field
+-----------------------------
+
+.. class:: django.db.models.Field
+
+.. attribute:: description
+
+As always, you should document your field type, so users will know what it is.
+In addition to providing a docstring for it, which is useful for developers,
+you can also allow users of the admin app to see a short description of the
+field type via the ``django.contrib.admindocs`` application. To do this simply
+provide descriptive text in a ``description`` class attribute of your custom field.
+In the above example, the type description displayed by the ``admindocs`` application
+for a ``HandField`` will be 'A hand of cards (bridge style)'.
+
Useful methods
--------------
@@ -263,10 +288,13 @@ approximately decreasing order of importance, so start from the top.
Custom database types
~~~~~~~~~~~~~~~~~~~~~
-.. method:: db_type(self)
+.. method:: db_type(self, connection)
+
+.. versionadded:: 1.2
+ The ``connection`` argument was added to support multiple databases.
Returns the database column data type for the :class:`~django.db.models.Field`,
-taking into account the current :setting:`DATABASE_ENGINE` setting.
+taking into account the connection object, and the settings associated with it.
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`
@@ -275,7 +303,7 @@ method, like so::
from django.db import models
class MytypeField(models.Field):
- def db_type(self):
+ def db_type(self, connection):
return 'mytype'
Once you have ``MytypeField``, you can use it in any model, just like any other
@@ -290,13 +318,13 @@ 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.
+check the ``connection.settings_dict['ENGINE']`` attribute.
+
For example::
class MyDateField(models.Field):
- def db_type(self):
- from django.conf import settings
- if settings.DATABASE_ENGINE == 'mysql':
+ def db_type(self, connection):
+ if connection.settings_dict['ENGINE'] == 'django.db.backends.mysql':
return 'datetime'
else:
return 'timestamp'
@@ -304,7 +332,7 @@ For example::
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`
+afford to execute slightly complex code, such as the ``connection.settings_dict``
check in the above example.
Some database column types accept parameters, such as ``CHAR(25)``, where the
@@ -315,7 +343,7 @@ sense to have a ``CharMaxlength25Field``, shown here::
# This is a silly example of hard-coded parameters.
class CharMaxlength25Field(models.Field):
- def db_type(self):
+ def db_type(self, connection):
return 'char(25)'
# In the model:
@@ -333,7 +361,7 @@ time -- i.e., when the class is instantiated. To do that, just implement
self.max_length = max_length
super(BetterCharField, self).__init__(*args, **kwargs)
- def db_type(self):
+ def db_type(self, connection):
return 'char(%s)' % self.max_length
# In the model:
@@ -396,33 +424,67 @@ Python object type we want to store in the model's attribute.
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
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Converting Python objects to query values
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. method:: get_prep_value(self, value)
-.. method:: get_db_prep_value(self, value)
+.. versionadded:: 1.2
+ This method was factored out of ``get_db_prep_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.
+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 has been
+prepared for use as a parameter in a query.
+
+This conversion should *not* include any database-specific
+conversions. If database-specific conversions are required, they
+should be made in the call to :meth:`get_db_prep_value`.
For example::
class HandField(models.Field):
# ...
- def get_db_prep_value(self, value):
+ def get_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)
+Converting query values to database values
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. method:: get_db_prep_value(self, value, connection, prepared=False)
+
+.. versionadded:: 1.2
+ The ``connection`` and ``prepared`` arguments were added to support multiple databases.
+
+Some data types (for example, dates) need to be in a specific format
+before they can be used by a database backend.
+:meth:`get_db_prep_value` is the method where those conversions should
+be made. The specific connection that will be used for the query is
+passed as the ``connection`` parameter. This allows you to use
+backend-specific conversion logic if it is required.
+
+The ``prepared`` argument describes whether or not the value has
+already been passed through :meth:`get_prep_value` conversions. When
+``prepared`` is False, the default implementation of
+:meth:`get_db_prep_value` will call :meth:`get_prep_value` to do
+initial data conversions before performing any database-specific
+processing.
+
+.. method:: get_db_prep_save(self, value, connection)
+
+.. versionadded:: 1.2
+ The ``connection`` argument was added to support multiple databases.
-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 needs a
-special conversion when being saved that is not the same as the conversion used
-for normal query parameters (which is implemented by ``get_db_prep_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 needs a special conversion when being saved
+that is not the same as the conversion used for normal query
+parameters (which is implemented by ``get_db_prep_value``).
Preprocessing values before saving
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -450,7 +512,16 @@ correct value.
Preparing values for use in database lookups
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.. method:: get_db_prep_lookup(self, lookup_type, value)
+As with value conversions, preparing a value for database lookups is a
+two phase process.
+
+.. method:: get_prep_lookup(self, lookup_type, value)
+
+.. versionadded:: 1.2
+ This method was factored out of ``get_db_prep_lookup()``
+
+:meth:`get_prep_lookup` performs the first phase of lookup preparation,
+performing generic data validity checks
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
@@ -467,34 +538,45 @@ by with handling the lookup types that need special handling for your field
and pass the rest to 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
+implement ``get_prep_lookup()``. If you don't, ``get_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
+Note that, for ``range`` and ``in`` lookups, ``get_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
+time, you can reuse ``get_prep_value()``, or at least factor out some common
pieces.
-For example, the following code implements ``get_db_prep_lookup`` to limit the
+For example, the following code implements ``get_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):
+ def get_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)]
+ return [self.get_prep_value(value)]
elif lookup_type == 'in':
- return [self.get_db_prep_value(v) for v in value]
+ return [self.get_prep_value(v) for v in value]
else:
raise TypeError('Lookup type %r not supported.' % lookup_type)
+.. method:: get_db_prep_lookup(self, lookup_type, value, connection, prepared=False)
+
+.. versionadded:: 1.2
+ The ``connection`` and ``prepared`` arguments were added to support multiple databases.
+
+Performs any database-specific data conversions required by a lookup.
+As with :meth:`get_db_prep_value`, the specific connection that will
+be used for the query is passed as the ``connection`` parameter.
+The ``prepared`` argument describes whether the value has already been
+prepared with :meth:`get_prep_lookup`.
+
Specifying the form field for a model field
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/howto/custom-template-tags.txt b/docs/howto/custom-template-tags.txt
index c6f76772de..774d12dc44 100644
--- a/docs/howto/custom-template-tags.txt
+++ b/docs/howto/custom-template-tags.txt
@@ -463,6 +463,85 @@ 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.
+.. _template_tag_thread_safety:
+
+Thread-safety considerations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. versionadded:: 1.2
+
+Once a node is parsed, its ``render`` method may be called any number of times.
+Since Django is sometimes run in multi-threaded environments, a single node may
+be simultaneously rendering with different contexts in response to two separate
+requests. Therefore, it's important to make sure your template tags are thread
+safe.
+
+To make sure your template tags are thread safe, you should never store state
+information on the node itself. For example, Django provides a builtin ``cycle``
+template tag that cycles among a list of given strings each time it's rendered::
+
+ {% for o in some_list %}
+ <tr class="{% cycle 'row1' 'row2' %}>
+ ...
+ </tr>
+ {% endfor %}
+
+A naive implementation of ``CycleNode`` might look something like this::
+
+ class CycleNode(Node):
+ def __init__(self, cyclevars):
+ self.cycle_iter = itertools.cycle(cyclevars)
+ def render(self, context):
+ return self.cycle_iter.next()
+
+But, suppose we have two templates rendering the template snippet from above at
+the same time:
+
+ 1. Thread 1 performs its first loop iteration, ``CycleNode.render()``
+ returns 'row1'
+ 2. Thread 2 performs its first loop iteration, ``CycleNode.render()``
+ returns 'row2'
+ 3. Thread 1 performs its second loop iteration, ``CycleNode.render()``
+ returns 'row1'
+ 4. Thread 2 performs its second loop iteration, ``CycleNode.render()``
+ returns 'row2'
+
+The CycleNode is iterating, but it's iterating globally. As far as Thread 1
+and Thread 2 are concerned, it's always returning the same value. This is
+obviously not what we want!
+
+To address this problem, Django provides a ``render_context`` that's associated
+with the ``context`` of the template that is currently being rendered. The
+``render_context`` behaves like a Python dictionary, and should be used to store
+``Node`` state between invocations of the ``render`` method.
+
+Let's refactor our ``CycleNode`` implementation to use the ``render_context``::
+
+ class CycleNode(Node):
+ def __init__(self, cyclevars):
+ self.cyclevars = cyclevars
+ def render(self, context):
+ if self not in context.render_context:
+ context.render_context[self] = itertools.cycle(self.cyclevars)
+ cycle_iter = context.render_context[self]
+ return cycle_iter.next()
+
+Note that it's perfectly safe to store global information that will not change
+throughout the life of the ``Node`` as an attribute. In the case of
+``CycleNode``, the ``cyclevars`` argument doesn't change after the ``Node`` is
+instantiated, so we don't need to put it in the ``render_context``. But state
+information that is specific to the template that is currently being rendered,
+like the current iteration of the ``CycleNode``, should be stored in the
+``render_context``.
+
+.. note::
+ Notice how we used ``self`` to scope the ``CycleNode`` specific information
+ within the ``render_context``. There may be multiple ``CycleNodes`` in a
+ given template, so we need to be careful not to clobber another node's state
+ information. The easiest way to do this is to always use ``self`` as the key
+ into ``render_context``. If you're keeping track of several state variables,
+ make ``render_context[self]`` a dictionary.
+
Registering the tag
~~~~~~~~~~~~~~~~~~~
diff --git a/docs/howto/deployment/modpython.txt b/docs/howto/deployment/modpython.txt
index 50dadf9854..143a6d5ae3 100644
--- a/docs/howto/deployment/modpython.txt
+++ b/docs/howto/deployment/modpython.txt
@@ -375,9 +375,9 @@ 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
+.. _Expat Causing Apache Crash: http://www.dscpl.com.au/wiki/ModPython/Articles/ExpatCausingApacheCrash
.. _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
+.. _Getting mod_python Working: http://www.dscpl.com.au/wiki/ModPython/Articles/GettingModPythonWorking
If you get a UnicodeEncodeError
===============================
diff --git a/docs/howto/initial-data.txt b/docs/howto/initial-data.txt
index d36329daa4..b071d6d529 100644
--- a/docs/howto/initial-data.txt
+++ b/docs/howto/initial-data.txt
@@ -118,23 +118,27 @@ The SQL files are read by the :djadmin:`sqlcustom`, :djadmin:`sqlreset`,
<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.
+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``).
+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 last part of the module name provided for the
+:setting:`ENGINE` in your settings file (e.g., if you have defined a
+database with an :setting:`ENGINE` value of
+``django.db.backends.postgresql``, Django will look for
+``<appname>/sql/<modelname>.postgresql.sql``).
-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``.
+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``.
diff --git a/docs/howto/legacy-databases.txt b/docs/howto/legacy-databases.txt
index c4eb1d82c7..b2aa7e4ea6 100644
--- a/docs/howto/legacy-databases.txt
+++ b/docs/howto/legacy-databases.txt
@@ -18,15 +18,16 @@ 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>`:
+what the name of the database is. Do that by editing the :setting:`DATABASES`
+setting and assigning values to the following keys for the ``'default'``
+connection:
- * :setting:`DATABASE_NAME`
- * :setting:`DATABASE_ENGINE`
- * :setting:`DATABASE_USER`
- * :setting:`DATABASE_PASSWORD`
- * :setting:`DATABASE_HOST`
- * :setting:`DATABASE_PORT`
+ * :setting:`NAME`
+ * :setting:`ENGINE`
+ * :setting:`USER`
+ * :setting:`PASSWORD`
+ * :setting:`HOST`
+ * :setting:`PORT`
Auto-generate the models
========================
diff --git a/docs/howto/outputting-pdf.txt b/docs/howto/outputting-pdf.txt
index 3cbab555e4..94acab8311 100644
--- a/docs/howto/outputting-pdf.txt
+++ b/docs/howto/outputting-pdf.txt
@@ -16,13 +16,13 @@ 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
+.. _ReportLab: http://www.reportlab.org/oss/rl-toolkit/
.. _kusports.com: http://www.kusports.com/
Install ReportLab
=================
-Download and install the ReportLab library from http://www.reportlab.org/downloads.html.
+Download and install the ReportLab library from http://www.reportlab.org/oss/rl-toolkit/download/.
The `user guide`_ (not coincidentally, a PDF file) explains how to install it.
Test your installation by importing it in the Python interactive interpreter::
@@ -138,17 +138,15 @@ 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
+ * `Pisa XHTML2PDF`_ 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/
+.. _`Pisa XHTML2PDF`: http://www.xhtml2pdf.com/
.. _HTMLdoc: http://www.htmldoc.org/
-.. _forge_fdf in Python: http://www.accesspdf.com/article.php/20050421092951834
Other formats
=============