2016-03-14 3 views
5

Мне нужно изменить тип поля в одной из моих моделей Django от CharField до ForeignKey. Поля уже заполнены данными, поэтому мне было интересно, что это лучший или правильный способ сделать это. Могу ли я просто обновить тип поля и выполнить миграцию, или есть ли какие-либо возможные «ошибки», о которых нужно знать? N.B: Я просто использую операции управления vanilla Django (makemigrations и migrate), а не на юг.Изменить тип поля модели Django от CharField до ForeignKey

+2

Следите за повторяющимися значениями, если у вас нет уникального ограничения на CharField? Это действительно зависит от того, дублировали ли вы данные раньше или просто хотите переместить его в свою таблицу. Если последнее, лучшее, что нужно делать, действительно зависит от того, что ваши данные ЗНАЧ. Django не может вызывать какое-либо магическое преобразование между CharField и ForeignKey. Вам нужно будет написать разумную миграцию самостоятельно. – user234461

+1

Я думаю, что это похоже на то, что вы ищете. http://stackoverflow.com/questions/5373906/changing-the-django-data-type-in-models-without-droping-the-table – Vibhu

ответ

25

Это, скорее всего, случай, когда вы хотите выполнить многоэтапную миграцию. Моя рекомендация для этого будет выглядеть примерно так:

Во-первых, давайте предположим, что это ваша первая модель, в приложение под названием discography:

from django.db import models 

class Album(models.Model): 
    name = models.CharField(max_length=255) 
    artist = models.CharField(max_length=255) 

Теперь вы понимаете, что вы хотите использовать ForeignKey для художника вместо. Ну, как уже упоминалось, это не просто процесс для этого. Это нужно сделать в несколько этапов.

Шаг 1, добавить новое поле для ForeignKey, убедившись в том, чтобы пометить его как нуль:

from django.db import models 

class Album(models.Model): 
    name = models.CharField(max_length=255) 
    artist = models.CharField(max_length=255) 
    artist_link = models.ForeignKey('Artist', null=True) 

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

... и создать миграции для этого изменения.

./manage.py makemigrations discography 

Шаг 2, заполните новое поле. Для этого вам нужно создать пустую миграцию.

./manage.py makemigrations --empty --name transfer_artists discography 

После этой пустой миграции, вы хотите добавить одну RunPython операции к нему для того, чтобы связать свои записи. В этом случае, это может выглядеть примерно так:

def link_artists(apps, schema_editor): 
    Album = apps.get_model('discography', 'Album') 
    Artist = apps.get_model('discography', 'Artist') 
    for album in Album.objects.all(): 
     artist, created = Artist.objects.get_or_create(name=album.artist) 
     album.artist_link = artist 
     album.save() 

Теперь, когда данные передаются в новое поле, вы могли бы на самом деле быть сделано, и оставить все как есть, используя новое поле для всего. Или, если вы хотите немного очистить, вы хотите создать еще две миграции.

Для первой миграции вы хотите удалить исходное поле, artist. Для вашей второй миграции переименуйте новое поле artist_link в artist.

Это сделано в несколько шагов, чтобы гарантировать, что Django правильно распознает операции. Вы можете создать миграцию вручную, чтобы справиться с этим, но я оставлю это вам, чтобы понять.

+0

Благодарим вас за ваш быстрый и всесторонний ответ. Это также стимулировало меня, наконец, сесть и правильно изучить миграцию Django! – ChrisM

+0

Не должно быть './manage.py makemigrations -empty ...', хотя? Шаг 2 имеет «makemigration» (единственное). – ChrisM

+0

А, да, спасибо за ловушку опечатки! –

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