Instantly share code, notes, and snippets.
Last active
August 29, 2015 14:02
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save zhangshine/58befa3cab5d84622c30 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#save into anyapp/management/commands/makefixture.py | |
#or back into django/core/management/commands/makefixture.py | |
#v0.1 -- current version | |
#known issues: | |
#no support for generic relations | |
#no support for one-to-one relations | |
from django.core import serializers | |
from django.core.management.base import BaseCommand | |
from django.core.management.base import CommandError | |
from django.core.management.base import LabelCommand | |
from django.db.models.fields.related import ForeignKey | |
from django.db.models.fields.related import ManyToManyField | |
from django.db.models.loading import get_models | |
DEBUG = False | |
def model_name(m): | |
module = m.__module__.split('.')[:-1] # remove .models | |
return ".".join(module + [m._meta.object_name]) | |
class Command(LabelCommand): | |
help = 'Output the contents of the database as a fixture of the JSON format.' | |
args = 'modelName[pk] or modelName[id1:id2] repeated one or more times' | |
option_list = BaseCommand.option_list | |
def handle_models(self, models, **options): | |
objects = [] | |
for model, model_slice in models: | |
if isinstance(model_slice, basestring): | |
objects.extend(model._default_manager.filter(pk__exact=model_slice)) | |
elif not model_slice or type(model_slice) is list: | |
items = model._default_manager.all() | |
if model_slice and model_slice[0]: | |
items = items.filter(pk__gte=model_slice[0]) | |
if model_slice and model_slice[1]: | |
items = items.filter(pk__lt=model_slice[1]) | |
items = items.order_by(model._meta.pk.attname) | |
objects.extend(items) | |
else: | |
raise CommandError("Wrong model_slice: %s" % model_slice) | |
all_objects = objects | |
collected = set([(x.__class__, x.pk) for x in all_objects]) | |
while objects: | |
related = [] | |
for x in objects: | |
if DEBUG: | |
print "Adding %s[%s]" % (model_name(x), x.pk) | |
for f in x.__class__._meta.fields + x.__class__._meta.many_to_many: | |
if isinstance(f, ForeignKey): | |
new = getattr(x, f.name) # instantiate object | |
if new and not (new.__class__, new.pk) in collected: | |
collected.add((new.__class__, new.pk)) | |
related.append(new) | |
if isinstance(f, ManyToManyField): | |
for new in getattr(x, f.name).all(): | |
if new and not (new.__class__, new.pk) in collected: | |
collected.add((new.__class__, new.pk)) | |
related.append(new) | |
related_m2m = [getattr(x, m2m.get_accessor_name()) for m2m in x.__class__._meta.get_all_related_many_to_many_objects()] | |
for rm in related_m2m: | |
for new in rm.all(): | |
if new and not(new.__class__, new.pk) in collected: | |
collected.add((new.__class__, new.pk)) | |
related.append(new) | |
objects = related | |
all_objects.extend(objects) | |
all_objects.reverse() | |
try: | |
return serializers.serialize('json', all_objects, indent=4) | |
except Exception, e: | |
raise CommandError("Unable to serialize database: %s" % e) | |
def get_models(self): | |
return [(m, model_name(m)) for m in get_models()] | |
def handle_label(self, labels, **options): | |
parsed = [] | |
for label in labels: | |
search, pks = label, '' | |
if '[' in label: | |
search, pks = label.split('[', 1) | |
label_slice = '' | |
if ':' in pks: | |
label_slice = pks.rstrip(']').split(':', 1) | |
elif pks: | |
label_slice = pks.rstrip(']') | |
models = [model for model, name in self.get_models() if name.endswith('.'+search) or name == search] | |
if not models: | |
raise CommandError("Wrong model: %s" % search) | |
if len(models) > 1: | |
raise CommandError("Ambiguous model name: %s" % search) | |
parsed.append((models[0], label_slice)) | |
return self.handle_models(parsed, **options) | |
def list_models(self): | |
names = [name for _model, name in self.get_models()] | |
raise CommandError('Neither model name nor slice given. Installed model names: \n%s' % ",\n".join(names)) | |
def handle(self, *labels, **options): | |
if not labels: | |
self.list_models() | |
output = [] | |
label_output = self.handle_label(labels, **options) | |
if label_output: | |
output.append(label_output) | |
return '\n'.join(output) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment