diff --git a/django/core/serializers/base.py b/django/core/serializers/base.py index 294934a04a0..1e78026c409 100644 --- a/django/core/serializers/base.py +++ b/django/core/serializers/base.py @@ -161,9 +161,7 @@ class DeserializedObject(object): 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(): diff --git a/docs/ref/django-admin.txt b/docs/ref/django-admin.txt index 8caa81180e4..412618f2f21 100644 --- a/docs/ref/django-admin.txt +++ b/docs/ref/django-admin.txt @@ -344,7 +344,46 @@ application, ``/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