フィールドをForeignKeyからManyToManyFieldに変更したいDjangoアプリケーションがあります。古いデータを保持したいのですが、これを行うための最も簡単で最良のプロセスは何ですか?重要なのは、データベースのバックエンドとしてsqlite3を使用していることです。
問題の要約が明確でない場合は、ここに例を示します。 2つのモデルがあるとします。
class Author(models.Model):
author = models.CharField(max_length=100)
class Book(models.Model):
author = models.ForeignKey(Author)
title = models.CharField(max_length=100)
データベースに大量のデータがあるとします。ここで、Bookモデルを次のように変更します。
class Book(models.Model):
author = models.ManyToManyField(Author)
title = models.CharField(max_length=100)
以前のデータをすべて「失う」ことはしたくありません。
これを達成するための最良/最も簡単な方法は何ですか?
ケン
この質問は古く、当時のデータ移行の最良の選択肢は南を使用することでした。現在、Djangoには独自のmigrate
コマンドがあり、プロセスは少し異なります。
これらのモデルをbooks
というアプリに追加しました。そうでない場合は、それに応じて調整してください。
まず、フィールドをBook
に追加し、_related_name
_を少なくとも1つ、または両方に追加します(または衝突します)。
_class Book(models.Model):
author = models.ForeignKey(Author, related_name='book')
authors = models.ManyToManyField(Author, related_name='books')
title = models.CharField(max_length=100)
_
移行を生成します。
_$ ./manage.py makemigrations
Migrations for 'books':
0002_auto_20151222_1457.py:
- Add field authors to book
- Alter field author on book
_
次に、データ自体の移行を保持するために空の移行を作成します。
_./manage.py makemigrations books --empty
Migrations for 'books':
0003_auto_20151222_1459.py:
_
そして、それに次のコンテンツを追加します。これがどのように機能するかを正確に理解するには、 データ移行 のドキュメントを確認してください。移行の依存関係を上書きしないように注意してください。
_# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from Django.db import models, migrations
def make_many_authors(apps, schema_editor):
"""
Adds the Author object in Book.author to the
many-to-many relationship in Book.authors
"""
Book = apps.get_model('books', 'Book')
for book in Book.objects.all():
book.authors.add(book.author)
class Migration(migrations.Migration):
dependencies = [
('books', '0002_auto_20151222_1457'),
]
operations = [
migrations.RunPython(make_many_authors),
]
_
次に、モデルからauthor
フィールドを削除します。次のようになります。
_class Book(models.Model):
authors = models.ManyToManyField(Author, related_name='books')
title = models.CharField(max_length=100)
_
そのための新しい移行を作成し、それらすべてを実行します。
_$ ./manage.py makemigrations
Migrations for 'books':
0004_remove_book_author.py:
- Remove field author from book
$ ./manage.py migrate
Operations to perform:
Synchronize unmigrated apps: messages, staticfiles
Apply all migrations: admin, auth, sessions, books, contenttypes
Synchronizing apps without migrations:
Creating tables...
Running deferred SQL...
Installing custom SQL...
Running migrations:
Rendering model states... DONE
Applying books.0002_auto_20151222_1457... OK
Applying books.0003_auto_20151222_1459... OK
Applying books.0004_remove_book_author... OK
_
以上です。以前は_book.author
_で利用可能だった作成者は、book.authors.all()
から取得するクエリセットに含まれているはずです。
おそらく、あなたがすべき最善かつ最も簡単なことは次のとおりです。
別の名前で多対多フィールドを作成すると言う
authors = models.ManyToManyField(Author)
外部キー値をM2M値に変換する小さな関数を記述します。
def convert():
books = Book.objects.all()
for book in books:
if book.author:
li = [book.author.id]
book.authors.append(li)
book.save()
実行したら、作成者フィールドをテーブルから削除して、移行を再度実行できます。