diff options
| author | Honza Král <honza.kral@gmail.com> | 2009-12-28 16:35:23 +0000 |
|---|---|---|
| committer | Honza Král <honza.kral@gmail.com> | 2009-12-28 16:35:23 +0000 |
| commit | f911df19a455246198b0c8c81ab96bf2abec04f8 (patch) | |
| tree | 0c0bfb72d622994419492db943d9d37857224f97 /docs/howto | |
| parent | 695de8cc9145e139c2b22e05aa44f5ac04da6f85 (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.txt | 2 | ||||
| -rw-r--r-- | docs/howto/custom-model-fields.txt | 148 | ||||
| -rw-r--r-- | docs/howto/custom-template-tags.txt | 79 | ||||
| -rw-r--r-- | docs/howto/deployment/modpython.txt | 4 | ||||
| -rw-r--r-- | docs/howto/initial-data.txt | 34 | ||||
| -rw-r--r-- | docs/howto/legacy-databases.txt | 17 | ||||
| -rw-r--r-- | docs/howto/outputting-pdf.txt | 10 |
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 ============= |
