My issue with this is with squashing those hairier cases often require a lot of work.
Also makemigrations is handling the majority of stuff automatically these days, I’ve got to be doing something really weird to trip it up, like moving models between apps.
For context our main project is over 5 years old, it has 2 dozen apps and collectively they’ve had one and a half thousand migrations. There are a lot of cross app FK’s.
Fortunately our situation is simplified because we never use RunSQL and RunPython is only used for updating existing data never for creating data.
Also we’re still on 4.2.
For us massaging a squash typically took days of work, which also meant we were only doing it every year or so.
Also aside from circular dependency issues my experiences with the optimiser have been lack lustre and compared to bankruptcy optimising seems like a fundamentally complex approach. A thing that will always need more work and never be perfect.
Because of the above difficulties we have given up on the built in squash functionally.
Instead we’ve adopted a process that’s kinda a hybrid between bankruptcy and the multiple squash file approach @adamchainz suggested.
We call this “crushing” and it is working surprisingly well for us.
The guts of it is when we squash we overwrite the initial migrations on each app with all the current table creation statements and create a squash on top of that which adds all the foreign keys.
This is “safe” because as long as there’s no really new apps you aren’t going to run one of those two and not the other.
If you are updating then the initial will already be marked as applied and some (if not all) the migrations in the squash will be applied so it can’t be used either.
If you are creating from fresh it will always use the initial and the squash.
So the migrations just need to get to the right state by the end of the squash it doesn’t matter what crimes you commit in between.
We have all this automated in a script, but it’s not usable as a general process, it has stuff specific to our code base and it does things that are quite dirty.
This is a “what’s working for us” post not a “here’s a patch” post.
If anyone is curious you can find the script here crush_migrations/crush_migrations.py at main · tolomea/crush_migrations · GitHub
I ran this this morning and it worked perfectly, took me maybe half an hour to “squash” a couple of hundred migrations. I’ve quite literally spent longer writing this message.