"post_save" signal should not be emitted when using manage.py "loaddata"
|Reported by:||Si Feng||Owned by:||nobody|
|Severity:||Normal||Keywords:||loaddata, post_save, signal, management commands|
|Has patch:||no||Needs documentation:||no|
|Needs tests:||no||Patch needs improvement:||no|
I spent some time on migrating database from MySQL to PostgreSQL. I used "dumpdata" to dump all data from MySQL into json ("pure" data, better than MySQL raw dump and then convert to PostgreSQL, which will cause losing some database specific features). Then I created a new database in PostgreSQL, and "syncdb". I also didn't forget to wipe it out completed by running "python manage.py sqlflush | psql -U myusername mydatabase".
However when I used "loaddata", I always get error (unique key conflict or something). I checked the database and it has nothing. I was confused.
Finally I found that in a few models of mine, I actually used "post_save" signal to create instance after a new User instance was created, like this:
def create_stat(sender, instance, created, **kwargs): if created: Stat.objects.create(user=instance) post_save.connect(create_stat, sender=User)
The Stat is like an extension to the User and it has a OneToOneField "user" to the User instance.
By commenting out the above post_save callback, the data was imported correctly into PostgreSQL. Then after resetting sequences, the migration was done.
So the reason is now clear: when "loaddata" loads data from json and creates a User instance, the "post_save" signal will always be emitted, resulting a new Stat instance is created as well. Then when loading the actually Stat data from json, error will occur since there is already a Stat instance for each User.
I'm not sure if using "post_save" signal in my case is a good practice (I just wanted to automatically create some instances when a new user is created. I know I can also put some check code in views and create instances if there is none, but that would look ugly). But I'm thinking perhaps "loaddata" could provide an option to temporarily disable emitting signals when loading data? I mean when someone is "loading" data it usually means the data should be completed "loaded" rather than "running bulk save" which could cause problems by signals/transactions/etc.