Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix nested dumps #2

Merged
merged 9 commits into from
Aug 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 43 additions & 29 deletions fixture_magic/management/commands/custom_dump.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
from __future__ import print_function

import sys

try:
import json
except ImportError:
Expand All @@ -14,16 +12,35 @@
from django.apps import apps as loading
from django.core.serializers import serialize
from django.conf import settings
from django.template import Variable, VariableDoesNotExist

from fixture_magic.utils import (
add_to_serialize_list,
reorder_json,
serialize_me,
serialize_fully
)


def process_dep(parent, dep, serialize_me, seen):
parts = dep.split('.')
current = parts.pop(0)
leftover = '.'.join(parts)

try:
thing = getattr(parent, current)
except AttributeError:
pass # related object not found
else:
if hasattr(thing, 'all'):
children = thing.all()
else:
children = [thing]
add_to_serialize_list(children, serialize_me, seen)

if leftover:
for child in children:
process_dep(child, leftover, serialize_me, seen)


class Command(BaseCommand):
help = 'Dump multiple pre-defined sets of objects into a JSON fixture.'

Expand All @@ -34,46 +51,43 @@ def add_arguments(self, parser):
help='Use natural keys if they are available.')

def handle(self, *args, **options):
serialize_me = []
seen = set()
# Get the primary object
dump_name = options['dump_name']
pks = options['pk']
dump_settings = settings.CUSTOM_DUMPS[dump_name]
app_label, model_name, *manager_method = dump_settings['primary'].split('.')
include_primary = dump_settings.get("include_primary", False)

default_manager = loading.get_model(app_label, model_name).objects
if manager_method:
dump_me = getattr(default_manager, manager_method[0])()
queryset = getattr(default_manager, manager_method[0])()
else:
dump_me = default_manager
queryset = default_manager.all()
if pks:
objs = dump_me.filter(pk__in=pks)
else:
objs = dump_me
for obj in objs.all():
queryset = queryset.filter(pk__in=pks)

deps = dump_settings.get('dependents', [])
for obj in queryset:
# get the dependent objects and add to serialize list
for dep in dump_settings['dependents']:
try:
thing = Variable("thing.%s" % dep).resolve({'thing': obj})
if hasattr(thing, 'all'): # Related managers can't be iterated over
thing = thing.all()
add_to_serialize_list([thing])
except VariableDoesNotExist:
sys.stderr.write('%s not found' % dep)

if include_primary or not dump_settings['dependents']:
add_to_serialize_list([obj])

serialize_fully()
data = serialize('json', [o for o in serialize_me if o is not None],
indent=4,
use_natural_foreign_keys=options.get('natural', False),
use_natural_primary_keys=options.get('natural', False),
)
for dep in deps:
process_dep(obj, dep, serialize_me, seen)
if include_primary or not deps:
add_to_serialize_list([obj], serialize_me, seen)

serialize_fully(serialize_me, seen)
data = serialize(
'json', [o for o in serialize_me if o is not None],
indent=4,
use_natural_foreign_keys=options.get('natural', False),
use_natural_primary_keys=options.get('natural', False),
)

data = reorder_json(
json.loads(data),
dump_settings.get('order', []),
ordering_cond=dump_settings.get('order_cond', {})
)

print(json.dumps(data, indent=4))
self.stdout.write(json.dumps(data, indent=4))
18 changes: 7 additions & 11 deletions fixture_magic/management/commands/dump_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
from django.apps import apps as loading
import json

from fixture_magic.utils import (add_to_serialize_list, serialize_me, seen,
serialize_fully)
from fixture_magic.utils import (add_to_serialize_list, serialize_fully)


class Command(BaseCommand):
Expand Down Expand Up @@ -65,6 +64,8 @@ def add_arguments(self, parser):
)

def handle(self, *args, **options):
serialize_me = []
seen = set()
error_text = ('%s\nTry calling dump_object with --help argument or ' +
'use the following arguments:\n %s' % self.args)
try:
Expand Down Expand Up @@ -117,18 +118,18 @@ def handle(self, *args, **options):
for rel in related_fields:
try:
if hasattr(getattr(obj, rel), 'all'):
add_to_serialize_list(getattr(obj, rel).all())
add_to_serialize_list(getattr(obj, rel).all(), serialize_me, seen)
else:
add_to_serialize_list([getattr(obj, rel)])
add_to_serialize_list([getattr(obj, rel)], serialize_me, seen)
except FieldError:
pass
except ObjectDoesNotExist:
pass

add_to_serialize_list(objs)
add_to_serialize_list(objs, serialize_me, seen)

if options.get('follow_fk', True):
serialize_fully()
serialize_fully(serialize_me, seen)
else:
# reverse list to match output of serializez_fully
serialize_me.reverse()
Expand All @@ -143,8 +144,3 @@ def handle(self, *args, **options):
indent=4,
use_natural_foreign_keys=natural_foreign,
use_natural_primary_keys=natural_primary))

# Clear the list. Useful for when calling multiple
# dump_object commands with a single execution of django
del serialize_me[:]
seen.clear()
14 changes: 7 additions & 7 deletions fixture_magic/utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
from django.db import models

serialize_me = []
seen = {}


def reorder_json(data, models, ordering_cond=None):
"""Reorders JSON (actually a list of model dicts).
Expand Down Expand Up @@ -45,21 +42,24 @@ def get_fields(obj):
return []


def serialize_fully():
def serialize_fully(serialize_me, seen):
index = 0

while index < len(serialize_me):
for field in get_fields(serialize_me[index]):
if isinstance(field, models.ForeignKey):
add_to_serialize_list(
[serialize_me[index].__getattribute__(field.name)])
[serialize_me[index].__getattribute__(field.name)],
serialize_me,
seen
)

index += 1

serialize_me.reverse()


def add_to_serialize_list(objs):
def add_to_serialize_list(objs, serialize_me, seen):
for obj in objs:
if obj is None:
continue
Expand All @@ -76,4 +76,4 @@ def add_to_serialize_list(objs):

if key not in seen:
serialize_me.append(obj)
seen[key] = 1
seen.add(key)