Django从CharField模型中引入外键

时间:2016-05-21 01:54:24

标签: django sqlite model

我已经从我的旧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")

2 个答案:

答案 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

上拥有唯一索引