2016-05-21 10 views
1

私の古いmySQLデータベースからDjango/sqliteに10,000レコード以上を移行しました。私の古いmysqlスキーマのSongテーブルでは、アーティストフィールドは1対多のフィールドではなく、mysql varcharフィールドでした。私の新しいDjangoモデルでは、アーティストフィールドをForeignKeyに変換し、temp_artistを使用して古いデータベースのアーティスト名を一時的に保存しました。DjangoモデルCharFieldから外部キーを導入

temp_artistフィールドに基づいて、各Songインスタンスのアーティストの外部キーを作成するにはどうすればよいですか?私は、マネージャのget_or_createメソッドを使用する必要があると仮定していますが、どこにどのようにコードを記述しますか?以下

私のモデル:

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

class Song (models.Model):  
    artist = models.ForeignKey(Artist, blank=True, null=True, on_delete=models.CASCADE, verbose_name="Artist") 
    temp_artist = models.CharField(null=True, blank=True, max_length=100) 
    title = models.CharField(max_length=100, verbose_name="Title") 
    duration = models.DurationField(null=True, blank=True, verbose_name="Duration") 

答えて

1

あなたは、現時点で使用可能な外部キーを持っていないので、あなたがraw_sqlする掘り下げなければならないでしょう。あなたがまだmysqlにいたなら、UPDATE JOIN構文を使用することができました。しかし残念ながらSqliteはUPDATE JOINをサポートしていません。

幸いなことに、あなたはわずか数千の行しか持っていないので、それらを繰り返して各行を個別に更新することができます。

raw_query = '''SELECT s.*, a.id as fkid 
      FROM myapp_song s 
      INNER JOIN myapp_artist a on s.temp_artist = a.name''' 
for song in Song.objects.raw(raw_query) 
    song.artist_id = s.fkid 
    song.save() 

これは、temp_artistとnameにインデックスがないため、完了するまでに数分かかる場合があります。 myappをアプリの実際の名前に置き換えてください。

EDIT1:しかしSqliteを更新JOINを持っていません

、それはあなたがサブクエリで値を設定することができません。だからこれも動作します。

UPDATE myapp_song set artist_id = 
    (SELECT id from myapp_artist WHERE name = myapp_song.temp_artist) 

これをsqliteコンソールまたはGUIに入力します。 myappを自分のアプリ名に置き換えてください。 これは単一のクエリであるため、これは非常に迅速になります。この回答の代替ソリューションを含む他のすべてのソリューションには10,000クエリが含まれています。

編集2

あなたのアーティストテーブルは、現時点では空である場合は、すべてこの操作を行う前に、あなたはそれを移植する必要がありますが、ここではそれ

INSERT INTO stackoverflow_artist(name) 
    SELECT distinct temp_artist from stackoverflow_song 

ノートない簡単なクエリでありますArtist.nameにユニークなインデックスが必要です。

+0

2番目の方法を使用している場合、myapp_artistテーブルは現在データがなく空であり、アーティスト名フィールドを最初に作成する必要があります。したがって、この時点でmyapp_artistのSELECT IDをどのようにしますか? – bayman

+0

更新しました – e4c5

+0

質問に小さなエラーがありました。それは別個のものを必要とした。また、好奇心から唯一のユニークな – e4c5

2

このロジックを実行するcustom management commandを書くことができます。ドキュメントには、セットアップ方法に関する適切な指示が記載されています。

# e.g., migrateauthors.py 
from django.core.management.base import BaseCommand 

from myapp import models 

class Command(BaseCommand): 
    help = 'Migrate authors from old schema' 

    def handle(self, *args, **options): 
     for song in myapp.models.Song.objects.all(): 
      song.artist, _ = models.Artist.objects.get_or_create(name=song.temp_artist) 
      song.save() 

その後、あなたは、単にmanage.py migrateauthorsで管理コマンドを実行します。あなたのコマンドコードは次のようになります。これが完了し検証されたら、モデルから一時フィールドを削除できます。

関連する問題