2016-05-21 3 views
1

Я перенесла более 10 000 записей из моей старой базы данных mySQL в Django/sqlite. В моей старой таблице комментариев схемы mysql поле художника не было полем от 1 до большого числа, а было только поле mysql varchar. В моей новой модели Django я преобразовал поле художника в ForeignKey и использовал temp_artist, чтобы временно сохранить имя исполнителя из старой базы данных.Django Введите внешний ключ от модели CharField

Как создать пользовательский интерфейс экземпляра экземпляра каждой песни на основе поля temp_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") 

ответ

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 и имени. Позаботьтесь о замене 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 запросов.

Edit 2

Если Исполнитель таблица пуста в настоящее время, прежде чем вы сделаете все это, вы должны будете заполнить его, вот простой запрос, который делает это

INSERT INTO stackoverflow_artist(name) 
    SELECT distinct temp_artist from stackoverflow_song 

сведению что у вас должен быть уникальный указатель на Artist.name

+0

Если вы используете свой второй метод, таблица myapp_artist в настоящее время пуста, без каких-либо данных, и сначала должно быть создано поле имени исполнителя, так как это будет SELECT id из myapp_artist в этот момент? – 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. Как только это будет сделано и проверено, вы можете удалить временное поле из своей модели.

Смежные вопросы