This utility makes a text dump of a model instance, including objects related by a forward or reverse foreign key. The result is a hierarchical data structure where
-
each instance is represented as a list of fields,
-
each field as a (<name>, <value>) tuple,
-
each <value> as a primitive type, a related object (as a list of fields), or a list of related objects.
See the docstring for examples.
We used this to make text dumps of parts of the database before and after running a batch job. The format was more useful than stock dumpdata
output since all related data is included with each object. These dumps lend themselves particularly well for comparison with a visual diff tool like Meld.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | from django.db import models
def shift_paths(exclude, name):
return tuple(item.split('.', 1)[1] for item in exclude
if item.startswith(('{0}.'.format(name), '*.')))
def deep_dump_instance(instance,
depth=1,
exclude=(),
include=(),
order_by=(),
seen=None):
"""Deep-dumps fields of a model instance as (name, value) tuples
Examples::
# create a fixture
>>> my_poll = Poll.objects.create(question=u"What's up?",
pub_date=datetime.datetime.now())
>>> choice_1 = my_poll.choice_set.create(choice='Not much', votes=5)
>>> choice_2.choice_set.create(choice='The sky', votes=2)
# recurse all related objects
>>> deep_dump_instance(my_poll)
[('question', u"What's up?"),
('pub_date', datetime.datetime(2012, 1, 30, 9, 48)),
('choice_set',
[[('choice', u'Not much'), ('votes', 5)],
[('choice', u'The sky'), ('votes', 2)]])]
# skip all related objects
>>> deep_dump_instance(my_poll, depth=0)
[('question', u"What's up?"),
('pub_date', datetime.datetime(2012, 1, 30, 9, 48))]
# exclude a field
>>> deep_dump_instance(my_poll, exclude=['pub_date'])
[('question', u"What's up?"),
('choice_set',
[[('choice', u'Not much'), ('votes', 5)],
[('choice', u'The sky'), ('votes', 2)]])]
# only include a field in related objects
>>> deep_dump_instance(choice_1,
... exclude=['*', 'question.*'],
... include=['poll', 'poll.pub_date'])
[[('poll',
[('pub_date', datetime.datetime(2012, 1, 30, 9, 48))])]]
# sort related objects
>>> deep_dump_instance(my_poll,
... exclude=['*'],
... include=['choice_set'],
... order_by=['choice_set.votes'])
[('choice_set',
[[('choice', u'The sky'), ('votes', 2)],
[('choice', u'Not much'), ('votes', 5)]])]
"""
if not seen:
seen = set()
if (instance.__class__, instance.pk) in seen:
return '<recursive>'
seen.add((instance.__class__, instance.pk))
field_names = sorted(
[field.name for field in instance._meta.fields] +
[f.get_accessor_name() for f in instance._meta.get_all_related_objects()])
dump = []
exclude_all = '*' in exclude
for name in field_names:
if name in include or (not exclude_all and name not in exclude):
try:
value = getattr(instance, name)
except models.ObjectDoesNotExist:
value = None
if value.__class__.__name__ == 'RelatedManager':
if depth >= 1:
related_objects = value.all()
for ordering in order_by:
parts = ordering.split('.')
if len(parts) == 2 and parts[0] == name:
related_objects = related_objects.order_by(parts[1])
value = [deep_dump_instance(related,
depth=depth-1,
exclude=shift_paths(exclude, name),
include=shift_paths(include, name),
order_by=shift_paths(order_by, name),
seen=seen)
for related in related_objects]
else:
continue
elif isinstance(value, models.Model):
if depth >= 1:
value = deep_dump_instance(value,
depth=depth-1,
exclude=shift_paths(exclude, name),
include=shift_paths(include, name),
order_by=shift_paths(order_by, name),
seen=seen)
else:
continue
dump.append((name, value))
return dump
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 6 months ago
Comments
Interesting. Is there a way to "load" the data back?
#
Please login first before commenting.