Opened 7 years ago

Closed 4 years ago

#13299 closed Bug (duplicate)

Handicapped objects passed to models signals during loaddata

Reported by: Patryk Zawadzki Owned by: nobody
Component: Documentation Version: 1.2-beta
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


The documentation:

...states that actual model instances are to be expected in post_save and pre_save signals.

This is not the case during loaddata. Models that use natural python inheritance (not proxy or abstract) are passed as handicapped instances that only have their own fields filled. This breaks signals that try to access any of the fields of the parent model. This happens because loaddata passes raw=True to the save method.

Consider the following:

class Foo(models.Model):
    foo_field = models.IntegerField(default=0)

class Bar(Foo):
    bar_field = models.IntegerField(default=0)

During loaddata the instance is passed as follows: = None
instance.foo_field = 0
instance.bar_field = 3


instance.foo_ptr_id = 1 = 1
instance.foo_ptr.foo_field = 2

I can think of three solutions:

  1. document it throughly and suggest doing something like:
    if not instance = instance.__class__.objects.get(
  1. make save_base reconstruct the object before calling signals
  1. ignore signals at all during raw object saves

Change History (8)

comment:1 Changed 7 years ago by Patryk Zawadzki

Needs documentation: unset
Needs tests: unset
Patch needs improvement: unset

Ok, after consulting current trunk I see that raw kwarg is already being passed to the signal so I guess this is a documentation request.

Maybe something like:

There are some rare cases (for example during fixture loading) when your post_save and pre_save signal handlers receive a "raw" instance. This is signalled by passing True for the raw keyword argument. "Raw" instances do not contain any fields inherited from the parent model. If your application relies on model inheritance, make sure you take this into account. You can get a regular instance by using code below:

if raw:
    instance = instance.__class__._default_manager.get(

comment:2 Changed 7 years ago by Russell Keith-Magee

Component: UncategorizedDocumentation
Triage Stage: UnreviewedAccepted

The issue is that when you call loaddata, we are specifically saving only the attributes that are local to the model; if we don't do this, we get a bunch of extra objects created up the inheritance hierarchy. This is what the raw save does. As a consequence of this, we don't actually have access to the values for the parent fields at time of save.

I think you're right that this may need to be a documentation fix; doing the database lookup to populate the parent fields will be expensive for anyone that doesn't need it.

comment:3 Changed 7 years ago by Patryk Zawadzki

Yes, I understand why parent object data is not available when loading a fixture and agree that doing an extra select for each insert is not a good idea.

Documenting raw=True would also let people skip signals during loading of fixtures. This might be the desired behavior if the fixture also contains objects normally created by post_save.

comment:4 Changed 6 years ago by Julien Phalip

Severity: Normal
Type: Bug

comment:5 Changed 5 years ago by Aymeric Augustin

UI/UX: unset

Change UI/UX from NULL to False.

comment:6 Changed 5 years ago by Aymeric Augustin

Easy pickings: unset

Change Easy pickings from NULL to False.

comment:7 Changed 4 years ago by Julien Phalip

See also #8399 which suggests adding a new pre_loaddata signal.

comment:8 Changed 4 years ago by Tim Graham

Resolution: duplicate
Status: newclosed

The documentation update is addressed in the patch for #20136.

Note: See TracTickets for help on using tickets.
Back to Top