我无法在文档或在线中找到对特定问题的引用。
我有很多关系。
class Books(models.Model):
name = models.CharField(max_length=100)
class Authors(models.Model):
name = models.CharField(max_length=100)
books = models.ManyToManyField(Books)
这包含迁移和数据。现在我需要使用through选项,以便在表中添加一个额外的字段,包含多对多关系。
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)
当我运行迁移时,django会为Authorship
模型创建新的迁移。我尝试通过在ordering
表中添加Authorship
列并在books
表中更改Authors
列来手动创建迁移文件,但我遇到了一些迁移问题。
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'),
),
]
尝试迁移时,会给出KeyError: ('app_name', u'authorship')
我敢打赌其他因素会受到影响,从而导致错误。
我错过了什么?还有其他方法可以解决这个问题吗?
答案 0 :(得分:20)
有一种方法可以在没有数据迁移的情况下添加“直通”。 我设法基于this @MatthewWilkes' answer。
因此,要将其转换为您的数据模型:
仅使用Authorship
和book
字段创建author
模型。指定表名称以使用与您已有的自动生成的M2M表相同的名称。添加“通过”参数。
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)
生成迁移,但尚未运行。
编辑生成的迁移并将迁移操作包装到migrations. SeparateDatabaseAndState
操作中,其中state_operations
字段内的所有操作(database_operations
为空)。你最终会得到这样的东西:
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'),
),
])
]
您现在可以运行迁移并将额外的ordering
字段添加到您的M2M表中。
修改强> 显然,对于自动M2M表,DB中的列名称与模型定义的表格略有不同。 (我正在使用Django 1.9.3。)
在描述的程序之后,我还必须手动将字段的列名更改为two_words=models.ForeignKey(...)
到twowords_id
的双字名称(two_words_id
)。
答案 1 :(得分:10)
看起来没有必要通过选项而无需进行数据迁移。所以不得不求助于数据迁移方法,我从@pista329的答案中得到了一些想法,并使用以下步骤解决了这个问题。
创建Authorship
模型
class Authorship(models.Model):
book = models.ForeignKey(Books)
author = models.ForeignKey(Authors)
ordering = models.PositiveIntegerField(default=1)
保持原始的ManyToManyField关系,但使用上面定义的模型添加另一个字段作为模型:
class Authors(models.Model):
name = models.CharField(max_length=100)
books = models.ManyToManyField(Books)
published_books = models.ManyToManyField(Books, through=Authorship, related_name='authors_lst') # different related name is needed.
添加数据迁移,将所有数据从旧表复制到新Authorship
表。
在此之后,books
模型上的Authors
字段可以删除,因为我们有一个名为published_books
的新字段。
答案 2 :(得分:2)
迁移有时会很混乱。
如果您想通过直通改变m2m字段,我建议将更改后的字段Authors.books
重命名为Authors.book
。当makemigrations
询问时,您是否更改了书籍之间的名称? [yN]
,选择" N
"如果没有,Django将删除books
并创建book
字段而不是更改。
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)
book = models.ManyToManyField("Books", through="Authorship")
如果您仍想使用books
,请将book
更改为books
并使用y
重复迁移过程,以回答有关重命名的makemigrations问题。