python pour débutant
Cette approche présente certains écueils dont vous devez être conscient. Vous les explorerez en détail dans les sections suivantes.
Créer le nouveau modèle
Commencez par créer un nouveau produit
app. Depuis votre terminal, exécutez la commande suivante:
$ produit startapp python manage.py
Après avoir exécuté cette commande, vous remarquerez un nouveau répertoire appelé produit
a été ajouté au projet.
Pour enregistrer la nouvelle application avec votre projet Django existant, ajoutez-la à la liste des INSTALLED_APPS
dans Django settings.py
:
--- un / store / store / settings.py
+++ b / store / store / settings.py
@@ -40,6 +40,7 @@ INSTALLED_APPS =[[[[
'catalogue',
'vente',
+ 'produit',
]MIDDLEWARE =[
Votre nouveau produit
l'application est maintenant enregistrée auprès de Django. Ensuite, créez un Produit
modèle dans le nouveau produit
app. Vous pouvez copier le code depuis le catalogue
application:
# product / models.py
de django.db importation des modèles
de catalog.models importation Catégorie
classe Produit(des modèles.Modèle):
Nom = des modèles.CharField(longueur maximale=100, db_index=Vrai)
Catégorie = des modèles.Clé étrangère(Catégorie, on_delete=des modèles.CASCADE)
Maintenant que vous avez défini le modèle, essayez de générer des migrations pour celui-ci:
$ python manage.py makemigrations produit
SystemCheckError: la vérification du système a identifié certains problèmes:
LES ERREURS:
catalog.Product.category: (fields.E304) L'accesseur inversé pour 'Product.category' se heurte à l'accesseur inversé pour 'Product.category'.
CONSEIL: ajoutez ou modifiez un argument nom_connecté à la définition de 'Product.category' ou 'Product.category'.
product.Product.category: (fields.E304) L'accesseur inverse pour 'Product.category' se heurte à l'accesseur inverse pour 'Product.category'.
CONSEIL: ajoutez ou modifiez un argument nom_connecté à la définition de 'Product.category' ou 'Product.category'.
L'erreur indique que Django a trouvé deux modèles avec le même accesseur inversé pour le champ Catégorie
. En effet, il existe deux modèles nommés Produit
qui font référence à la Catégorie
modèle, créant un conflit.
Lorsque vous ajoutez des clés étrangères à votre modèle, Django crée un accesseur inversé dans le modèle associé. Dans ce cas, l'accesseur inversé est des produits
. L'accesseur inverse vous permet d'accéder à des objets connexes comme celui-ci: category.products
.
Le nouveau modèle est celui que vous souhaitez conserver. Pour résoudre ce conflit, supprimez l'accesseur inversé de l'ancien modèle dans catalogue / models.py
:
--- un / magasin / catalogue / models.py
+++ b / magasin / catalogue / models.py
@@ -7,4 +7,4 @@ classe Catégorie (models.Model):
Produit de classe (models.Model):
name = models.CharField (max_length = 100, db_index = True)
- category = models.ForeignKey (Category, on_delete = models.CASCADE)
+ category = models.ForeignKey (Category, on_delete = models.CASCADE, related_name = '+')
L'attribut nom_relié
peut être utilisé pour définir explicitement un nom associé pour un accesseur inversé. Ici, vous utilisez la valeur spéciale +
, qui demande à Django de ne pas créer d'accesseur inversé.
Générez maintenant une migration pour le catalogue
application:
$ python manage.py makemigrations catalogue
Migrations pour 'catalogue':
catalogue / migrations / 0002_auto_20200124_1250.py
- Modifier la catégorie de champ sur le produit
N'appliquez pas encore cette migration! Une fois cette modification effectuée, le code qui a utilisé l'accesseur inverse peut se casser.
Maintenant qu'il n'y a pas de conflit entre les accesseurs inversés, essayez de générer les migrations pour le nouveau produit
application:
$ python manage.py makemigrations produit
Migrations pour «produit»:
produit / migrations / 0001_initial.py
- Créer un modèle de produit
Génial! Vous êtes prêt à passer à l'étape suivante.
Copiez les données dans le nouveau modèle
À l'étape précédente, vous avez créé un nouveau produit
application avec un Produit
modèle identique au modèle que vous souhaitez déplacer. L'étape suivante consiste à déplacer les données de l'ancien modèle vers le nouveau modèle.
Pour créer une migration de données, exécutez la commande suivante à partir de votre terminal:
$ produit python manage.py makemigrations --empty
Migrations pour «produit»:
produit / migrations / 0002_auto_20200124_1300.py
Modifiez le nouveau fichier de migration et ajoutez l'opération pour copier les données de l'ancienne table:
de django.db importation migrations
classe Migration(migrations.Migration):
dépendances = [[[[
('produit', '0001_initial'),
]
opérations = [[[[
migrations.RunSQL("" "
INSÉRER DANS product_product (
id,
Nom,
category_id
)
SÉLECTIONNER
id,
Nom,
category_id
DE
catalog_product;
"" ", reverse_sql="" "
INSÉRER DANS catalog_product (
id,
Nom,
category_id
)
SÉLECTIONNER
id,
Nom,
category_id
DE
product_product;
"" ")
]
Pour exécuter SQL dans une migration, vous utilisez le spécial RunSQL
commande de migration. Le premier argument est le SQL à appliquer. Vous fournissez également une action pour inverser la migration à l'aide du reverse_sql
argument.
Inverser une migration peut être utile lorsque vous découvrez une erreur et que vous souhaitez annuler la modification. La plupart des actions de migration intégrées peuvent être annulées. Par exemple, l'action inverse pour ajouter un champ supprime le champ. L'action inverse pour créer une nouvelle table consiste à supprimer la table. Il est généralement préférable de fournir reverse_SQL
à RunSQL
afin que vous puissiez revenir en arrière si quelque chose tourne mal.
Dans ce cas, l'opération de migration vers l'avant insère des données de produit_produit
dans catalogue_produit
. L'opération en arrière fera exactement le contraire, en insérant des données de catalogue_produit
dans produit_produit
. En fournissant à Django l'opération inverse, vous pourrez inverser la migration en cas de sinistre.
À ce stade, vous êtes encore à mi-chemin du processus de migration. Mais il y a une leçon à tirer ici, alors allez-y et appliquez les migrations:
$ produit de migration python manage.py
Opérations à effectuer:
Appliquer toutes les migrations: produit
Exécution de migrations:
Application du produit 0001_initial ... OK
Application du produit 0002_auto_20200124_1300 ... OK
Avant de passer à l'étape suivante, essayez de créer un nouveau produit:
>>> de produits.modèles importation Produit
>>> Produit.objets.créer(Nom=«Bottes fantaisie», category_id=2)
Traceback (dernier appel le plus récent):
Fichier "/venv/lib/python3.8/site-packages/django/db/backends/utils.py", ligne 86, dans _exécuter
revenir soi.le curseur.exécuter(sql, params)
psycopg2.errors.UniqueViolation: la valeur de clé en double viole la contrainte unique "product_product_pkey"
DÉTAIL: La clé (id) = (1) existe déjà.
Lorsque vous utilisez un clé primaire à incrémentation automatique, Django crée une séquence dans la base de données pour attribuer des identifiants uniques aux nouveaux objets. Notez, par exemple, que vous n'avez pas fourni d'ID pour le nouveau produit. Normalement, vous ne voudriez pas fournir un ID, car vous souhaitez que la base de données vous attribue des clés primaires à l'aide d'une séquence. Cependant, dans ce cas, la nouvelle table a donné l'ID au nouveau produit 1
même si cet ID existait déjà dans la table.
Alors, qu'est-ce qui a mal tourné? Lorsque vous avez copié les données dans la nouvelle table, vous n'avez pas synchronisé la séquence. Pour synchroniser la séquence, vous pouvez utiliser une autre commande d'administration Django appelée sqlsequencereset
. La commande produit un script pour définir la valeur actuelle de la séquence en fonction des données existantes dans la table. Cette commande est souvent utilisée pour remplir de nouveaux modèles avec des données préexistantes.
Utilisation sqlsequencereset
pour produire un script pour synchroniser la séquence:
$ produit python manage.py sqlsequencereset
COMMENCER;
SELECT setval (pg_get_serial_sequence ('"product_product"', 'id'), coalesce (max ("id"), 1), max ("id") N'EST PAS nul)
FROM "product_product";
COMMETTRE;
Le script généré par la commande est spécifique à la base de données. Dans ce cas, la base de données est PostgreSQL. Le script définit la valeur actuelle de la séquence sur la valeur suivante que la séquence doit produire, qui est l'ID maximum dans le tableau plus un.
Pour terminer, ajoutez l'extrait de code à la migration des données:
--- un / magasin / produit / migrations / 0002_auto_20200124_1300.py
+++ b / magasin / produit / migrations / 0002_auto_20200124_1300.py
@@ -22,6 +22,8 @@ classe Migration (migrations.Migration):
category_id
DE
catalog_product;
+
+ SELECT setval (pg_get_serial_sequence ('"product_product"', 'id'), coalesce (max ("id"), 1), max ("id") N'EST PAS nul) FROM "product_product";
"" ", reverse_sql =" ""
INSÉRER DANS catalog_product (
id,
L'extrait synchronisera la séquence lorsque vous appliquerez la migration, résolvant le problème de séquence que vous avez rencontré ci-dessus.
Ce détour pour en savoir plus sur la synchronisation des séquences a créé un petit gâchis dans votre code. Pour le nettoyer, supprimez les données du nouveau modèle du shell Django:
>>> de produits.modèles importation Produit
>>> Produit.objets.tout().supprimer()
(3, 'produit.Produit': 3)
Maintenant que les données que vous avez copiées sont supprimées, vous pouvez inverser la migration. Pour inverser une migration, vous migrez vers une migration précédente:
$ produit showmigrations python manage.py
produit
[X] 0001_initial
[X] 0002_auto_20200124_1300
$ python manage.py migrer le produit 0001_initial
Opérations à effectuer:
Migration spécifique cible: 0001_initial, à partir du produit
Exécution de migrations:
Le modèle de rendu indique ... TERMINÉ
Produit non appliqué.0002_auto_20200124_1300 ... OK
Vous avez d'abord utilisé la commande showmigrations
pour répertorier les migrations appliquées à l'application produit
. La sortie montre que les deux migrations ont été appliquées. Vous avez ensuite inversé la migration 0002_auto_20200124_1300
en migrant vers la migration précédente, 0001_initial
.
Si vous exécutez showmigrations
encore une fois, vous verrez que la deuxième migration n'est plus marquée comme appliquée:
$ produit showmigrations python manage.py
produit
[X] 0001_initial
[ ] 0002_auto_20200124_1300
La case vide confirme que la deuxième migration a été inversée. Maintenant que vous avez une table rase, exécutez les migrations avec le nouveau code:
$ produit de migration python manage.py
Opérations à effectuer:
Appliquer toutes les migrations: produit
Exécution de migrations:
Application du produit 0002_auto_20200124_1300 ... OK
La migration a été appliquée avec succès. Assurez-vous que vous pouvez maintenant créer un nouveau Produit
dans le shell Django:
>>> de produits.modèles importation Produit
>>> Produit.objets.créer(Nom=«Bottes fantaisie», category_id=2)
Incroyable! Votre travail acharné a porté ses fruits et vous êtes prêt pour la prochaine étape.
Mettre à jour les clés étrangères vers le nouveau modèle
L'ancienne table contient actuellement d'autres tables qui la référencent à l'aide d'un Clé étrangère
champ. Avant de pouvoir supprimer l'ancien modèle, vous devez modifier les modèles référençant l'ancien modèle afin qu'ils référencent le nouveau modèle.
Un modèle qui fait toujours référence à l'ancien modèle est Vente
dans le vente
app. Modifiez la clé étrangère dans le Vente
modèle pour référencer le nouveau Produit
modèle:
--- un / magasin / vente / models.py
+++ b / magasin / vente / models.py
@@ -1,6 +1,6 @@
à partir des modèles d'importation django.db
-de catalogue.models importer un produit
+ de product.models import Produit
Vente de classe (models.Model):
created = models.DateTimeField ()
Générez la migration et appliquez-la:
$ python manage.py makemigrations vente
Migrations pour la «vente»:
vente / migrations / 0002_auto_20200124_1343.py
- Alter field product en vente
$ python manage.py migrer la vente
Opérations à effectuer:
Appliquer toutes les migrations: vente
Exécution de migrations:
Appliquer sale.0002_auto_20200124_1343 ... OK
le Vente
modèle fait désormais référence à la nouvelle Produit
modèle dans le produit
app. Étant donné que vous avez déjà copié toutes les données dans le nouveau modèle, il n'y a aucune violation de contrainte.
Supprimer l'ancien modèle
L'étape précédente a éliminé toutes les références à l'ancien Produit
modèle. Il est désormais sûr de supprimer l’ancien modèle du catalogue
application:
--- un / magasin / catalogue / models.py
+++ b / magasin / catalogue / models.py
@@ -3,8 +3,3 @@ à partir de modèles d'importation django.db
Catégorie Catégorie (models.Model):
name = models.CharField (max_length = 100)
-
-
-Produit de classe (modèles.Modèle):
- name = models.CharField (max_length = 100, db_index = True)
- category = models.ForeignKey (Category, on_delete = models.CASCADE, related_name = '+')
Générer une migration mais ne l'applique pas encore:
$ python manage.py makemigrations
Migrations pour 'catalogue':
catalogue / migrations / 0003_delete_product.py
- Supprimer le modèle de produit
Pour vous assurer que l'ancien modèle est supprimé uniquement après les données sont copiées, ajoutez la dépendance suivante:
--- un / magasin / catalogue / migrations / 0003_delete_product.py
+++ b / magasin / catalogue / migrations / 0003_delete_product.py
@@ -7,6 +7,7 @@ classe Migration (migrations.Migration):
dépendances =[
('catalogue', '0002_auto_20200124_1250'),
+ ('vente', '0002_auto_20200124_1343'),
]opérations =[
L'ajout de cette dépendance est extrêmement important. Ignorer cette étape peut avoir des conséquences terribles, notamment la perte de données. Pour en savoir plus sur les fichiers de migration et les dépendances entre les migrations, consultez Digging Deeper Into Django Migrations.
Remarque: Le nom de la migration inclut la date et l'heure de sa génération. Si vous suivez votre propre code, ces parties du nom seront différentes.
Maintenant que vous avez ajouté la dépendance, appliquez la migration:
$ python manage.py migrer le catalogue
Opérations à effectuer:
Appliquer toutes les migrations: catalogue
Exécution de migrations:
Application du catalogue.0003_delete_product ... OK
Le transfert est maintenant terminé! Vous avez réussi à déplacer le Produit
modèle de la catalogue
app pour le nouveau produit
en créant un nouveau modèle et en y copiant les données.
Bonus: inversez les migrations
L'un des avantages des migrations Django est qu'elles sont réversibles. Que signifie qu'une migration est réversible? Si vous faites une erreur, vous pouvez inverser la migration et la base de données reviendra à l'état d'avant l'application de la migration.
Rappelez-vous comment vous avez fourni précédemment reverse_sql
à RunSQL
? Eh bien, c'est là que ça paie.
Appliquez toutes les migrations sur une nouvelle base de données:
$ migration de python manage.py
Opérations à effectuer:
Appliquer toutes les migrations: admin, auth, catalogue, contenttypes, produit, vente, sessions
Exécution de migrations:
Application du produit 0001_initial ... OK
Application du produit 0002_auto_20200124_1300 ... OK
Appliquer sale.0002_auto_20200124_1343 ... OK
Application du catalogue.0003_delete_product ... OK
Maintenant, inversez-les tous en utilisant le mot-clé spécial zéro
:
$ python manage.py migrer le produit zéro
Opérations à effectuer:
Désappliquer toutes les migrations: produit
Exécution de migrations:
Le modèle de rendu indique ... TERMINÉ
Désapplication du catalogue.0003_delete_product ... OK
Vente sans application.0002_auto_20200124_1343 ... OK
Produit non appliqué.0002_auto_20200124_1300 ... OK
Désapplication du produit.0001_initial ... OK
La base de données est maintenant revenue à son état d'origine. Si vous déployez cette version et découvrez une erreur, vous pouvez l'inverser!
Gérer les cas spéciaux
Lorsque vous déplacez des modèles d'une application à une autre, certaines fonctionnalités de Django peuvent nécessiter une attention particulière. En particulier, ajouter ou modifier contraintes de base de données et en utilisant relations génériques les deux nécessitent des précautions supplémentaires.
Modification des contraintes
L'ajout de contraintes aux tables contenant des données peut être une opération dangereuse à effectuer sur un système en direct. Pour ajouter une contrainte, la base de données doit d'abord la vérifier. Pendant la vérification, la base de données acquiert un verrou sur la table, ce qui peut empêcher d'autres opérations jusqu'à la fin du processus.
Certaines contraintes, telles que PAS NUL
et VÉRIFIER
, peut nécessiter une analyse complète de la table pour vérifier que les nouvelles données sont valides. D'autres contraintes, telles que CLÉ ÉTRANGÈRE
, nécessitent une validation avec une autre table, ce qui peut prendre un certain temps en fonction de la taille de la table référencée.
Gestion des relations génériques
Si vous utilisez des relations génériques, vous aurez peut-être besoin d'une étape supplémentaire. Les relations génériques utilisent à la fois la clé primaire et l'ID de type de contenu du modèle pour référencer une ligne dans tout table modèle. L'ancien modèle et le nouveau modèle n'ont pas le même ID de type de contenu, les connexions génériques peuvent donc se rompre. Cela peut parfois passer inaperçu car l'intégrité des clés étrangères génériques n'est pas appliquée par la base de données.
Il existe deux façons de gérer les clés étrangères génériques:
- Mettez à jour l'ID de type de contenu du nouveau modèle à celui de l'ancien modèle.
- Mettez à jour l'ID de type de contenu de toutes les tables de référence avec celui du nouveau modèle.
Dans les deux cas, assurez-vous de le tester correctement avant de le déployer en production.
Résumé: avantages et inconvénients de la copie des données
Déplacer un modèle Django vers une autre application en copiant les données a ses avantages et ses inconvénients. Voici quelques-uns des avantages associés à cette approche:
- Il est soutenu par l'ORM: Effectuer cette transition à l'aide d'opérations de migration intégrées garantit une prise en charge appropriée de la base de données.
- C'est réversible: Inverser cette migration est possible si nécessaire.
Voici quelques-uns des les inconvénients associés à cette approche:
- C'est lent: La copie de grandes quantités de données peut prendre du temps.
- Il nécessite des temps d'arrêt: La modification des données de l'ancienne table pendant sa copie dans la nouvelle table entraînera une perte de données pendant la transition. Pour éviter que cela ne se produise, un temps d'arrêt est nécessaire.
- Il nécessite un travail manuel pour synchroniser la base de données: Le chargement des données dans des tables existantes nécessite des séquences de synchronisation et des clés étrangères génériques.
Comme vous le verrez dans les sections suivantes, l'utilisation de cette approche pour déplacer un modèle Django vers une autre application prend beaucoup plus de temps que les autres approches.
[ad_2]