If you are running a Django application, hopefully you have regular backups of the DB. We had a customer who realized they deleted something over a month ago and needed the deleted objects restored. Instead of just reverting the entire DB and losing all of the new information, I wrote a simple script that will create a fixture of everything that was deleted that can then be used with loaddata.
Thanks goes to Constantin Berzan for how to programmatically enumerate objects that will get cascade-deleteded in Django.
Step By Step
- In a local development environment restore the DB to the version with the objects you need to restore into production.
- Run python manage.py shell
- In the shell type execfile('dump_partial.py') where ‘dump_partial.py’ is what you named your customized version of the script below.
- On the production environment, place the dump.json file generated in step 3 in the same directory as manage.py and run python manage.py loaddata dump.json
Save this file in the same directory as your Django manage.py on your local development environment. Update what you need to dump as needed
from APP.models import MODELNAME # Update Me to include the models from your Django app that you need to restore
from django.contrib.admin.util import NestedObjects
from django.db import DEFAULT_DB_ALIAS
from django.core import serializers
restore_me = MODEL.objects.filter(id=ID_OF_OBJECT_TO_RESTORE) # Update to get the item that was deleted.
collector = NestedObjects(using=DEFAULT_DB_ALIAS)
# This generates a hierarchical list of all of the objects related to the object that was deleted.
# The same output that Django creates when it prompts you for confirmation to delete something.
result = collector.nested()
output = '[' # Start the json string.
global output # I cringe when I write this, but for the sake of what this script is doing simple is fine.
for model in obj:
if not isinstance(model, list):
# Ignore many to many tables as they are included in the primary object serialization
if "_" not in model.__class__.__name__:
# Use Django's built in serializer, and strip off the array brackets
output += serializers.serialize("json", [model])[1:-1]
# append a comma
output += ","
json_dump(model) # Yay for recursion
output = output[:-1] + "]" # remove the last comma and add the ending array bracket.
with open("dump.json", "w+") as dump:
# dump it to a file