physicalattraction
physicalattraction

Reputation: 6858

Django fixtures with specific data

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?

Upvotes: 5

Views: 6140

Answers (2)

physicalattraction
physicalattraction

Reputation: 6858

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))

Upvotes: 4

iklinac
iklinac

Reputation: 15758

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 .

Upvotes: 1

Related Questions