mirror of
https://github.com/django/django.git
synced 2025-10-24 06:06:09 +00:00
[soc2009/multidb] Merged up to trunk r11864.
git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/multidb@11866 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
@@ -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
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -48,14 +48,20 @@ their deprecation, as per the :ref:`Django deprecation policy
|
||||
manager in the ``User`` model (``user.message_set``), and the
|
||||
associated methods (``user.message_set.create()`` and
|
||||
``user.get_and_delete_messages()``), which have
|
||||
been deprecated since the 1.2 release, will be removed. The
|
||||
:ref:`messages framework <ref-contrib-messages>` should be used
|
||||
been deprecated since the 1.2 release, will be removed. The
|
||||
:ref:`messages framework <ref-contrib-messages>` should be used
|
||||
instead.
|
||||
|
||||
* Authentication backends need to support the ``obj`` parameter for
|
||||
permission checking. The ``supports_object_permissions`` variable
|
||||
is not checked any longer and can be removed.
|
||||
|
||||
* The ability to specify a callable template loader rather than a
|
||||
``Loader`` class will be removed, as will the ``load_template_source``
|
||||
functions that are included with the built in template loaders for
|
||||
backwards compatibility. These have been deprecated since the 1.2
|
||||
release.
|
||||
|
||||
* 2.0
|
||||
* ``django.views.defaults.shortcut()``. This function has been moved
|
||||
to ``django.contrib.contenttypes.views.shortcut()`` as part of the
|
||||
|
||||
@@ -36,7 +36,7 @@ To install the sitemap app, follow these steps:
|
||||
1. Add ``'django.contrib.sitemaps'`` to your :setting:`INSTALLED_APPS`
|
||||
setting.
|
||||
|
||||
2. Make sure ``'django.template.loaders.app_directories.load_template_source'``
|
||||
2. Make sure ``'django.template.loaders.app_directories.Loader'``
|
||||
is in your :setting:`TEMPLATE_LOADERS` setting. It's in there by default,
|
||||
so you'll only need to change this if you've changed that setting.
|
||||
|
||||
@@ -45,7 +45,7 @@ To install the sitemap app, follow these steps:
|
||||
|
||||
(Note: The sitemap application doesn't install any database tables. The only
|
||||
reason it needs to go into :setting:`INSTALLED_APPS` is so that the
|
||||
:func:`~django.template.loaders.app_directories.load_template_source` template
|
||||
:func:`~django.template.loaders.app_directories.Loader` template
|
||||
loader can find the default templates.)
|
||||
|
||||
Initialization
|
||||
|
||||
@@ -240,6 +240,16 @@ model names.
|
||||
The :djadminopt:`--database` option can be used to specify the database
|
||||
onto which the data will be loaded.
|
||||
|
||||
.. django-admin-option:: --natural
|
||||
|
||||
.. versionadded:: 1.2
|
||||
|
||||
Use :ref:`natural keys <topics-serialization-natural-keys>` to represent
|
||||
any foreign key and many-to-many relationship with a model that provides
|
||||
a natural key definition. If you are dumping ``contrib.auth`` ``Permission``
|
||||
objects or ``contrib.contenttypes`` ``ContentType`` objects, you should
|
||||
probably be using this flag.
|
||||
|
||||
flush
|
||||
-----
|
||||
|
||||
@@ -807,7 +817,7 @@ information.
|
||||
|
||||
.. versionadded:: 1.2
|
||||
|
||||
Use the ``--failfast`` option to stop running tests and report the failure
|
||||
Use the ``--failfast`` option to stop running tests and report the failure
|
||||
immediately after a test fails.
|
||||
|
||||
testserver <fixture fixture ...>
|
||||
|
||||
@@ -903,7 +903,7 @@ MESSAGE_LEVEL
|
||||
|
||||
Default: `messages.INFO`
|
||||
|
||||
Sets the minimum message level that will be recorded by the messages
|
||||
Sets the minimum message level that will be recorded by the messages
|
||||
framework. See the :ref:`messages documentation <ref-contrib-messages>` for
|
||||
more details.
|
||||
|
||||
@@ -1246,11 +1246,14 @@ TEMPLATE_LOADERS
|
||||
|
||||
Default::
|
||||
|
||||
('django.template.loaders.filesystem.load_template_source',
|
||||
'django.template.loaders.app_directories.load_template_source')
|
||||
('django.template.loaders.filesystem.Loader',
|
||||
'django.template.loaders.app_directories.Loader')
|
||||
|
||||
A tuple of callables (as strings) that know how to import templates from
|
||||
various sources. See :ref:`ref-templates-api`.
|
||||
A tuple of template loader classes, specified as strings. Each ``Loader`` class
|
||||
knows how to import templates from a particular sources. Optionally, a tuple can be
|
||||
used instead of a string. The first item in the tuple should be the ``Loader``'s
|
||||
module, subsequent items are passed to the ``Loader`` during initialization. See
|
||||
:ref:`ref-templates-api`.
|
||||
|
||||
.. setting:: TEMPLATE_STRING_IF_INVALID
|
||||
|
||||
|
||||
@@ -322,7 +322,7 @@ and return a dictionary of items to be merged into the context. By default,
|
||||
cannot be turned off by the :setting:`TEMPLATE_CONTEXT_PROCESSORS` setting.
|
||||
|
||||
.. versionadded:: 1.2
|
||||
The ``'messages'`` context processor was added. For more information, see
|
||||
The ``'messages'`` context processor was added. For more information, see
|
||||
the :ref:`messages documentation <ref-contrib-messages>`.
|
||||
|
||||
Each processor is applied in order. That means, if one processor adds a
|
||||
@@ -379,7 +379,7 @@ If :setting:`TEMPLATE_CONTEXT_PROCESSORS` contains this processor, every
|
||||
|
||||
.. versionchanged:: 1.2
|
||||
Prior to version 1.2, the ``messages`` variable was a lazy accessor for
|
||||
``user.get_and_delete_messages()``. It has been changed to include any
|
||||
``user.get_and_delete_messages()``. It has been changed to include any
|
||||
messages added via the :ref:`messages framework <ref-contrib-messages`.
|
||||
|
||||
django.core.context_processors.debug
|
||||
@@ -448,7 +448,7 @@ If :setting:`TEMPLATE_CONTEXT_PROCESSORS` contains this processor, every
|
||||
context processor. For backwards compatibility the ``'auth'`` context
|
||||
processor will continue to supply the ``messages`` variable until Django
|
||||
1.4. If you use the ``messages`` variable, your project will work with
|
||||
either (or both) context processors, but it is recommended to add
|
||||
either (or both) context processors, but it is recommended to add
|
||||
``django.contrib.messages.context_processors.messages`` so your project
|
||||
will be prepared for the future upgrade.
|
||||
|
||||
@@ -571,11 +571,11 @@ by editing your :setting:`TEMPLATE_LOADERS` setting. :setting:`TEMPLATE_LOADERS`
|
||||
should be a tuple of strings, where each string represents a template loader.
|
||||
Here are the template loaders that come with Django:
|
||||
|
||||
``django.template.loaders.filesystem.load_template_source``
|
||||
``django.template.loaders.filesystem.Loader``
|
||||
Loads templates from the filesystem, according to :setting:`TEMPLATE_DIRS`.
|
||||
This loader is enabled by default.
|
||||
|
||||
``django.template.loaders.app_directories.load_template_source``
|
||||
``django.template.loaders.app_directories.Loader``
|
||||
Loads templates from Django apps on the filesystem. For each app in
|
||||
:setting:`INSTALLED_APPS`, the loader looks for a ``templates``
|
||||
subdirectory. If the directory exists, Django looks for templates in there.
|
||||
@@ -599,12 +599,43 @@ Here are the template loaders that come with Django:
|
||||
|
||||
This loader is enabled by default.
|
||||
|
||||
``django.template.loaders.eggs.load_template_source``
|
||||
``django.template.loaders.eggs.Loader``
|
||||
Just like ``app_directories`` above, but it loads templates from Python
|
||||
eggs rather than from the filesystem.
|
||||
|
||||
This loader is disabled by default.
|
||||
|
||||
``django.template.loaders.cached.Loader``
|
||||
By default, the templating system will read and compile your templates every
|
||||
time they need to be rendered. While the Django templating system is quite
|
||||
fast, the overhead from reading and compiling templates can add up.
|
||||
|
||||
The cached template loader is a class-based loader that you configure with
|
||||
a list of other loaders that it should wrap. The wrapped loaders are used to
|
||||
locate unknown templates when they are first encountered. The cached loader
|
||||
then stores the compiled ``Template`` in memory. The cached ``Template``
|
||||
instance is returned for subsequent requests to load the same template.
|
||||
|
||||
For example, to enable template caching with the ``filesystem`` and
|
||||
``app_directories`` template loaders you might use the following settings::
|
||||
|
||||
TEMPLATE_LOADERS = (
|
||||
('django.template.loaders.cached.Loader', (
|
||||
'django.template.loaders.filesystem.Loader',
|
||||
'django.template.loaders.app_directories.Loader',
|
||||
)),
|
||||
)
|
||||
|
||||
.. note::
|
||||
All of the built-in Django template tags are safe to use with the cached
|
||||
loader, but if you're using custom template tags that come from third
|
||||
party packages, or that you wrote yourself, you should ensure that the
|
||||
``Node`` implementation for each tag is thread-safe. For more
|
||||
information, see
|
||||
:ref:`template tag thread safety considerations<template_tag_thread_safety>`.
|
||||
|
||||
This loader is disabled by default.
|
||||
|
||||
Django uses the template loaders in order according to the
|
||||
:setting:`TEMPLATE_LOADERS` setting. It uses each loader until a loader finds a
|
||||
match.
|
||||
@@ -667,3 +698,68 @@ settings you wish to specify. You might want to consider setting at least
|
||||
and :setting:`TEMPLATE_DEBUG`. All available settings are described in the
|
||||
:ref:`settings documentation <ref-settings>`, and any setting starting with
|
||||
``TEMPLATE_`` is of obvious interest.
|
||||
|
||||
.. _topic-template-alternate-language:
|
||||
|
||||
Using an alternative template language
|
||||
======================================
|
||||
|
||||
.. versionadded 1.2
|
||||
|
||||
The Django ``Template`` and ``Loader`` classes implement a simple API for
|
||||
loading and rendering templates. By providing some simple wrapper classes that
|
||||
implement this API we can use third party template systems like `Jinja2
|
||||
<http://jinja.pocoo.org/2/>`_ or `Cheetah <http://www.cheetahtemplate.org/>`_. This
|
||||
allows us to use third-party template libraries without giving up useful Django
|
||||
features like the Django ``Context`` object and handy shortcuts like
|
||||
``render_to_response()``.
|
||||
|
||||
The core component of the Django templating system is the ``Template`` class.
|
||||
This class has a very simple interface: it has a constructor that takes a single
|
||||
positional argument specifying the template string, and a ``render()`` method
|
||||
that takes a ``django.template.context.Context`` object and returns a string
|
||||
containing the rendered response.
|
||||
|
||||
Suppose we're using a template language that defines a ``Template`` object with
|
||||
a ``render()`` method that takes a dictionary rather than a ``Context`` object.
|
||||
We can write a simple wrapper that implements the Django ``Template`` interface::
|
||||
|
||||
import some_template_language
|
||||
class Template(some_template_language.Template):
|
||||
def render(self, context):
|
||||
# flatten the Django Context into a single dictionary.
|
||||
context_dict = {}
|
||||
for d in context.dicts:
|
||||
context_dict.update(d)
|
||||
return super(Template, self).render(context_dict)
|
||||
|
||||
That's all that's required to make our fictional ``Template`` class compatible
|
||||
with the Django loading and rendering system!
|
||||
|
||||
The next step is to write a ``Loader`` class that returns instances of our custom
|
||||
template class instead of the default ``django.template.Template``. Custom ``Loader``
|
||||
classes should inherit from ``django.template.loader.BaseLoader`` and override
|
||||
the ``load_template_source()`` method, which takes a ``template_name`` argument,
|
||||
loads the template from disk (or elsewhere), and returns a tuple:
|
||||
``(template_string, template_origin)``.
|
||||
|
||||
The ``load_template()`` method of the ``Loader`` class retrieves the template
|
||||
string by calling ``load_template_source()``, instantiates a ``Template`` from
|
||||
the template source, and returns a tuple: ``(template, template_origin)``. Since
|
||||
this is the method that actually instantiates the ``Template``, we'll need to
|
||||
override it to use our custom template class instead. We can inherit from the
|
||||
builtin ``django.template.loaders.app_directories.Loader`` to take advantage of
|
||||
the ``load_template_source()`` method implemented there::
|
||||
|
||||
from django.template.loaders import app_directories
|
||||
class Loader(app_directories.Loader):
|
||||
is_usable = True
|
||||
|
||||
def load_template(self, template_name, template_dirs=None):
|
||||
source, origin = self.load_template_source(template_name, template_dirs)
|
||||
template = Template(source)
|
||||
return template, origin
|
||||
|
||||
Finally, we need to modify our project settings, telling Django to use our custom
|
||||
loader. Now we can write all of our templates in our alternative template
|
||||
language while continuing to use the rest of the Django templating system.
|
||||
|
||||
@@ -218,6 +218,20 @@ database specific conversions, then you will need to provide an
|
||||
implementation ``get_db_prep_*`` that uses the ``connection``
|
||||
argument to resolve database-specific values.
|
||||
|
||||
Stateful template tags
|
||||
----------------------
|
||||
|
||||
Template tags that store rendering state on the node itself may experience
|
||||
problems if they are used with the new :ref:`cached
|
||||
template loader<template-loaders>`.
|
||||
|
||||
All of the built-in Django template tags are safe to use with the cached
|
||||
loader, but if you're using custom template tags that come from third
|
||||
party packages, or that you wrote yourself, you should ensure that the
|
||||
``Node`` implementation for each tag is thread-safe. For more
|
||||
information, see
|
||||
:ref:`template tag thread safety considerations<template_tag_thread_safety>`.
|
||||
|
||||
.. _deprecated-features-1.2:
|
||||
|
||||
Features deprecated in 1.2
|
||||
@@ -271,11 +285,11 @@ additional arguments, those arguments can be passed to the
|
||||
:meth:`~django.core.mail.get_connection()` call::
|
||||
|
||||
connection = get_connection('django.core.mail.backends.smtp', hostname='localhost', port=1234)
|
||||
|
||||
|
||||
User Messages API
|
||||
-----------------
|
||||
|
||||
The API for storing messages in the user ``Message`` model (via
|
||||
The API for storing messages in the user ``Message`` model (via
|
||||
``user.message_set.create``) is now deprecated and will be removed in Django
|
||||
1.4 according to the standard :ref:`release process <internals-release-process>`.
|
||||
|
||||
@@ -288,20 +302,20 @@ with the following::
|
||||
from django.contrib import messages
|
||||
messages.add_message(request, messages.INFO, 'a message')
|
||||
|
||||
Additionally, if you make use of the method, you need to replace the
|
||||
Additionally, if you make use of the method, you need to replace the
|
||||
following::
|
||||
|
||||
for message in user.get_and_delete_messages():
|
||||
...
|
||||
|
||||
|
||||
with::
|
||||
|
||||
from django.contrib import messages
|
||||
for message in messages.get_messages(request):
|
||||
...
|
||||
|
||||
For more information, see the full
|
||||
:ref:`messages documentation <ref-contrib-messages>`. You should begin to
|
||||
|
||||
For more information, see the full
|
||||
:ref:`messages documentation <ref-contrib-messages>`. You should begin to
|
||||
update your code to use the new API immediately.
|
||||
|
||||
What's new in Django 1.2
|
||||
@@ -389,3 +403,28 @@ Also, filters may now be used in the ``if`` expression. For example:
|
||||
class="highlight"
|
||||
{% endif %}
|
||||
>{{ message }}</div>
|
||||
|
||||
Template caching
|
||||
----------------
|
||||
|
||||
In previous versions of Django, every time you rendered a template it
|
||||
would be reloaded from disk. In Django 1.2, you can use a :ref:`cached
|
||||
template loader <template-loaders>` to load templates once, then use a
|
||||
cached the result for every subsequent render. This can lead to a
|
||||
significant performance improvement if your templates are broken into
|
||||
lots of smaller subtemplates (using the ``{% extends %}`` or ``{%
|
||||
include %}`` tags).
|
||||
|
||||
As a side effect, it is now much easier to support non-Django template
|
||||
languages. For more details, see the :ref:`notes on supporting
|
||||
non-Django template languages<topic-template-alternate-language>`.
|
||||
|
||||
Natural keys in fixtures
|
||||
------------------------
|
||||
|
||||
Fixtures can refer to remote objects using
|
||||
:ref:`topics-serialization-natural-keys`. This lookup scheme is an
|
||||
alternative to the normal primary-key based object references in a
|
||||
fixture, improving readability, and resolving problems referring to
|
||||
objects whose primary key value may not be predictable or known.
|
||||
|
||||
|
||||
@@ -154,10 +154,10 @@ to install third-party Python modules:
|
||||
.. _PyYAML: http://www.pyyaml.org/
|
||||
|
||||
Notes for specific serialization formats
|
||||
----------------------------------------
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
json
|
||||
~~~~
|
||||
^^^^
|
||||
|
||||
If you're using UTF-8 (or any other non-ASCII encoding) data with the JSON
|
||||
serializer, you must pass ``ensure_ascii=False`` as a parameter to the
|
||||
@@ -191,3 +191,191 @@ them. Something like this will work::
|
||||
|
||||
.. _special encoder: http://svn.red-bean.com/bob/simplejson/tags/simplejson-1.7/docs/index.html
|
||||
|
||||
.. _topics-serialization-natural-keys:
|
||||
|
||||
Natural keys
|
||||
------------
|
||||
|
||||
The default serialization strategy for foreign keys and many-to-many
|
||||
relations is to serialize the value of the primary key(s) of the
|
||||
objects in the relation. This strategy works well for most types of
|
||||
object, but it can cause difficulty in some circumstances.
|
||||
|
||||
Consider the case of a list of objects that have foreign key on
|
||||
:class:`ContentType`. If you're going to serialize an object that
|
||||
refers to a content type, you need to have a way to refer to that
|
||||
content type. Content Types are automatically created by Django as
|
||||
part of the database synchronization process, so you don't need to
|
||||
include content types in a fixture or other serialized data. As a
|
||||
result, the primary key of any given content type isn't easy to
|
||||
predict - it will depend on how and when :djadmin:`syncdb` was
|
||||
executed to create the content types.
|
||||
|
||||
There is also the matter of convenience. An integer id isn't always
|
||||
the most convenient way to refer to an object; sometimes, a
|
||||
more natural reference would be helpful.
|
||||
|
||||
Deserialization of natural keys
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
It is for these reasons that Django provides `natural keys`. A natural
|
||||
key is a tuple of values that can be used to uniquely identify an
|
||||
object instance without using the primary key value.
|
||||
|
||||
Consider the following two models::
|
||||
|
||||
from django.db import models
|
||||
|
||||
class Person(models.Model):
|
||||
first_name = models.CharField(max_length=100)
|
||||
last_name = models.CharField(max_length=100)
|
||||
|
||||
birthdate = models.DateField()
|
||||
|
||||
class Book(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
author = models.ForeignKey(Person)
|
||||
|
||||
Ordinarily, serialized data for ``Book`` would use an integer to refer to
|
||||
the author. For example, in JSON, a Book might be serialized as::
|
||||
|
||||
...
|
||||
{
|
||||
"pk": 1,
|
||||
"model": "store.book",
|
||||
"fields": {
|
||||
"name": "Mostly Harmless",
|
||||
"author": 42
|
||||
}
|
||||
}
|
||||
...
|
||||
|
||||
This isn't a particularly natural way to refer to an author. It
|
||||
requires that you know the primary key value for the author; it also
|
||||
requires that this primary key value is stable and predictable.
|
||||
|
||||
However, if we add natural key handling to Person, the fixture becomes
|
||||
much more humane. To add natural key handling, you define a default
|
||||
Manager for Person with a ``get_by_natural_key()`` method. In the case
|
||||
of a Person, a good natural key might be the pair of first and last
|
||||
name::
|
||||
|
||||
from django.db import models
|
||||
|
||||
class PersonManager(models.Manager):
|
||||
def get_by_natural_key(self, first_name, last_name):
|
||||
return self.filter(first_name=first_name, last_name=last_name)
|
||||
|
||||
class Person(models.Model):
|
||||
objects = PersonManager()
|
||||
|
||||
first_name = models.CharField(max_length=100)
|
||||
last_name = models.CharField(max_length=100)
|
||||
|
||||
birthdate = models.DateField()
|
||||
|
||||
Now books can use that natural key to refer to ``Person`` objects::
|
||||
|
||||
...
|
||||
{
|
||||
"pk": 1,
|
||||
"model": "store.book",
|
||||
"fields": {
|
||||
"name": "Mostly Harmless",
|
||||
"author": ["Douglas", "Adams"]
|
||||
}
|
||||
}
|
||||
...
|
||||
|
||||
When you try to load this serialized data, Django will use the
|
||||
``get_by_natural_key()`` method to resolve ``["Douglas", "Adams"]``
|
||||
into the primary key of an actual ``Person`` object.
|
||||
|
||||
Serialization of natural keys
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
So how do you get Django to emit a natural key when serializing an object?
|
||||
Firstly, you need to add another method -- this time to the model itself::
|
||||
|
||||
class Person(models.Model):
|
||||
objects = PersonManager()
|
||||
|
||||
first_name = models.CharField(max_length=100)
|
||||
last_name = models.CharField(max_length=100)
|
||||
|
||||
birthdate = models.DateField()
|
||||
|
||||
def natural_key(self):
|
||||
return (self.first_name, self.last_name)
|
||||
|
||||
Then, when you call ``serializers.serialize()``, you provide a
|
||||
``use_natural_keys=True`` argument::
|
||||
|
||||
>>> serializers.serialize([book1, book2], format='json', indent=2, use_natural_keys=True)
|
||||
|
||||
When ``use_natural_keys=True`` is specified, Django will use the
|
||||
``natural_key()`` method to serialize any reference to objects of the
|
||||
type that defines the method.
|
||||
|
||||
If you are using :djadmin:`dumpdata` to generate serialized data, you
|
||||
use the `--natural` command line flag to generate natural keys.
|
||||
|
||||
.. note::
|
||||
|
||||
You don't need to define both ``natural_key()`` and
|
||||
``get_by_natural_key()``. If you don't want Django to output
|
||||
natural keys during serialization, but you want to retain the
|
||||
ability to load natural keys, then you can opt to not implement
|
||||
the ``natural_key()`` method.
|
||||
|
||||
Conversely, if (for some strange reason) you want Django to output
|
||||
natural keys during serialization, but *not* be able to load those
|
||||
key values, just don't define the ``get_by_natural_key()`` method.
|
||||
|
||||
Dependencies during serialization
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Since natural keys rely on database lookups to resolve references, it
|
||||
is important that data exists before it is referenced. You can't make
|
||||
a `forward reference` with natural keys - the data you are referencing
|
||||
must exist before you include a natural key reference to that data.
|
||||
|
||||
To accommodate this limitation, calls to :djadmin:`dumpdata` that use
|
||||
the :djadminopt:`--natural` optionwill serialize any model with a
|
||||
``natural_key()`` method before it serializes normal key objects.
|
||||
|
||||
However, this may not always be enough. If your natural key refers to
|
||||
another object (by using a foreign key or natural key to another object
|
||||
as part of a natural key), then you need to be able to ensure that
|
||||
the objects on which a natural key depends occur in the serialized data
|
||||
before the natural key requires them.
|
||||
|
||||
To control this ordering, you can define dependencies on your
|
||||
``natural_key()`` methods. You do this by setting a ``dependencies``
|
||||
attribute on the ``natural_key()`` method itself.
|
||||
|
||||
For example, consider the ``Permission`` model in ``contrib.auth``.
|
||||
The following is a simplified version of the ``Permission`` model::
|
||||
|
||||
class Permission(models.Model):
|
||||
name = models.CharField(max_length=50)
|
||||
content_type = models.ForeignKey(ContentType)
|
||||
codename = models.CharField(max_length=100)
|
||||
# ...
|
||||
def natural_key(self):
|
||||
return (self.codename,) + self.content_type.natural_key()
|
||||
|
||||
The natural key for a ``Permission`` is a combination of the codename for the
|
||||
``Permission``, and the ``ContentType`` to which the ``Permission`` applies. This means
|
||||
that ``ContentType`` must be serialized before ``Permission``. To define this
|
||||
dependency, we add one extra line::
|
||||
|
||||
class Permission(models.Model):
|
||||
# ...
|
||||
def natural_key(self):
|
||||
return (self.codename,) + self.content_type.natural_key()
|
||||
natural_key.dependencies = ['contenttypes.contenttype']
|
||||
|
||||
This definition ensures that ``ContentType`` models are serialized before
|
||||
``Permission`` models. In turn, any object referencing ``Permission`` will
|
||||
be serialized after both ``ContentType`` and ``Permission``.
|
||||
|
||||
Reference in New Issue
Block a user