You are the one generating migration files, Django is not forcing them.
The problem is not in Django, the problem is that this cannot be solved with a single deploy, there is not way for the old code to know whats coming in the future, which means you need to make a deploy just for this, and after that make a second deploy with the real changes. But if you are gonna make two deploys then you don't need Django to help you, you can solve this alone. Here is an example: Lets say we want to migrate from a full_name column to first_name and last_name columns. Here is what you can do:
1) Add first_name and last_name into the model and create a migration (which adds two columns and eventually populates them with data from full_name).
2) Change the code to make use of the new fields, remove full_name from the code, BUT do not make migration yet!
3) Deploy.
Now, during the deployment your old code will still use full_name which is still in the database, and when the new code gets live it will start using the new columns.
Note: during the deployment you need to run migrations first, and reload the server after that, so your new code won't fail because new columns don't exist yet.
Note2: since you are running the migrations first, and restarting the server later, in theory its possible for a new data to appear into the database from the old code! Thus you wont have it migrated yet. e.g. A new user registered right after the migration ended and before the new code gets live, his name will be stored into the old full_name column! But you can fix this on the next step!
4) Now after the new code is live, and no one is using full_name anymore create a new migrations which will remove it from the database. In this migration you can double check that all data from full_name is properly migrated to the new columns.
5) Deploy again. (no code changes, just removing the old unused column from the database).