Potrzebuję zmienić typ pola w jednym z moich modeli Django z CharField
na ForeignKey
. Pola są już wypełnione danymi, więc zastanawiałem się, co jest najlepszym lub właściwym sposobem, aby to zrobić. Czy mogę po prostu zaktualizować typ pola i przeprowadzić migrację, czy też są jakieś potencjalne "gotyki", o których należy pamiętać? N.B: Używam tylko operacji zarządzania Vanilla Django (makemigrations
i migrate
), a nie Południowej.Zmiana typu pola modelu Django z CharField na ForeignKey
Odpowiedz
Jest to prawdopodobnie sytuacja, w której chcesz przeprowadzić wieloetapową migrację. Moja rekomendacja dla tego będzie wyglądać następująco.
Po pierwsze, załóżmy to początkowy model wewnątrz aplikacja nazywa discography
:
from django.db import models
class Album(models.Model):
name = models.CharField(max_length=255)
artist = models.CharField(max_length=255)
Teraz okazuje się, że chcesz użyć ForeignKey dla artysty zamiast. Jak już wspomniano, nie jest to po prostu prosty proces. Należy to zrobić w kilku krokach.
Krok 1, dodać nowe pole do ForeignKey, upewniając się, aby oznaczyć ją jako wartość null:
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)
... i stworzyć migrację do tej zmiany.
./manage.py makemigrations discography
Krok 2, zapełnij nowe pole. Aby to zrobić, musisz utworzyć pustą migrację.
./manage.py makemigrations --empty --name transfer_artists discography
Po tej pustej migracji chcesz dodać pojedynczy RunPython
operację do niego, aby połączyć swoje rekordy. W tym przypadku, może to wyglądać mniej więcej tak:
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()
Teraz, gdy dane są przesyłane do nowego pola, można rzeczywiście zrobić i zostawić wszystko tak jak jest, korzystając z nowego boiska do wszystkiego. Lub, jeśli chcesz zrobić porządek, chcesz utworzyć dwie kolejne migracje.
Podczas pierwszej migracji należy usunąć swoje oryginalne pole, artist
. Podczas drugiej migracji zmień nazwę nowego pola na artist_link
na artist
.
Odbywa się to wieloetapowo, aby upewnić się, że Django prawidłowo rozpoznaje operacje. Można utworzyć migrację ręcznie, aby sobie z tym poradzić, ale pozostawię to, aby się dowiedzieć.
Dziękujemy za szybką i kompleksową odpowiedź. To również zachęciło mnie, abym w końcu usiadł i właściwie zapoznał się z migracjami Django! – ChrisM
Czy jednak nie powinno to być './manage.py makemigrations --empty ...'? Krok 2 ma "makemigration" (w liczbie pojedynczej). – ChrisM
Ach, tak, dzięki za złapanie literówki! –
Uważaj na powielone wartości, jeśli nie masz unikalnego ograniczenia na CharField? To naprawdę zależy od tego, czy wcześniej duplikujesz dane, czy po prostu chcesz przenieść je do własnej tabeli. Jeśli to drugie, to najlepsza rzecz do zrobienia naprawdę zależy od tego, co oznaczają twoje dane. Django nie może wywnioskować jakiejś magicznej konwersji między CharField i ForeignKey. Musisz sam napisać sensowną migrację. – user234461
Myślę, że to jest podobne do tego, czego szukasz. http://stackoverflow.com/questions/5373906/changing-the-django-data-type-in-models-without-droping-the-table – Vibhu