Skip to content

Commit 6e9e193

Browse files
committed
Added a makefixture management command, from http://djangosnippets.org/snippets/918/, somewhat hacked.
- Legacy-Id: 6307
1 parent a758639 commit 6e9e193

3 files changed

Lines changed: 153 additions & 0 deletions

File tree

ietf/utils/management/__init__.py

Whitespace-only changes.

ietf/utils/management/commands/__init__.py

Whitespace-only changes.
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
# From http://djangosnippets.org/snippets/918/
2+
3+
#save into anyapp/management/commands/makefixture.py
4+
#or back into django/core/management/commands/makefixture.py
5+
#v0.1 -- current version
6+
#known issues:
7+
#no support for generic relations
8+
#no support for one-to-one relations
9+
from optparse import make_option
10+
from django.core import serializers
11+
from django.core.management.base import BaseCommand
12+
from django.core.management.base import CommandError
13+
from django.core.management.base import LabelCommand
14+
from django.db.models.fields.related import ForeignKey
15+
from django.db.models.fields.related import ManyToManyField
16+
from django.db.models.loading import get_models
17+
18+
import debug
19+
20+
DEBUG = False
21+
22+
def model_name(m):
23+
module = m.__module__.split('.')[:-1] # remove .models
24+
return ".".join(module + [m._meta.object_name])
25+
26+
class Command(LabelCommand):
27+
help = 'Output the contents of the database as a fixture of the given format.'
28+
args = 'modelname[pk] or modelname[id1:id2] repeated one or more times'
29+
option_list = BaseCommand.option_list + (
30+
make_option('--skip-related', default=True, action='store_false', dest='propagate',
31+
help='Specifies if we shall not add related objects.'),
32+
make_option('--format', default='json', dest='format',
33+
help='Specifies the output serialization format for fixtures.'),
34+
make_option('--indent', default=None, dest='indent', type='int',
35+
help='Specifies the indent level to use when pretty-printing output'),
36+
make_option('--include-reverse', default=False, action='store_true', dest='reverse',
37+
help='Add reverse related objects too'),
38+
)
39+
40+
def handle_models(self, models, **options):
41+
format = options.get('format','json')
42+
indent = options.get('indent',None)
43+
show_traceback = options.get('traceback', False)
44+
propagate = options.get('propagate', True)
45+
opt_reverse = options.get('reverse', False)
46+
47+
# Check that the serialization format exists; this is a shortcut to
48+
# avoid collating all the objects and _then_ failing.
49+
if format not in serializers.get_public_serializer_formats():
50+
raise CommandError("Unknown serialization format: %s" % format)
51+
52+
try:
53+
serializers.get_serializer(format)
54+
except KeyError:
55+
raise CommandError("Unknown serialization format: %s" % format)
56+
57+
objects = []
58+
for model, slice in models:
59+
if isinstance(slice, basestring):
60+
objects.extend(model._default_manager.filter(pk__exact=slice))
61+
elif not slice or type(slice) is list:
62+
items = model._default_manager.all()
63+
if slice and slice[0]:
64+
items = items.filter(pk__gte=slice[0])
65+
if slice and slice[1]:
66+
items = items.filter(pk__lt=slice[1])
67+
items = items.order_by(model._meta.pk.attname)
68+
objects.extend(items)
69+
else:
70+
raise CommandError("Wrong slice: %s" % slice)
71+
72+
all = objects
73+
collected = set([(x.__class__, x.pk) for x in all])
74+
75+
if opt_reverse:
76+
related = []
77+
for x in objects:
78+
attribs = []
79+
for name in dir(x):
80+
try:
81+
attribs.append(getattr(x, name))
82+
except AttributeError:
83+
pass
84+
for o in attribs:
85+
if "django.db.models.fields.related.RelatedManager object" in repr(o):
86+
for new in o.all():
87+
collected.add((new.__class__, new.pk))
88+
related.append(new)
89+
all.extend(related)
90+
91+
if propagate:
92+
while objects:
93+
related = []
94+
for x in objects:
95+
if DEBUG:
96+
print "Adding %s[%s]" % (model_name(x), x.pk)
97+
for f in x.__class__._meta.fields + x.__class__._meta.many_to_many:
98+
if isinstance(f, ForeignKey):
99+
new = getattr(x, f.name) # instantiate object
100+
if new and not (new.__class__, new.pk) in collected:
101+
collected.add((new.__class__, new.pk))
102+
related.append(new)
103+
if isinstance(f, ManyToManyField):
104+
for new in getattr(x, f.name).all():
105+
if new and not (new.__class__, new.pk) in collected:
106+
collected.add((new.__class__, new.pk))
107+
related.append(new)
108+
objects = related
109+
all.extend(related)
110+
111+
try:
112+
return serializers.serialize(format, all, indent=indent)
113+
except Exception, e:
114+
if show_traceback:
115+
raise
116+
raise CommandError("Unable to serialize database: %s" % e)
117+
118+
def get_models(self):
119+
return [(m, model_name(m)) for m in get_models()]
120+
121+
def handle_label(self, labels, **options):
122+
parsed = []
123+
for label in labels:
124+
search, pks = label, ''
125+
if '[' in label:
126+
search, pks = label.split('[', 1)
127+
slice = ''
128+
if ':' in pks:
129+
slice = pks.rstrip(']').split(':', 1)
130+
elif pks:
131+
slice = pks.rstrip(']')
132+
models = [model for model, name in self.get_models()
133+
if name.endswith('.'+search) or name == search]
134+
if not models:
135+
raise CommandError("Wrong model: %s" % search)
136+
if len(models)>1:
137+
raise CommandError("Ambiguous model name: %s" % search)
138+
parsed.append((models[0], slice))
139+
return self.handle_models(parsed, **options)
140+
141+
def list_models(self):
142+
names = [name for _model, name in self.get_models()]
143+
raise CommandError('Neither model name nor slice given. Installed model names: \n%s' % ",\n".join(names))
144+
145+
def handle(self, *labels, **options):
146+
if not labels:
147+
self.list_models()
148+
149+
output = []
150+
label_output = self.handle_label(labels, **options)
151+
if label_output:
152+
output.append(label_output)
153+
return '\n'.join(output)

0 commit comments

Comments
 (0)