Blog /

Django

How to safely remove Django model and its relations

January 28, 2021

How to safely remove Django model and its relations

January 28, 2021
Django

Removing a Django model or its relationships as direct as just removing them from code could lead to irreversible errors.

Before removing them from code we need to make sure to delete all its objects and the relations of those objects with other models.

But wait, why on earth do we need to remove a model and its relations? At most we may just want to “rename” a model. And for that, Django already provides RenameModel operation. So whenever you rename a model and run makemigrations, Django is smart enough to ask if you renamed an existing model.

Rename model migration shell


This will create a migrations file as simple as:


Rename model migrations file

Which automatically transfers all your old model’s data to the new model along with its relations.

Now coming back to the question “Why do we need to remove a model and its relations?”.

Well I can’t think of a direct answer. But here is a use case where you kind of have to:

Suppose you have the following models in your core app:

Initial models


As you can see both the models have a field label which has a ForeignKey relations with two separate models in the utils app “PackageLabel” and “CTALabel”.

Initially you were not sure if both these models can be just one model, “Label”, as you might be thinking of storing some different data in both, or the idea was not finalised. But now you are!

So here is our first use case where we need to delete our old models and their relations:


Merging two models into one.

It is obvious that we can not use RenameModel here. So the only way to preserve the data of old models is to write a data migration to transfer both models data and their relations to the new one.

In case you delete the models without changing the references of the models it is related to, you’ll keep on getting errors when trying to migrate, not to mention you’ll also loose all the old models data. For example:

Remove old models directly from the utils app:

remove directly utils models


And then Remove relational field directly from core app models:

Remove fields directly core models


Run “python manage.py makemigrations”

And then run, “python manage.py migrate”, you’ll get the following error:

Shell error


Which basically means that your CTA object is related to a Label object which doesn’t exist. 

In order to correctly do this:

  • Add the new model and new fields relating to it
  • Migrate old model and its relations to new one
  • Delete old model and its relations

So our models.py in the utils app look like:

add new model utils


And the models.py in core app look like:

add new fields core models


Notice that along with adding the new label field I also changed the reverse accessor of the old field to ‘temp_’, to use the correct reverse accessor for the new model.

Now that we have added the new model and new relational fields we can do “makemigrations” and “migrate”.

Next task is to write data migrations to migrate old models data to the new one. To do that we first need to create an empty migrations file: “python manage makemigrations utils --empty”

And add the code to migrate in that:

Data migrations file


Note: we have also written a blog on understanding data migration, in case you’ve not written them before.

Now doing “python manage.py migrate” will migrate the old models data and its relations to the new one.

We can now go ahead and safely delete the old models and there relation fields:


Delete model and fields


Then do “makemigrations” and “migrate”!
That’s it. You have successfully removed a Django model and its relations without introducing any errors in your project.

Another use case where you may have to delete a Django model is when you have to move a model from one app to another.

This workflow of adding the new field which is replacing the old one, and only removing the old one after having been migrated the data can also be used, when you’ve to change a ForeignKey field to ManyToMany.

Thanks for reading!

Last updated on
January 28, 2021

Tagged under

Django