mirror of
				https://github.com/django/django.git
				synced 2025-11-04 13:39:16 +00:00 
			
		
		
		
	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
					
				
					 2 changed files with 41 additions and 4 deletions
				
			
		| 
						 | 
					@ -161,9 +161,7 @@ class DeserializedObject(object):
 | 
				
			||||||
    def save(self, save_m2m=True, using=None):
 | 
					    def save(self, save_m2m=True, using=None):
 | 
				
			||||||
        # Call save on the Model baseclass directly. This bypasses any
 | 
					        # Call save on the Model baseclass directly. This bypasses any
 | 
				
			||||||
        # model-defined save. The save is also forced to be raw.
 | 
					        # model-defined save. The save is also forced to be raw.
 | 
				
			||||||
        # This ensures that the data that is deserialized is literally
 | 
					        # raw=True is passed to any pre/post_save signals.
 | 
				
			||||||
        # what came from the file, not post-processed by pre_save/save
 | 
					 | 
				
			||||||
        # methods.
 | 
					 | 
				
			||||||
        models.Model.save_base(self.object, using=using, raw=True)
 | 
					        models.Model.save_base(self.object, using=using, raw=True)
 | 
				
			||||||
        if self.m2m_data and save_m2m:
 | 
					        if self.m2m_data and save_m2m:
 | 
				
			||||||
            for accessor_name, object_list in self.m2m_data.items():
 | 
					            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``.
 | 
					: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.
 | 
					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,
 | 
					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
 | 
					all fixture data is installed as a single transaction, so data in
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue