2016-03-20 2 views
9

ich ein neues Feld zu einem meiner Modelle hinzugefügt:Wie man richtig Migrationen zu machen, wenn ein neues eindeutiges Feld Hinzufügen

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

Da dieses Feld nicht leer sein kann, angefordert django-admin makemigrations mich Einmalstandard zu schaffen, die Ich tat. Hier ist die erzeugte Migration:

# 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, 
     ), 
    ] 

Wie erwartet, django-admin migrate einen Fehler throwed:

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

Ich dachte, ich die Migration bearbeiten könnte eindeutige Werte zu setzen, bevor das Feld einzigartig. Also habe ich versucht:

# -*- 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, 
     ), 
    ] 

Leider ich diesen Fehler erhalten, wenn django-admin migrate ausgeführt wird:

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

Meine Vermutung ist, dass operations nicht synchron ausgeführt werden.

Ich denke, ich könnte das Problem beheben, indem ich die Migration in zwei Migrationen aufspalte, aber ich würde gerne wissen, ob ich es in nur einer Migration tun kann. Wie können Migrationen normalerweise erstellt werden, wenn ein neues eindeutiges Feld in einem Modell hinzugefügt wird?

PS: Ich habe auch versucht, einen F-Ausdruck als Standard zu verwenden (default=models.F('name') + '@example.fr'), aber es ist fehlgeschlagen:

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

Haben Sie den Abschnitt der Dokumentation gelesen, der genau dieses Problem behandelt? https://docs.djangoproject.com/de/1.9/howto/writing-migrations/#migrations-that-add-unique-fields – koniiiik

+0

@koniiiik, ich suche auf der falschen Seite https://docs.djangoproject.com/ de/1.9/topics/migrations/Es sieht also so aus, als ob es keine Möglichkeit gibt, es mit nur einer Migration funktionieren zu lassen. –

+1

Gibt es einen Grund, warum Sie nicht zwei Migrationen verwenden möchten? – koniiiik

Antwort

2

Vielleicht ist es zu spät, aber vielleicht könnte es für jemand anderen arbeiten

Sie können dies tun in einer Migration migrations.RunSQL Methode

Für Ihren Beispielcode über, nachdem Sie das neue Feld zu Ihrem Modell und führen Sie die python manage.py makemigrations hinzugefügt Befehl (hier, wenn Sie bestehende Zeilen in Ihrer Tabelle Befehl will Wahl Standardwert können Sie wählen "Geben Sie einen einmaligen Standard jetzt" Option und geben Sie einen String-Wert ist es nicht wichtig, weil wir es tatsächlich nicht verwendet haben) dann gehen Sie zu Migrationsdatei und ändern Teil Operationen mit diesem (Anmerkung i postgresql verwenden Sie für Ihre Datenbank SQL ändern)

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;' 
     ) 
    ] 

dann laufen „python manage.py migrieren“ Befehl , die es ist.

+0

Das war super. Vielen Dank – Martin

Verwandte Themen