mirror of
				https://github.com/django/django.git
				synced 2025-10-30 17:16:10 +00:00 
			
		
		
		
	[1.5.X] Fixed #20136 - Fixed and expanded the docs for loaddata and model signals.
Thanks brandon@ and Anssi for the report.
Backport of 2c62a509de from master
			
			
This commit is contained in:
		| @@ -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(): | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user