Skip to content

Commit

Permalink
[1.5.X] Fixed #20136 - Fixed and expanded the docs for loaddata and m…
Browse files Browse the repository at this point in the history
…odel signals.

Thanks brandon@ and Anssi for the report.

Backport of 2c62a50 from master
  • Loading branch information
timgraham committed May 11, 2013
1 parent 13de270 commit 18a2fb1
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 4 deletions.
4 changes: 1 addition & 3 deletions django/core/serializers/base.py
Expand Up @@ -161,9 +161,7 @@ def __repr__(self):
def save(self, save_m2m=True, using=None):
# Call save on the Model baseclass directly. This bypasses any
# model-defined save. The save is also forced to be raw.
# This ensures that the data that is deserialized is literally
# what came from the file, not post-processed by pre_save/save
# methods.
# raw=True is passed to any pre/post_save signals.
models.Model.save_base(self.object, using=using, raw=True)
if self.m2m_data and save_m2m:
for accessor_name, object_list in self.m2m_data.items():
Expand Down
41 changes: 40 additions & 1 deletion docs/ref/django-admin.txt
Expand Up @@ -344,7 +344,46 @@ application, ``<dirname>/foo/bar/mydata.json`` for each directory in
:setting:`FIXTURE_DIRS`, and the literal path ``foo/bar/mydata.json``.

When fixture files are processed, the data is saved to the database as is.
Model defined ``save`` methods and ``pre_save`` signals are not called.
Model defined :meth:`~django.db.models.Model.save` methods are not called, and
any :data:`~django.db.models.signals.pre_save` or
:data:`~django.db.models.signals.post_save` signals will be called with
``raw=True`` since the instance only contains attributes that are local to the
model. You may, for example, want to disable handlers that access
related fields that aren't present during fixture loading and would otherwise
raise an exception::

from django.db.models.signals import post_save
from .models import MyModel

def my_handler(**kwargs):
# disable the handler during fixture loading
if kwargs['raw']:
return
...

post_save.connect(my_handler, sender=MyModel)

You could also write a simple decorator to encapsulate this logic::

from functools import wraps

def disable_for_loaddata(signal_handler):
"""
Decorator that turns off signal handlers when loading fixture data.
"""
@wraps(signal_handler)
def wrapper(*args, **kwargs):
if kwargs['raw']:
return
signal_handler(*args, **kwargs)
return wrapper

@disable_for_loaddata
def my_handler(**kwargs):
...

Just be aware that this logic will disable the signals whenever fixtures are
deserialized, not just during ``loaddata``.

Note that the order in which fixture files are processed is undefined. However,
all fixture data is installed as a single transaction, so data in
Expand Down

0 comments on commit 18a2fb1

Please sign in to comment.