Fixed #16364 -- Clarified why automatically created data shouldn't be saved in fixtures. Thanks Gabriel for the review.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17355 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Aymeric Augustin 2012-01-07 21:52:07 +00:00
parent c51c9b3ce6
commit d101ed2cb8
1 changed files with 40 additions and 35 deletions

View File

@ -198,23 +198,32 @@ Natural keys
------------
.. versionadded:: 1.2
The ability to use natural keys when serializing/deserializing data was
added in the 1.2 release.
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.
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 objects, 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.
Consider the case of a list of objects that have a foreign key referencing
:class:`~django.contrib.conttenttypes.models.ContentType`. If you're going to
serialize an object that refers to a content type, then you need to have a way
to refer to that content type to begin with. Since ``ContentType`` objects are
automatically created by Django during the database synchronization process,
the primary key of a given content type isn't easy to predict; it will
depend on how and when :djadmin:`syncdb` was executed. This is true for all
models which automatically generate objects, notably including
:class:`~django.contrib.auth.models.Permission`.
.. warning::
You should never include automatically generated objects in a fixture or
other serialized data. By chance, the primary keys in the fixture
may match those in the database and loading the fixture will
have no effect. In the more likely case that they don't match, the fixture
loading will fail with an :class:`~django.db.IntegrityError`.
There is also the matter of convenience. An integer id isn't always
the most convenient way to refer to an object; sometimes, a
@ -363,13 +372,13 @@ 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
is important that the 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` option will serialize any model with a
``natural_key()`` method before it serializes normal key objects.
``natural_key()`` method before serializing standard primary 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
@ -381,28 +390,24 @@ 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::
For example, let's add a natural key to the ``Book`` model from the
example above::
class Book(models.Model):
name = models.CharField(max_length=100)
author = models.ForeignKey(Person)
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()
return (self.name,) + self.author.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::
The natural key for a ``Book`` is a combination of its name and its
author. This means that ``Person`` must be serialized before ``Book``.
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']
return (self.name,) + self.author.natural_key()
natural_key.dependencies = ['example_app.person']
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``.
This definition ensures that all ``Person`` objects are serialized before
any ``Book`` objects. In turn, any object referencing ``Book`` will be
serialized after both ``Person`` and ``Book`` have been serialized.