python manage.py makemigrations
only to find out a bunch of errors showed up.
Django does not automatically detect the models where moved and automatically write the proper migration, it doesn't seem smart enough to read our minds, so here is what I did.
1. First option:
The first workaround I found was to addclass Meta:db_table = 'old tablename'app_label = 'old app'
To the models I moved. Although it works fine, it's an awful hack to just have the code someplace while the models still belong to the old app.
2. Stack Overflow blessing
A more profound search led me to this reply in one post
Which describes in detail the process needed to move a model to another app. It makes use of state_operations and database_operations separately in a migration inside the old application, as showed below
class Migration(migrations.Migration):
dependencies = []
database_operations = [
migrations.AlterModelTable('TheModel', 'newapp_themodel')
]
state_operations = [
migrations.DeleteModel('TheModel')
]
operations = [
migrations.SeparateDatabaseAndState(
database_operations=database_operations,
state_operations=state_operations) ]
I am not including the full code here, as you can take a look in Stack Overflow directly. It also involves a second migration in the destination application only to create the model with a state_operation and the use of SeparateDatabaseAndState again (the table is already in the database, so we trying to create it again would cause an error)
The process is simple and it does not require any data migration, which makes it delightful (thanks to ozan)
In my case I am using Postgresql, so I went and took a look into the database to see what was going on
As the picture shows I had the table ui_environments and the sequence table ui_environments_id_seq
The detail for those tables displays how ui_environmens reference the sequence, as well as sequence numbers at the moment prior the migration
Running the above migration schema (both migrations mentioned) to rename ui_environments to spatial_geom (as it's now part of the 'spatial' application, and I chose to take the opportunity to also rename the model class to Geom as it made more sense at this point), led to the following tables
We can see spatial_geom is there, ui_environments was deleted, but ui_environments_id_seq remained the same. Inspecting both tables, the table was correctly renamed, and it still points to the same sequence. This all looks fine, but I wanted to clean up the database and rename also the sequence to avoid confusion.
Of course, I tried to do this with Django migrations, to learn a bit more about it. So here is how I did it.
Migrations' RunSql to run custom SQL to alter your database
Digging into the documentation, there's no command to just alter a table name which does not belong to a model, so RunSql seemed the best fit. As showed in the documentation, we need to pass in the SQL we want to run, and optionally, the SQL to revert the operation and the operation to reflect it in the migrations' state, if needed.
As renaming the sequence did not require any migration state change, I just passed in the first two parameters.
I ran
python manage.py makemigrations spatial --empty
to create an empty migration in my application, and then modified it with the custom statement.
# -*- coding: utf-8 -*-from __future__ import unicode_literalsfrom django.db import models, migrationsclass Migration(migrations.Migration):dependencies = [('spatial', '0005_environmentgeom'),]operations = [migrations.RunSQL(sql="ALTER SEQUENCE ui_environments_id_seq RENAME TO spatial_geom_id_seq",reverse_sql="ALTER SEQUENCE spatial_geom_id_seq RENAME TO ui_environments_id_seq"),]
then run
python manage.py migrate spatial
and took a look inside the db
The sequence name had changed and it was correctly referenced by the spatial_geom table. Sequence numbers remained unaltered as required. The only strange thing I noticed was that sequence_name field in the sequence had the old value. Digging a bit into this I found this issue with Postgresql sequences, which states that the field is not used anywhere, so it does not really matter that the ALTER SEQUENCE statement does not change it. So we are happy to ignore.
Summary
Django Migrations perform an excellent job inside one application, but some changes across applications may require creating some custom migrations to do the job. In this post I looked into moving a model between applications, and cleaning up the database tables afterwards, for any change that Django alone might have not performed. Looking at final result, indexes also remained with the old name and a similar approach should be taken if we want to tidy up further.
No comments:
Post a Comment