2016-03-20 15 views
9

ja dodane nowe pole do jednego z moich modeli:Jak prawidłowo dokonać migracji podczas dodawania nowego unikalne pole

class Agency(models.Model): 
    email = models.EmailField(unique=True, verbose_name=_("e-mail")) 

W tej dziedzinie nie może być puste, django-admin makemigrations o mnie, aby zapewnić jednorazowe domyślne, które Zrobiłem. Oto generowane migracja:

# Generated by Django 1.9.4 on 2016-03-20 10:38 
from __future__ import unicode_literals 

from django.db import migrations, models 


class Migration(migrations.Migration): 

    dependencies = [ 
     ('accounts', '0008_auto_20160226_1226'), 
    ] 

    operations = [ 
     migrations.AddField(
      model_name='agency', 
      name='email', 
      field=models.EmailField(default='[email protected]', max_length=254, unique=True, verbose_name='e-mail'), 
      preserve_default=False, 
     ), 
    ] 

Zgodnie z oczekiwaniami, django-admin migrate throwed błąd:

psycopg2.IntegrityError: could not create unique index "accounts_agency_email_key" 
DETAIL: Key (email)=([email protected]) is duplicate. 

Myślałem, że mogę zmieniać migrację do zestawu unikalnych wartości przed dokonaniem pole wyjątkowy. Tak próbowałem:

# -*- coding: utf-8 -*- 
# Generated by Django 1.9.4 on 2016-03-20 10:38 
from __future__ import unicode_literals 

from django.db import migrations, models 
from django.utils.text import slugify 


def set_email(apps, schema_editor): 
    Agency = apps.get_model('accounts', 'Agency') 
    for agency in Agency.objects.all(): 
     agency.email = '{}@example.fr'.format(slugify(agency.name)) 
     agency.save() 


class Migration(migrations.Migration): 

    dependencies = [ 
     ('accounts', '0008_auto_20160226_1226'), 
    ] 

    operations = [ 
     migrations.AddField(
      model_name='agency', 
      name='email', 
      field=models.EmailField(default='', max_length=254, blank=True, verbose_name='e-mail'), 
      preserve_default=False, 
     ), 
     migrations.RunPython(set_email), 
     migrations.AlterField(
      model_name='agency', 
      name='email', 
      field=models.EmailField(max_length=254, unique=True, verbose_name='e-mail'), 
      preserve_default=False, 
     ), 
    ] 

Niestety otrzymuję ten błąd podczas uruchamiania django-admin migrate:

django.db.utils.OperationalError: cannot ALTER TABLE "accounts_agency" because it has pending trigger events 

Domyślam się, że operations nie są wykonywane synchronicznie.

Myślę, że mógłbym rozwiązać problem dzieląc migrację na dwie migracje, ale chciałbym wiedzieć, czy mogę to zrobić tylko w jednej migracji. Jaki jest najczęstszy sposób tworzenia migracji podczas dodawania nowego unikalnego pola w modelu?

PS: Próbowałem też użyć wyrażenia F jako domyślne (default=models.F('name') + '@example.fr'), ale nie powiodło się:

django.db.utils.IntegrityError: could not create unique index "accounts_agency_email_key" 
DETAIL: Key (email)=(F(name) + Vallu(@example.fr)) is duplicated. 
+3

Czy przeczytałeś część dokumentacji, która dotyczy właśnie tego problemu? https://docs.djangoproject.com/en/1.9/howto/writing-migrations/#migrations-that-add-unique-fields – koniiiik

+0

@koniiiik, szukam na niewłaściwej stronie https://docs.djangoproject.com/ pl/1.9/topics/migrations/Wygląda na to, że nie ma sposobu na to, by działał z jedną migracją. –

+1

Czy jest jakiś powód, dla którego nie chcesz używać dwóch migracji? – koniiiik

Odpowiedz

2

Może to zbyt późno, ale może to mógłby pracować dla kogoś innego

Można to zrobić w jednym migracji poprzez używając migrations.RunSQL metodę

Dla przykładu kodu po dodaniu nowego pola do modelu i uruchomić Pythona makemigrations manage.py Polecenie (tutaj, jeśli istnieją już wiersze w poleceniu tabeli, chcesz wybrać domyślną wartość, możesz wybrać opcję "Podaj jednorazową domyślną opcję" i podaj jakąś wartość ciągu, ale nie jest to ważne, ponieważ w rzeczywistości jej nie użyliśmy) a następnie przejść do pliku migracji i zmienić operacji częściowo z tego (Uwaga używam PostgreSQL można zmienić SQL do bazy danych)

operations = [ 
     migrations.RunSQL(
     'ALTER TABLE "agency" ADD COLUMN "email" varchar(254) NULL;ALTER TABLE "agency" ALTER COLUMN "email" DROP DEFAULT;COMMIT;', 
     ), 
     migrations.RunSQL(
     "UPDATE agency SET email= Concat(country_code, '@example.fr');COMMIT;", 
     ), 
     migrations.RunSQL(
     'ALTER TABLE "agency" ALTER COLUMN "email" SET NOT NULL;ALTER TABLE "agency" ADD CONSTRAINT "agency_email_b551ad2a_uniq" UNIQUE ("email");ALTER TABLE "agency" ALTER COLUMN "email" DROP DEFAULT;CREATE INDEX "agency_email_b551ad2a_like" ON "agency" ("email" varchar_pattern_ops);COMMIT;' 
     ) 
    ] 

następnie uruchom „python manage.py migrować” polecenie to jest to.

+0

To było niesamowite. Dziękuję bardzo – Martin

Powiązane problemy