Dans les deux notes précédentes, j'ai beaucoup appris sur la fonctionnalité de migration de django. Cette fois, apprenons à résoudre les problèmes de migrations utiles pour les opérations.
Environnement de développement |
---|
Mac OS:Sierra |
python2.7.10 |
django1.11.2 |
mysql5.7.18 |
Description du problème: Les données ont été créées après que le site a été exploité pendant un certain temps. Ajoutez maintenant un nouveau champ unique, non nullable à votre modèle. Les données héritées (données existantes) doivent recevoir des valeurs par défaut pour que le modèle soit reflété dans la base de données. Cependant, attribuer la même valeur par défaut à plusieurs enregistrements de données enfreint la règle d'unicité et provoque une erreur. Si vous êtes dans un environnement de développement, vous pouvez supprimer toutes les bases de données et fichiers de migration et recréer la base de données, mais résolvons ce problème de manière plus gracieuse.
Entrez dans le shell Django et créez les données de démonstration.
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()
Vous pouvez voir les données créées par le client mysql (spécifiez d'abord la base de données du projet). Tout d'abord, les données de catégorie de blog:
mysql> select * from polls_category;
+----+------+
| id | name |
+----+------+
| 1 | game |
+----+------+
1 row in set (0.00 sec)
Ensuite, les données de phrase
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)
Ajoutez maintenant un champ article_id au modèle Article pour identifier de manière unique l'article (contrairement à la clé primaire créée automatiquement). Ce champ répond aux exigences suivantes: --non-nullable (Null n'est pas autorisé car il s'agit d'un identifiant, une valeur par défaut est requise) --unique (le rend identifiable de manière unique) Si vous modifiez le fichier modèle en fonction de vos besoins:
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)
(Seule la classe d'article est affichée) Créez un fichier de migrations:
python manage.py makemigrations polls
Succès
Migrations for 'polls':
polls/migrations/0003_article_article_id.py
- Add field article_id to article
Essayer de refléter dans la base de données:
python manage.py migrate polls
J'obtiens une erreur (journal partiel)
...
django.db.utils.IntegrityError: (1062, "Duplicate entry '3059fd8259254f0693ce8d91cf1198cc' for key 'article_id'")
Pour clarifier l'erreur, jetez un œil au fichier de migrations 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'), unique=True),
),
]
La raison de l'erreur est que lorsque j'ai ajouté article_id à un enregistrement de données (article) existant, je lui ai donné la même valeur par défaut et violé l'exigence unique.
Si vous disposez de données héritées, trois étapes sont nécessaires pour ajouter des champs uniques et non nullables. Reportez-vous au site officiel
Hypothèse: Ajout du champ correspondant au fichier modèle.
Étape 1: Comme mentionné ci-dessus, les champs ont déjà été ajoutés au modèle d'article et le fichier de migration 0003_article_article_id.py a également été créé. Par conséquent, modifiez le fichier de migrations 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),
),
]
Autrement dit, remplacez "unique = True" dans la classe Migration-> operations-> migrations.AddField () par "null = True". Vous pouvez maintenant mettre les mêmes valeurs par défaut dans la nouvelle colonne des données héritées.
Étape 2: Créez un fichier de migration vierge.
python manage.py makemigrations polls --empty
Maintenant, mettez une valeur unique pour chaque enregistrement de données héritées dans une nouvelle colonne
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)
]
Étape 3: Enfin, créez à nouveau un fichier de migration vide et redéfinissez les attributs de colonne sur unique. Vous pouvez maintenant limiter les colonnes de l'enregistrement de données nouvellement créé.
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),
),
]
Une fois le fichier de migrations prêt, reflétez les modifications apportées au modèle et aux données héritées.
(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
Succès, et si vous regardez la base de données
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)
Vous avez ajouté avec succès une nouvelle colonne à votre table et à vos données héritées. Créer de nouvelles données d'article:
>>> a4 = Article(title="play Game4", text="Game4 is new-feeling!", category=c, image_url = "http://url4")
>>> a4.save()
En regardant la base de données:
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)
Le champ article_id a été implémenté comme prévu.
Recommended Posts