Seems like this should be "easy" or at least documented somewhere, I just cant find it.
Lets say I have a model:
class A(models.Model):
users = models.ManyToMany('auth.User', blank=True)
Now I want to migrate to have a through
table to add fields to the ManyToMany relation...
class AUsers(models.Model):
user = models.ForeignKey('auth.User')
a = models.ForeignKey('A')
new_field = models.BooleanField()
class A(models.Model):
users = models.ManyToMany('auth.User', blank=True, through='AUsers')
Then I do:
% ./manage.py schemamigration app --auto
Not totally surprising, it tells me it is going to drop the original auto-created through table and create a new one for AUsers
. What's the best practice at this point? Is there a decent way to migrate to the new through
table? Do I use db_table
in Meta? Do I just not use the through=...
right away... then do a schemamigration --auto
, then a datamigration
to copy the current table (somehow, not sure...) and then add the through
relation and let it kill the table?
What's the trick here? Is this really that hard?
You should be able to do this pretty easily.
First of all, make sure that the manual through table that you are creating has the same table name in the database as the one Django originally created automatically.
So, first, let's consider a manual through model before your change:
That should be functionally (almost) identical to the
ManyToManyField
you used to have. Actually, you could make an empty migration and apply it, and then use --auto for your changes (but don't).Now, add your field like you did in your sample code above, and then run
./manage.py schemamigration appname manual_through_table --empty
. That will give you an empty migration named####_manual_through_table.py
.In the migration itself, there will be a
forwards
andbackwards
method. Each one needs to be one line each:That should get you what you are after.
As mentioned in a comment, the first step may be simplified using
db.rename_table
as described here, which gives this through model:Then, create a migration with --auto (this way you'll have the names of the DB tables visible), and replace the content with:
I just applied it in my project without issues.
If anyone comes across this question when trying to do the same thing with the moderns migration framework, here are the steps:
migrations. SeparateDatabaseAndState
migration, where the auto-generated steps are in thestate_operations
field and the database operations are empty.