如何在django中添加通过选项到现有的ManyToManyField中的迁移和数据

qnzebej0  于 2023-03-31  发布在  Go
关注(0)|答案(3)|浏览(114)

我在文档或网上找不到关于特定问题的参考资料。
我有一个现有的多对多关系。

class Books(models.Model):
    name = models.CharField(max_length=100)

class Authors(models.Model):
    name = models.CharField(max_length=100)
    books = models.ManyToManyField(Books)

这有迁移和数据。现在我需要使用通过选项,以便在表中添加一个额外的字段持有多对多的关系。

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模型创建了新的迁移。我试图通过在Authorship表中添加ordering列并在Authors表中更改books列来手动创建迁移文件,但我遇到了一些迁移问题。

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')我敢打赌还有其他的东西受到影响,从而出现错误。
我遗漏了什么?有没有其他方法来处理这个问题?

yk9xbfzb

yk9xbfzb1#

有一种方法可以在不进行数据迁移的情况下添加“through”,我设法基于this @MatthewWilkes' answer做到了。
因此,将其转换为您的数据模型:
1.创建仅包含bookauthor字段的Authorship模型。指定表名以使用与您已有的自动生成的M2M表相同的名称。指定unique_together属性以匹配自动生成的M2M表的功能(源)。添加'through'参数。

class Authorship(models.Model):
     book = models.ForeignKey(Books)
     author = models.ForeignKey(Authors)

     class Meta:
         db_table = 'app_name_authors_books'
         unique_together = ['book', 'author']

 class Authors(models.Model):
     name = models.CharField(max_length=100)
     books = models.ManyToManyField(Books, through=Authorship)

1.生成迁移,但不要运行它。
1.编辑生成的迁移并将迁移操作 Package 到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'),
         ),
         migrations.AlterUniqueTogether(
             name='authorship',
             unique_together={('book', 'author')},
         ),
     ])
 ]

1.现在可以运行迁移并将额外的ordering字段添加到M2M表中。

**编辑:**显然,自动M2M表和模型定义的表在数据库中生成的列名略有不同(我使用的是Django 1.9.3)。

在完成所描述的过程之后,我还必须手动将具有两个单词名称(two_words=models.ForeignKey(...))的字段的列名从twowords_id更改为two_words_id

3zwtqj6y

3zwtqj6y2#

看起来没有办法使用通过选项而不必进行数据迁移。所以不得不求助于数据迁移方法,我从@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(
          to=Books,
          through=Authorship,
          related_name='authors_lst' # different related name is needed.
      )

重要提示:你必须使用一个不同的related_name到现有的ManyToManyField。如果你不这样做,Django可能会丢失原始字段中的数据。

  • 添加数据迁移,将所有数据从旧表复制到新的Authorship表。

在此之后,可以删除Authors模型上的books字段,因为我们有一个名为published_books的新字段。

b1zrtrql

b1zrtrql3#

迁移有时会很麻烦。
如果你想通过through修改m2m字段,我建议你把修改后的字段Authors.books重命名为Authors.book。当makemigrations询问时,如果你把名字从books改为book?[yN],选择“N”作为No。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关于重命名的问题。

相关问题