Wellfire Interactive // Expertise for established Django SaaS applications

The Old Pony: Moving the Monolith (part 2)

Faced with your Django monolith, you’ve assessed how it should be broken up, moved the low hanging fruit out and into the new apps, and now you’re ready to move the models.

With a good refactoring tool by your side, how hard could it be?

Image

« Cue dramatic music »

#
Why moving models isn’t _quite _that simple Unless your models are unmanaged by Django0, any and all changes to your models are tracked in your migrations module.

That means when you add, remove, or modify an existing model, whether a single field or some greater combination thereof, this gets reflected in the migration state each time you run “makemigrations”.

Migrations are app specific. So when you remove a model, you’re removing it from the app, which means you might as well be moving it from the entire project.

And removing it from the database.
 

Keeping everything in one place

There are a couple of ways to handle this, but we’re going to walk through _one _strategy for handling this situation. It isn’t the best strategy for every project, but it is the most straightforward, and every other solution kind of falls out from it.

Our goal here is to keep our tables intact. All we want to do is move the model class, we don’t need to move around or drop database tables1.

So first step, add explicit table names to the models in the monolith, using the db_table Meta option2. Make sure to use the exact same names as your database already uses.

Then create a new migration. That’s right, we’re not making any changes in the database, but this is still a state change as far as migrations are concerned. You’ll build a new migration that includes renaming operations, but because the table name specified in your model’s Meta class is identical to the table names in the database, no change.
 

The model extraction

Now you’re ready to move the model classes out of the monolith and into your new apps. Use a refactoring tool or make judicious use of grep to ensure you _every _reference was updated.

With the model classes in your new app, go ahead and create new migration files. Verify these before you run them!

The migrations in your new app will create tables matching the current table, and the migrations in your monolith from which you removed the models will drop the tables.

If you do run these, you’ll end up with the exactly the same structure as you started with, but having dropped the tables in order to recreate them, you’ll lose all of your data.
 

Fake it till you make it 

The solution, however, is rather simple. Fake the migration.

Faking the migration, including for subsequent deployments, will allow you to keep your migration state up to date and prevent inadvertent data loss.

Following migration you’d be advised to squash the migrations in the monolith so that you don’t need to worry about faking this migration anywhere else in the future.

If you don’t run deployments manually or have more than one dev environment, the drawbacks of this method are probably clear already. This is a manual process and as such is prone to human error.

For these situations you can streamline the migration handling by _neutering _the operations (using customized migration operation classes) or delegating these migrations to another migration or management command run on deploy.
 

Renaming the tables

For those still wondering about table names, the key point is that by explicitly naming the tables in the model Meta classes we decouple any changes to the table names from the app/model names. This allows us to decouple the changes as well.

If you do decide to update the table names, say, to reflect the new app and/or model class names, then you’re free to do that. But you’ve moved this to its own step, thus reducing your risk exposure. Further, there may be other references to these table names not captured in your models, for example saved queries or stored procedures.

If your team does decide to rename the tables, this can be done with minimal changes to the application itself beyond a single Meta value now.

Irreversibly yours,
Ben

P.s. I started work on a book a while back, a guide to writing Django Standalone Apps. It’s been hard to wrap up so I thought maybe I’d leak it bit by bit over email instead of trying to finish it in one go. Is that something you’d be interested in? If you’d be interested in getting a drip-campaign version of the Django Standalone Apps book just click this trigger link and I’ll start keeping a tab of interest :)

Learn from more articles like this how to make the most out of your existing Django site.