Package: django-syzygy
Django application providing database migration tooling to automate their deployment.Inspired by a2015 post from Ludwig Hähneand experience dealing with migration atZapier.Currently only supports PostgreSQL and SQLite as they are the only two FOSS
core backends that support transactional DDL and this tool is built around
that expectation.Installationpipinstalldjango-syzygyUsageAdd'syzygy'to yourINSTALLED_APPS# settings.pyINSTALLED_APPS=[...'syzygy',...]Setup you deployment pipeline to runmigrate--pre-deploybefore rolling
out your code changes andmigrateafterwards to apply the postponed
migrations.ConceptSyzygy introduces a notion ofprerequisiteandpostponedmigrations with
regards to deployment.A migration is assumed to be aprerequisiteto deployment unless it contains
a destructive operation or the migration has itsstageclass attribute set
toStage.POST_DEPLOY. When this attribute is defined it will bypassoperationsbased heuristics.e.g. this migration would be considered aprerequisiteclassMigration(migrations.Migration):operations=[AddField('model','field',models.IntegerField(null=True))]while the following migrations would bepostponedclassMigration(migrations.Migration):operations=[RemoveField('model','field'),]fromsyzygyimportStageclassMigration(migrations.Migration):stage=Stage.POST_DEPLOYoperations=[RunSQL(...),]In order to prevent the creation of migrations mixing operations of differentstagesthis package registers system checks. These checks will generate an error
for every migration with an ambiguousstage.e.g. this migration would result in a check errorclassMigration(migrations.Migration):operations=[AddField('model','other_field',models.IntegerField(null=True)),RemoveField('model','field'),]Migration revert are also supported and result in inverting the nature of
migrations. A migration that is normally considered aprerequisitewould then
bepostponedwhen reverted.With this new notion of migration stage it’s possible for themigratecommand
to target only migrations meant to be run before a deployment using the–pre-deployflag or error out in the case on an ambiguous plan.Third-party migrationsAs long as the adoption of migration stages concept  not generalized your
project might depend on third-party apps containing migrations with an
ambiguous sequence of operations.Since an explicitstagecannot be explicitly assigned by editing these
migrations a fallback or an override stage can be specified through the
respectiveMIGRATION_STAGES_FALLBACKandMIGRATION_STAGES_OVERRIDEsettings.By default third-party app migrations with an ambiguous sequence of operations
will fallback toStage.PRE_DEPLOYbut this behavior can be changed by
settingMIGRATION_THIRD_PARTY_STAGES_FALLBACKtoStage.POST_DEPLOYor
disabled by setting it toNone.NoteThe third-party app detection logic relies on thesitePython moduleand is known to not properly detect all kind of third-party Django
applications. You should rely onMIGRATION_STAGES_FALLBACKandMIGRATION_STAGES_OVERRIDEto configure stages if it doesn’t work for your
setup.Migration quorumWhen deploying migrations to multiple clusters sharing the same database it’s
important that:Migrations are applied only oncePre-deployment migrations are applied before deployment in any clusters is
takes placePost-deployment migrations are only applied once all clusters are done
deployingThe built-inmigratecommand doesn’t offer any guarantees with regards to
serializability of invocations, in other words naively callingmigratefrom
multiple clusters before or after a deployment could cause some migrations to
be attempted to be applied twice.To circumvent this limitation Syzygy introduces a--quorum<N:int>flag to themigratecommand that allow clusters coordination to take place.When specified themigrate--quorum<N:int>command will wait for at leastNnumber invocations ofmigratefor the planned migrations before proceeding
with applying them once and blocking on all callers until the operation completes.In order to use the--quorumfeature you must configure theMIGRATION_QUORUM_BACKENDsetting to point to a quorum backend such as cache based one provided by SygyzyMIGRATION_QUORUM_BACKEND='syzygy.quorum.backends.cache.CacheQuorum'orCACHES={...,'quorum':{...},}MIGRATION_QUORUM_BACKEND={'backend':'syzygy.quorum.backends.cache.CacheQuorum','alias':'quorum',}NoteIn order forCacheQuorumto work properly in a distributed environment it
must be pointed at a backend that supports atomicincroperations such as
Memcached or Redis.DevelopmentMake your changes, and then run tests via tox:tox