Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I export an instance and all its related objects in Django?

Someone accidentally deleted an instance and all the related objects (through the Django admin) in production. I have a backup of the database, so I can get those data back, but I would like to do it with a script rather than copy the data manually, since it includes a lot of related objects.

I would like to retrieve the item that has been deleted (I do have its model and its pk, so I can do MyModel.objects.get(pk=123456)), but also all its related objects (ForeignKey, ManyToMany...) in a way to re-import them in the production database.

It can be either in SQL or any serialized format, to use loaddata. How can I do that?

like image 542
Maxime Lorant Avatar asked May 11 '15 13:05

Maxime Lorant


1 Answers

To achieve that, you need to combine the collection of related objects and their serialization. Since you know the exact model instance that have been deleted, you can first get all the objects deleted (the same way that the django admin does, with a NestedObjects collector) and then iterating on this list to generate a json.

The more appropriate is to do a one-time script (note Sept 2016: updated for Django >= 1.9):

from itertools import chain      

from django.core import serializers
from django.contrib.admin.utils import NestedObjects

from myproject.myapp.models import MyModel

collector = NestedObjects(using="default") # database name
collector.collect([MyModel.objects.get(pk=123456)])

objects = list(chain.from_iterable(collector.data.values()))
with open("backup_export.json", "w") as f:
    f.write(serializers.serialize("json", objects))

This will produce a json file with all the instances that have been deleted. You can now use manage.py loaddata to put them back on your production database. When re-importing the json, you should deactivate the post_save signal, otherwise it can failed sometimes with complex dependencies.

like image 185
Maxime Lorant Avatar answered Oct 04 '22 16:10

Maxime Lorant