5

I have an app with 3 models that refer to each other in a parent-child way:

class A(Model):
    # ...

class B(Model):
    a = ForeignKey(A)
    # ...

class C(Model):
    b = ForeignKey(B)
    # ...

In my production database, I have hundreds objects of type A, with thousands of child objects below it. I now want to create a fixture for only a (specific) handful objects. If I run this command, my output will become huge:

python manage.py dumpdata ca_myapp -o /tmp/my_app_dump.json

However, when I restrict the output using this command:

python manage.py dumpdata ca_myapp.A -o /tmp/myapp_dump.json --pks pk1, pk2, pk3

Then only the A objects are deserialized, but not their children. How can I easily create a fixture file with a handful of objects and their children?

physicalattraction
  • 6,485
  • 10
  • 63
  • 122

2 Answers2

4

I have written now a Django command that first checks which pks I want to fetch, and which children they have, to fetch all related objects.

import logging
import os

from django.core.management import BaseCommand, call_command

logger = logging.getLogger(__name__)

A = {'pk1', 'pk2', 'pk3'}

class Command(BaseCommand):
    def __init__(self, stdout=None, stderr=None, no_color=False):
        super().__init__(stdout, stderr, no_color)
        self.settings = None
        self.a = set()

    @property
    def tmp_dir(self):
        return '/tmp'

    def handle(self, *args, **options):
        self.settings = options.get('settings')

        # TODO: Make list of A an optional argument
        a_pks = A
        self.dump_objects('ca_myapp.A', pks=a_pks)

        b_pks = B.objects.filter(a_id__in=a_pks).values_list('pk', flat=True)
        self.dump_objects('ca_myapp.B', pks=b_pks)

        c_pks = C.objects.filter(b_id__in=b_pks).values_list('pk', flat=True)
        self.dump_objects('ca_myapp.C', pks=c_pks)

    def dump_objects(self, model_name: str, pks: set):
        if pks:
            call_command('dumpdata', model_name,
                         '--pks', ','.join(pks),
                         '--indent', '2',
                         '-o', os.path.join(self.tmp_dir, '{}.json'.format(model_name)),
                         '--settings', self.settings)
        else:
            logger.warning('No objects for model {} found'.format(model_name))
physicalattraction
  • 6,485
  • 10
  • 63
  • 122
1

From Django documentation regarding dumpdata

dumpdata

django-admin dumpdata [app_label[.ModelName] [app_label[.ModelName]...]]

So in your case

python manage.py dumpdata ca_myapp.A ca_myapp.B ca_myapp.C

Other way around would be to use exclude

--exclude EXCLUDE, -e EXCLUDE

Prevents specific applications or models (specified in the form of app_label.ModelName) from being dumped. If you specify a model name, the output will be restricted to that model, rather than the entire application. You can also mix application names and model names.

If you want to exclude multiple applications, pass --exclude more than once


If I haven't properly understood question and you are asking if it is possible to select just few of pks and follow their relationship that is currently not possible with dumpdata, but you can easily prepare your db to hold just data that is necessary .

Community
  • 1
  • 1
iklinac
  • 14,944
  • 4
  • 28
  • 30
  • Thanks iklinac. I had seen those options, but they do not do what I need. I indeed need to select just a few pks and follow their relationships. – physicalattraction Feb 20 '18 at 14:00
  • @physicalattraction please read second part of my response, easiest way would be to prepare your DB prior to dumpdata, Also there is a utility https://github.com/davedash/django-fixture-magic which seems to extend dumpdata to your requirements, not sure if it is still maintained. – iklinac Feb 20 '18 at 16:07
  • It's unfortunately impossible to prepare my database before dump, since it's a production database. I have currently written a script that fetches all uuids that I need, and calls this command with the proper `--pks` flag, where this list can grow into thousands. – physicalattraction Feb 21 '18 at 10:08