我已经从我的旧mySQL数据库迁移了10,000多条记录到Django / sqlite。在我的旧mysql架构的Song表中,artist字段不是1到多个字段,而只是一个mysql varchar
字段。在我的新Django模型中,我将artist字段转换为ForeignKey
并使用temp_artist临时存储旧数据库中的艺术家名称。
如何根据temp_artist字段创建每个Song实例的artist外键?我假设我应该使用经理的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")
答案 0 :(得分: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
运行管理命令。完成并验证后,您可以从模型中删除临时字段。
答案 1 :(得分: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
上拥有唯一索引