When you need to remove any piece of code that's been referenced in migrations, generally there's a multi-step process.
For sake of a simple example, let's assume you have Model A in App A, and Model B in App B. And at some point you added a foreign key from Model A to Model B, but now you want to completely remove Model B. The process is:
1. Remove the foreign key from Model A and generate a migration for that. Apply the migration. DO NOT DELETE MODEL B'S CODE YET.
2. Generate a migration with a RemoveModel operation for Model B. DO NOT DELETE MODEL B'S CODE YET.
3. Squash migrations for App A, starting at the point the foreign key to Model B was added, and ending at the point the foreign key to Model B was removed. DO NOT DELETE MODEL B'S CODE YET.
4. Now that only a single migration file references Model B, either remove the AddField/RemoveField operations from it entirely, or replace them with migrations.RunPython.noop operations. DO NOT DELETE MODEL B'S CODE YET.
5. Verify that you can bring up a fresh database correctly with the migrations you now have. DO NOT DELETE MODEL B'S CODE YET.
6. Finally: delete Model B's code from your codebase.
if you referred to this model from multiple apps/models, you will need to do steps 1-5 once for each app/model that had a reference.