Czasami zachodzi potrzeba dodania nowej, unikalnej kolumny do istniejącego już modelu w Django. Niestety jeśli w tabelce istnieją już wpisy, otrzymamy błąd. W takim przypadku, dodanie nowej kolumny należy podzielić na 3 kroki. Stworzenie kolumny bez indeksu unikalnego, wygenerowanie unikalnych wartości, dodanie indeksu. Możemy to osiągnąć, za pomocą standardowego mechanizmu migracji, który znajduje się w Django. Zacznijmy od przykładowego kodu:
from __future__ import unicode_literals | |
import common.functions | |
from django.db import migrations, models | |
def uniquify_keys_for_events(apps, schema_editor): | |
events = apps.get_model("event", "Event").objects.all() | |
for event in events: | |
event.key = common.functions.generate_random_string_32() | |
event.save() | |
class Migration(migrations.Migration): | |
dependencies = [ | |
('event', '0002_auto_20170102_1816'), | |
] | |
operations = [ | |
migrations.AddField( # krok 1 | |
model_name='event', | |
name='key', | |
field=models.CharField(max_length=32, null=True), | |
), | |
migrations.RunPython(uniquify_keys_for_events), # krok 2 | |
migrations.AlterField( # krok 3 | |
model_name='event', | |
name='key', | |
field=models.CharField(max_length=32, default=common.functions.generate_random_string_32, unique=True)) | |
] |
W przykładzie do modelu Event dodajemy kolumnę key, która zawiera unikalny ciąg znaków. Pierwszy krok tworzy nową kolumnę. W kroku 2 przekazujemy do mechanizmu funkcje Pythona. Jako parametry otrzyma ona obiekty, za pomocą których będzie mogła wykonywać operacje na bazie danych. W przykładowej funkcji wyciągamy wszystkie wiersze, które znajdują się w bazie. Przechodzimy pojedynczo przez każdy element, generujemy losowy ciąg znaków i zapisujemy zmiany w bazie. Można przyjąć dowolną strategię generowania unikalnej wartości, dla liczb może to być po prostu kolejny numer. Gdy już mamy unikalne wartości w każdym wierszu tabelki, możemy na nią nałożyć indeks unikalny (krok 3).