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