I can't find reference to particular issue in docs or online.
I have an existing many to many relation.
class Books(models.Model): name = models.CharField(max_length=100) class Authors(models.Model): name = models.CharField(max_length=100) books = models.ManyToManyField(Books)
This has migrations and data. Now I need to use through option in order to add one extra field in table holding many to many relation.
class Authorship(models.Model): book = models.ForeignKey(Books) author = models.ForeignKey(Authors) ordering = models.PositiveIntegerField(default=1) class Authors(models.Model): name = models.CharField(max_length=100) books = models.ManyToManyField(Books, through=Authorship)
When I run migrations, django creates fresh migration for Authorship
model. I tried to create migration file manually by adding ordering
column in Authorship
table and altering books
column in Authors
table but I get some migration issues.
operations = [ migrations.AddField( model_name='authorship', name='ordering', field=models.PositiveIntegerField(default=1), ), migrations.AlterField( model_name='authors', name='books', field=models.ManyToManyField(to='app_name.Books', through='app_name.Authorship'), ), ]
When trying to migrate, it gives KeyError: ('app_name', u'authorship')
I bet there are other things that are affected and thus errors.
What things am I missing? Is there any other approach to work with this?
There is a way to add "through" without data migrations. I managed to do it based on this @MatthewWilkes' answer.
So, to translate it to your data model:
Create the Authorship
model only with book
and author
fields. Specify the table name to use the same name as the auto-generated M2M table you already have. Add the 'through' parameter.
class Authorship(models.Model): book = models.ForeignKey(Books) author = models.ForeignKey(Authors) class Meta: db_table = 'app_name_authors_books' class Authors(models.Model): name = models.CharField(max_length=100) books = models.ManyToManyField(Books, through=Authorship)
Generate a migration, but don't run it yet.
Edit the generated migration and wrap the migration operations into a migrations. SeparateDatabaseAndState
operation with all the operations inside state_operations
field (with database_operations
left empty). You will end up with something like this:
operations = [ migrations.SeparateDatabaseAndState(state_operations=[ migrations.CreateModel( name='Authorship', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('book', models.ForeignKey(to='app_name.Books')), ], options={ 'db_table': 'app_name_authors_books', }, ), migrations.AlterField( model_name='authors', name='books', field=models.ManyToManyField(through='app_name.Authorship', to='app_name.Books'), ), migrations.AddField( model_name='authorship', name='author', field=models.ForeignKey( to='app_name.Author'), ), ]) ]
You can now run the migration and add the extra ordering
field to your M2M table.
Edit: Apparently, column names in the DB are generated slightly differently for automatic M2M tables as for models-defined tables. (I am using Django 1.9.3.)
After the described procedure, I also had to manually change the column names of a field with a 2-word name (two_words=models.ForeignKey(...)
) from twowords_id
to two_words_id
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With