In den beiden vorherigen Notizen habe ich viel über die Migrationsfunktion von Django gelernt. In diesem Abschnitt erfahren Sie mehr über die Fehlerbehebung bei Migrationen, die für Vorgänge hilfreich sind.
Entwicklungsumgebung |
---|
Mac OS:Sierra |
python2.7.10 |
django1.11.2 |
mysql5.7.18 |
Problembeschreibung: Die Daten wurden erstellt, nachdem die Site für einen bestimmten Zeitraum betrieben wurde. Fügen Sie Ihrem Modell nun ein neues eindeutiges Feld hinzu, das nicht nullbar ist. Legacy-Daten (vorhandene Daten) müssen Standardwerte erhalten, damit das Modell in der Datenbank angezeigt wird. Wenn Sie jedoch mehreren Datensätzen denselben Standardwert geben, verstößt dies gegen die Eindeutigkeitsregel und verursacht einen Fehler. Wenn Sie sich in einer Entwicklungsumgebung befinden, können Sie alle Datenbanken und Migrationsdateien löschen und die Datenbank neu erstellen. Lassen Sie uns dieses Problem jedoch auf eine elegantere Weise lösen.
Rufen Sie die Django-Shell auf und erstellen Sie die Demo-Daten.
python manage.py shell
>>> from polls.models import Category, Article
>>> c = Category(name="game")
>>> c.save()
>>> a1 = Article(title="play Game1", text="Game1 is amazing!", category=c, image_url = "http://url1")
>>> a1.save()
>>> a2 = Article(title="play Game2", text="Game2 is good!", category=c, image_url = "http://url2")
>>> a2.save()
>>> a3 = Article(title="play Game3", text="Game3 is dump!", category=c, image_url = "http://url3")
>>> a3.save()
Sie können die vom MySQL-Client erstellten Daten sehen (geben Sie zuerst die Projektdatenbank an). Zunächst Blog-Kategoriedaten:
mysql> select * from polls_category;
+----+------+
| id | name |
+----+------+
| 1 | game |
+----+------+
1 row in set (0.00 sec)
Als nächstes Satzdaten
mysql> select * from polls_article;
+----+------------+-------------------+-------------+-------------+
| id | title | text | category_id | image_url |
+----+------------+-------------------+-------------+-------------+
| 1 | play Game1 | Game1 is amazing! | 1 | http://url1 |
| 2 | play Game2 | Game2 is good! | 1 | http://url2 |
| 3 | play Game3 | Game3 is dump! | 1 | http://url3 |
+----+------------+-------------------+-------------+-------------+
3 rows in set (0.00 sec)
Fügen Sie nun dem Artikelmodell ein Feld article_id hinzu, um den Artikel eindeutig zu identifizieren (im Gegensatz zum automatisch erstellten Primärschlüssel). Dieses Feld erfüllt die folgenden Anforderungen: --non-nullable (Null ist nicht zulässig, da es sich um einen Bezeichner handelt. Ein Standardwert ist erforderlich.) --unique (macht es eindeutig identifizierbar) Wenn Sie die Modelldatei gemäß Ihren Anforderungen ändern:
models.py
class Article(models.Model):
title = models.CharField(max_length=100)
text = models.CharField(max_length=1000)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
image_url = models.URLField(max_length=200, default='toBeImplement')
article_id = models.UUIDField(default=uuid.uuid4(), unique=True)
(Es wird nur die Artikelklasse angezeigt.) Migrationsdatei erstellen:
python manage.py makemigrations polls
Erfolg
Migrations for 'polls':
polls/migrations/0003_article_article_id.py
- Add field article_id to article
Versuch, in der Datenbank zu reflektieren:
python manage.py migrate polls
Ich erhalte eine Fehlermeldung (Teilprotokoll)
...
django.db.utils.IntegrityError: (1062, "Duplicate entry '3059fd8259254f0693ce8d91cf1198cc' for key 'article_id'")
Sehen Sie sich die Migrationsdatei 0003_article_article_id.py an, um den Fehler zu beheben:
0003_article_article_id.py
# -*- coding: utf-8 -*-
# Generated by Django 1.11.2 on 2017-07-18 08:25
from __future__ import unicode_literals
from django.db import migrations, models
import uuid
class Migration(migrations.Migration):
dependencies = [
('polls', '0002_article_image_url'),
]
operations = [
migrations.AddField(
model_name='article',
name='article_id',
field=models.UUIDField(default=uuid.UUID('3059fd82-5925-4f06-93ce-8d91cf1198cc'), unique=True),
),
]
Der Grund für den Fehler ist, dass ich beim Hinzufügen von article_id zu einem vorhandenen Datendatensatz (Article) denselben Standardwert angegeben und die eindeutige Anforderung verletzt habe.
Wenn Sie über Legacy-Daten verfügen, sind drei Schritte erforderlich, um nicht nullfähige und eindeutige Felder hinzuzufügen. Siehe offizielle Website
Annahme: Das entsprechende Feld wurde zur Modelldatei hinzugefügt.
Schritt 1: Wie oben erwähnt, wurden die Felder bereits zum Artikelmodell hinzugefügt und die Migrationsdatei 0003_article_article_id.py wurde ebenfalls erstellt. Ändern Sie daher die Migrationsdatei 0003_article_article_id.py.
0003_article_article_id.py
# -*- coding: utf-8 -*-
# Generated by Django 1.11.2 on 2017-07-18 08:25
from __future__ import unicode_literals
from django.db import migrations, models
import uuid
class Migration(migrations.Migration):
dependencies = [
('polls', '0002_article_image_url'),
]
operations = [
migrations.AddField(
model_name='article',
name='article_id',
field=models.UUIDField(default=uuid.UUID('3059fd82-5925-4f06-93ce-8d91cf1198cc'), null=True),
),
]
Ändern Sie also "unique = True" in der Klasse Migration-> operation-> migrations.AddField () in "null = True". Sie können jetzt dieselben Standardwerte in die neue Spalte der Altdaten einfügen.
Schritt 2: Erstellen Sie eine leere Migrationsdatei.
python manage.py makemigrations polls --empty
Fügen Sie nun einen eindeutigen Wert für jeden Datensatz von Altdaten in eine neue Spalte ein
0004_auto_20170718_0901.py
# -*- coding: utf-8 -*-
# Generated by Django 1.11.2 on 2017-07-18 09:01
from __future__ import unicode_literals
from django.db import migrations
import uuid
def gen_uuid(apps, schema_editor):
Article = apps.get_model('polls', 'Article')
for row in Article.objects.all():
row.article_id = uuid.uuid4()
row.save(update_fields=['article_id'])
class Migration(migrations.Migration):
dependencies = [
('polls', '0003_article_article_id'),
]
operations = [
migrations.RunPython(gen_uuid, reverse_code=migrations.RunPython.noop)
]
Schritt 3: Erstellen Sie abschließend erneut eine leere Migrationsdatei und setzen Sie die Spaltenattribute wieder auf eindeutig. Jetzt können Sie die Spalten des neu erstellten Datensatzes einschränken.
0005_auto_20170718_0901.py
# -*- coding: utf-8 -*-
# Generated by Django 1.11.2 on 2017-07-18 09:01
from __future__ import unicode_literals
from django.db import migrations, models
import uuid
class Migration(migrations.Migration):
dependencies = [
('polls', '0004_auto_20170718_0901'),
]
operations = [
migrations.AlterField(
model_name='article',
name='article_id',
field=models.UUIDField(default=uuid.uuid4, unique=True),
),
]
Sobald die Migrationsdatei fertig ist, spiegeln Sie die Änderungen am Modell und an den Altdaten wider.
(a_site) IT-02085-M:m_Migrate ruofan.ye$ python manage.py migrate polls
Operations to perform:
Apply all migrations: polls
Running migrations:
Applying polls.0003_article_article_id... OK
Applying polls.0004_auto_20170718_0901... OK
Applying polls.0005_auto_20170718_0901... OK
Erfolg, und wenn Sie sich die Datenbank ansehen
mysql> select * from polls_article;
+----+------------+-------------------+-------------+-------------+----------------------------------+
| id | title | text | category_id | image_url | article_id |
+----+------------+-------------------+-------------+-------------+----------------------------------+
| 1 | play Game1 | Game1 is amazing! | 1 | http://url1 | 7347eab9e4df47eb989de30fc6baeec9 |
| 2 | play Game2 | Game2 is good! | 1 | http://url2 | c4bac1cc1d3242aa934c9cb16f1cf5a9 |
| 3 | play Game3 | Game3 is dump! | 1 | http://url3 | e6094b7b24fc46e7a59a7b90aaca298c |
+----+------------+-------------------+-------------+-------------+----------------------------------+
3 rows in set (0.00 sec)
Sie haben Ihrer Tabelle und Ihren Altdaten erfolgreich eine neue Spalte hinzugefügt. Neue Artikeldaten erstellen:
>>> a4 = Article(title="play Game4", text="Game4 is new-feeling!", category=c, image_url = "http://url4")
>>> a4.save()
Blick in die Datenbank:
mysql> select * from polls_article;
+----+------------+-----------------------+-------------+-------------+----------------------------------+
| id | title | text | category_id | image_url | article_id |
+----+------------+-----------------------+-------------+-------------+----------------------------------+
| 1 | play Game1 | Game1 is amazing! | 1 | http://url1 | 7347eab9e4df47eb989de30fc6baeec9 |
| 2 | play Game2 | Game2 is good! | 1 | http://url2 | c4bac1cc1d3242aa934c9cb16f1cf5a9 |
| 3 | play Game3 | Game3 is dump! | 1 | http://url3 | e6094b7b24fc46e7a59a7b90aaca298c |
| 4 | play Game4 | Game4 is new-feeling! | 1 | http://url4 | 0f1fcf070c544784b2a11ba2a4661cd7 |
+----+------------+-----------------------+-------------+-------------+----------------------------------+
4 rows in set (0.00 sec)
Das Feld article_id wurde wie erwartet implementiert.
Recommended Posts