Package: django-dynamic-initial-data
Django Initial DataDjango Dynamic Initial Data is adjango>=1.6andpostgresqlonly app that helps solve the problem of initializing data for apps with
dependencies and other conditional data. Rather than having static fixtures for each app, the initial data
can be created and updated dynamically. Furthermore, Django Dynamic Initial Data also handles when objects are
deleted from initial data, a feature that Django's initial data fixture system lacks.Table of Contents[Installation] (#installation)[A Brief Overview] (#a-brief-overview)[Example] (#example)Handling DeletionsInstallationTo install Django Dynamic Initial Data:pipinstalldjango-dynamic-initial-dataAdd Django Dynamic Initial Data to yourINSTALLED_APPSto get started:settings.pyINSTALLED_APPS=('dynamic_initial_data',)A Brief OverviewA management commandupdate_initial_datais provided which will try to update allINSTALLED_APPS. This
command is intended to be called as part of the deployment process of your app. Any missing dependencies
will raise anInitialDataMissingAppexception and any circular dependencies will raise anInitialDataCircularDependencyexception.Any app needing to define initial data needs a file calledinitial_data.pyinside of afixturesdirectory. This will look like{app_name}/fixtures/initial_data.py. Don't forget to include
the__init__.pyfile in the fixtures directory.initial_data.pymust define a classInitialDatathat inherits fromBaseInitialData.When apps are being initialized, eachInitialDataclass is instantiated andupdate_initial_datais called.
Ifupdate_initial_datais not implemented, then aNotImplementedErrorwill be raised.Any dependencies should be included in a list calleddependencies. Each dependency is a string
of the app name as defined inINSTALLED_APPS.Example:fromdynamic_initial_data.baseimportBaseInitialDataclassInitialData(BaseInitialData):dependencies=['my_first_app','my.second.app']defupdate_initial_data(self):model_obj,created=TestModel.objects.upsert(int_field=5,defaults={'float_field':2.0})TestModel.objects.bulk_upsert([TestModel(float_field=1.0,char_field='1',int_field=1),TestModel(float_field=2.0,char_field='2',int_field=2),TestModel(float_field=3.0,char_field='3',int_field=3),],['int_field'],['char_field'])In this example, theupdate_initial_datamethod will be called formy_first_app(following any dependencies first),
and then formy.second.app, before finally callingupdate_initial_dataon this class. Again, this can be executed by callingpython manage.py update_initial_dataSimilarly, to only initialize a single app, usepython manage.py update_initial_data --app 'app_path'Documentation on usingupsertandbulk_upsertcan be found below:https://github.com/ambitioninc/django-manager-utils#upserthttps://github.com/ambitioninc/django-manager-utils#bulk_upsertHandling DeletionsOne difficulty when specifying initial data in Django apps is the inability to deploy initial data to your project and then subsequently remove any initial data fixtures. If one removes an object in an initial_data.json file, Django does not handle its deletion next time it is deployed, which can cause headaches with lingering objects.Django Dynamic Initial Data fixes this problem by allowing the user to either:Return all managed initial data objects as an array from the update_initial_data function.Explicitly register objects for deletion with the register_for_deletion(*model_objs) method.Note that it is up to the user to be responsible for always registering every object every time, regardless if the object was updated or created by the initial data process. Doing this allows Django Dynamic Initial Data to remove any objects that were previosly managed. For example, assume you have an InitialData class that manages two users with the user names "hello" and "world".fromdynamic_initial_data.baseimportBaseInitialDataclassInitialData(BaseInitialData):defupdate_initial_data(self):hello=Account.objects.get_or_create(name='hello')world=Account.objects.get_or_create(name='world')# register the accounts for deletionself.register_for_deletion(hello,world)After this code is created, the initial data process now owns the "hello" and "world" account objects. If these objects are not registered for deletion in subsequent versions of the code, they will be deleted when the initial data process executes. For example, assume the first piece of code executed and then the user executed this piece of code:fromdynamic_initial_data.baseimportBaseInitialDataclassInitialData(BaseInitialData):defupdate_initial_data(self):world=Account.objects.get_or_create(name='world')# register the accounts for deletionself.register_for_deletion(world)When this piece of code executes, the previous "hello" account would then be deleted since the initial data process no longer owns it. And don't worry, if it was already deleted by another process, the deletion will not throw an error.