mirror of https://github.com/django/django.git
Fixed #20136 - Fixed and expanded the docs for loaddata and model signals.
Thanks brandon@ and Anssi for the report.
This commit is contained in:
parent
679a2ac843
commit
2c62a509de
|
@ -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():
|
||||
|
|
|
@ -373,7 +373,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
|
||||
|
|
Loading…
Reference in New Issue