Django从模型CharField引入外键

Django从模型CharField引入外键,django,sqlite,model,Django,Sqlite,Model,我已经将10000多条记录从旧的mySQL数据库迁移到Django/sqlite。在我以前的mysql模式的歌曲表中,艺术家字段不是一对多字段,而是一个mysqlvarchar字段。在我的新Django模型中,我将艺术家字段转换为ForeignKey,并使用临时艺术家从旧数据库中临时存储艺术家的姓名 如何基于临时艺术家字段创建每个歌曲实例的艺术家外键?我假设我应该使用经理的get\u或\u create方法,但是我应该在哪里以及如何编写代码 我的模型如下: class Artist (model

我已经将10000多条记录从旧的mySQL数据库迁移到Django/sqlite。在我以前的mysql模式的歌曲表中,艺术家字段不是一对多字段,而是一个mysql
varchar
字段。在我的新Django模型中,我将艺术家字段转换为
ForeignKey
,并使用临时艺术家从旧数据库中临时存储艺术家的姓名

如何基于临时艺术家字段创建每个歌曲实例的艺术家外键?我假设我应该使用经理的
get\u或\u 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")

由于您目前没有可用的外键,因此必须深入到原始sql。如果您仍然使用mysql,那么可以使用UPDATE JOIN语法。但不幸的是,Sqlite不支持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()
这可能需要几分钟才能完成,因为您没有关于临时艺术家和姓名的索引。注意用应用程序的实际名称替换myapp

Edit1:

虽然Sqlite没有update JOIN,但它允许您使用子查询设置值。所以这也会起作用

UPDATE myapp_song set artist_id = 
  (SELECT id from myapp_artist WHERE name = myapp_song.temp_artist)
在sqlite控制台或GUI中键入它。确保用您自己的应用程序名称替换myapp这将非常快,因为这是一个查询。所有其他解决方案,包括我在本答案中的替代解决方案,都涉及10000个查询

编辑2

如果您的艺术家表目前是空的,那么在执行所有这些操作之前,您必须填充它,下面是一个简单的查询

INSERT INTO stackoverflow_artist(name)
   SELECT distinct temp_artist from stackoverflow_song
请注意,您应该在Artist.name上有一个唯一的索引。您可以编写一个用于执行此逻辑的索引。这些文档为如何设置它提供了很好的说明。您的命令代码如下所示:

# 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
运行管理命令。完成并验证后,您可以从模型中删除临时字段。

如果使用第二种方法,myapp_Artister表当前为空,没有数据,需要先创建Artister name字段,那么此时它将如何从myapp_Artister中选择id?哎呀,查询中出现了一个小错误。它需要一个明确的定义。还请注意关于Uniques的观察结果出于好奇,为什么选择了另一个答案,而我的答案解释了你提出的所有问题?哎呀,我认为这个检查意味着它也起作用了。我不知道你只能选一个,但是你的更快。谢谢。当一个答案是好的时,习惯上会投票(我也会投票给另一个答案)。但是唐;别担心,没什么大不了的