Opened 6 months ago
Closed 6 months ago
#35463 closed Uncategorized (duplicate)
Squash migrations inheriting dependencies from unsquashed migrations.
Reported by: | Gordon Wrigley | Owned by: | nobody |
---|---|---|---|
Component: | Migrations | Version: | 4.2 |
Severity: | Normal | Keywords: | squash |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
We have a large system with several apps and a lot of interdependent migrations. Currently 17 apps and a total of 1,266 migrations.
Squashing this is very difficult. One of the things that makes it much more difficult is the change associated with https://code.djangoproject.com/ticket/25945 where by dependencies are copied between squashed and unsquashed migrations.
This means that while the unsquashed migrations still exist in the codebase the squash that replaces them is dependent on all of the things the individual migrations are dependent on.
With large squashes on different apps that refer to each other this frequently creates circular dependencies between squashes where they don't actually exist.
The net effect of this is I have squashes where I know the squashes don't depend on each other and the dependencies listed in the squashes are chosen to not lead to them depending on each other, however they end up depending on each other because they inherit the dependencies of the migrations they replace.
We are addressing this by reverting part of that change so it no longer copy dependencies onto the squash, trusting that the squash knows what it's dependencies should be.
def patch_squash_migration_dependencies(): from django.db.migrations.graph import MigrationGraph patchy.patch( MigrationGraph.remove_replaced_nodes, r"""\ @@ -28,7 +28,3 @@ child.add_parent(replacement_node) for parent in replaced_node.parents: parent.children.remove(replaced_node) - # Again, to avoid self-referencing. - if parent.key not in replaced: - replacement_node.add_parent(parent) - parent.add_child(replacement_node) """, )
As an aside, generally cross app dependencies are from foreign keys. When you add a foreign key to another app you need to depend on the migrations in that app. Django depends on the most recent migration by default. But AFAIK it only really needs to depend on the last migration where the PK of the target table changed (usually when the table was added). It's probably a lot of work but I suspect that having the migration system figure that out would reduce a lot of circular dependency issues.
Duplicate of #23337