ドキュメントやオンラインで特定の問題への参照を見つけることができません。
私は既存の多対多の関係を持っています。
_class Books(models.Model):
name = models.CharField(max_length=100)
class Authors(models.Model):
name = models.CharField(max_length=100)
books = models.ManyToManyField(Books)
_
これには移行とデータがあります。ここで、多対多の関係を保持するテーブルに1つのフィールドを追加するために、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')
が表示されます。影響を受けるものが他にもあるため、エラーが発生する可能性があります。
私は何が欠けていますか?これを処理する他のアプローチはありますか?
データ移行を行わずにオプションを使用する方法はないようです。そのため、データ移行アプローチに頼らざるを得なかったので、@ 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
テーブルにコピーします。
この後、published_books
という名前の新しいフィールドがあるため、books
モデルのAuthors
フィールドを削除できます。
データを移行せずに「スルー」を追加する方法があります。 この@MatthewWilkesの答え に基づいてなんとかできました。
したがって、それをデータモデルに変換するには:
Authorship
フィールドとbook
フィールドのみを使用してauthor
モデルを作成します。すでに持っている自動生成されたM2Mテーブルと同じ名前を使用するようにテーブル名を指定します。 'through'パラメーターを追加します。
_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テーブルに追加できます。
編集:どうやら、DBの列名は、自動M2Mテーブルとモデル定義テーブルでわずかに異なる方法で生成されます。 (私はDjango 1.9.3を使用しています。)
説明した手順の後、2ワード名(two_words=models.ForeignKey(...)
)のフィールドの列名を_twowords_id
_から_two_words_id
_に手動で変更する必要もありました。
移行が煩雑になる場合があります。
Throughを使用して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
に変更し、名前の変更に関するmakemigrationsの質問への回答としてy
を使用して移行プロセスを繰り返します。