python pour débutant
- Conseils de sécurité hors site faciles pour WordPress
- Techniques avancées d'importation Python et gestion des utilisateurs dans Django – Le vrai podcast Python
- Comment monétiser un blog: 7 stratégies de Kickass Pro
- Corrélation avec Python – Real Python
- Réflexions sur l'édition collaborative dans WordPress • WPShout
Voici le deuxième article de notre série sur les migrations Django:
Dans le précédent article de cette série, vous avez appris le but des migrations de Django. Vous vous êtes familiarisé avec les modèles d'utilisation fondamentaux tels que la création et l'application de migrations. Il est maintenant temps d’approfondir la question du système de migration et de jeter un coup d’œil sur certains de ses mécanismes sous-jacents.
À la fin de cet article, vous saurez:
- Comment Django assure le suivi des migrations
- Comment les migrations savent quelles opérations de base de données effectuer
- Comment les dépendances entre les migrations sont définies
Une fois que vous avez compris cette partie du système de migration Django, vous serez bien préparé pour créer vos propres migrations personnalisées. Passons directement là où nous nous sommes arrêtés!
Cet article utilise le bitcoin_tracker
Projet Django intégré à Django Migrations: A Primer. Vous pouvez recréer ce projet en travaillant sur cet article ou télécharger le code source:
Comment Django sait quelles migrations appliquer
Récapitulons la toute dernière étape de l’article précédent de la série. Vous avez créé une migration, puis appliqué toutes les migrations disponibles avec python manage.py migrer
.
Si cette commande a été exécutée avec succès, vos tables de base de données correspondent maintenant aux définitions de votre modèle.
Que se passe-t-il si vous exécutez à nouveau cette commande? Essayons-le:
$ python manage.py migrer
Opérations à effectuer:
Appliquer toutes les migrations: admin, auth, contenttypes, historical_data, sessions
Migrations en cours:
Aucune migration à appliquer.
Rien ne s'est passé! Une fois qu'une migration a été appliquée à une base de données, Django n'appliquera plus cette migration à cette base de données particulière. S'assurer qu'une migration n'est appliquée qu'une seule fois nécessite de garder une trace des migrations appliquées.
Django utilise une table de base de données appelée django_migrations
. Django crée automatiquement cette table dans votre base de données la première fois que vous appliquez une migration. Pour chaque migration appliquée ou falsifiée, une nouvelle ligne est insérée dans le tableau.
Par exemple, voici à quoi ressemble ce tableau dans notre bitcoin_tracker
projet:
ID | App | prénom | Appliqué |
---|---|---|---|
1 | types de contenu |
0001_initial |
2019-02-05 20: 23: 21.461496 |
2 | auth |
0001_initial |
2019-02-05 20: 23: 21.489948 |
3 | admin |
0001_initial |
2019-02-05 20: 23: 21.508742 |
4 | admin |
0002_logentry_remove ... |
2019-02-05 20: 23: 21.531390 |
5 | admin |
0003_logentry_add_ac ... |
2019-02-05 20: 23: 21.564834 |
6 | types de contenu |
0002_remove_content _... |
2019-02-05 20: 23: 21.597186 |
7 | auth |
0002_alter_permissio ... |
2019-02-05 20: 23: 21.608705 |
8 | auth |
0003_alter_user_emai ... |
2019-02-05 20: 23: 21.628441 |
9 | auth |
0004_alter_user_user ... |
2019-02-05 20: 23: 21.646824 |
dix | auth |
0005_alter_user_last ... |
2019-02-05 20: 23: 21.661182 |
11 | auth |
0006_require_content ... |
2019-02-05 20: 23: 21.663664 |
12 | auth |
0007_alter_validator ... |
2019-02-05 20: 23: 21.679482 |
13 | auth |
0008_alter_user_user ... |
2019-02-05 20: 23: 21.699201 |
14 | auth |
0009_alter_user_last ... |
2019-02-05 20: 23: 21.718652 |
15 | données historiques |
0001_initial |
2019-02-05 20: 23: 21.726000 |
16 | sessions |
0001_initial |
2019-02-05 20: 23: 21.734611 |
19 | données historiques |
0002_switch_to_decimals |
2019-02-05 20: 30: 11,337894 |
Comme vous pouvez le constater, il existe une entrée pour chaque migration appliquée. La table contient non seulement les migrations de notre données historiques
app, mais aussi les migrations de toutes les autres applications installées.
Lors de la prochaine exécution des migrations, Django ignorera les migrations répertoriées dans la table de base de données. Cela signifie que, même si vous modifiez manuellement le fichier d'une migration déjà appliquée, Django ignorera ces modifications, à condition qu'il y ait déjà une entrée correspondante dans la base de données.
Vous pouvez amener Django à réexécuter une migration en supprimant la ligne correspondante de la table, mais ceci est rarement une bonne idée et peut vous laisser avec un système de migration endommagé.
Le fichier de migration
Qu'est-ce qui se passe quand tu cours python manage.py makemigrations
? Django recherche les modifications apportées aux modèles de votre application.
. S'il en trouve, comme un modèle ajouté, il crée un fichier de migration dans le dossier migrations
sous-répertoire. Ce fichier de migration contient une liste d'opérations permettant de synchroniser votre schéma de base de données avec la définition de votre modèle.
Remarque: Votre application doit être répertoriée dans le INSTALLED_APPS
réglage, et il doit contenir un migrations
répertoire avec un __init__.py
fichier. Sinon, Django ne créera aucune migration pour cela.
le migrations
Le répertoire est automatiquement créé lorsque vous créez une nouvelle application avec le startapp
commande de gestion, mais il est facile d’oublier lors de la création manuelle d’une application.
Les fichiers de migration ne sont que Python. Voyons donc le premier fichier de migration du prix_historique
app. Vous pouvez le trouver à historical_prices / migrations / 0001_initial.py
. Ça devrait ressembler a quelque chose comme ca:
de django.db importation des modèles, migrations
classe Migration(migrations.Migration):
les dépendances = []
opérations = [[[[
migrations.CreateModel(
prénom='PriceHistory',
des champs=[[[[
('id', des modèles.AutoField(
nom verbeux='ID',
sérialiser=Faux,
clé primaire=Vrai,
auto_created=Vrai)),
('rendez-vous amoureux', des modèles.DateTimeField(auto_now_add=Vrai)),
('prix', des modèles.DecimalField(décimal_places=2, max_digits=5)),
('le volume', des modèles.PositiveIntegerField()),
('total_btc', des modèles.PositiveIntegerField()),
],
options=
,
des bases=(des modèles.Modèle,),
),
]
Comme vous pouvez le voir, il contient une seule classe appelée Migration
qui hérite de django.db.migrations.Migration
. Il s'agit de la classe que l'infrastructure de migration recherchera et exécutera lorsque vous lui demanderez d'appliquer des migrations.
le Migration
La classe contient deux listes principales:
les dépendances
opérations
Opérations de migration
Regardons le opérations
liste en premier. Cette table contient les opérations à effectuer dans le cadre de la migration. Les opérations sont des sous-classes de la classe django.db.migrations.operations.base.Operation
. Voici les opérations courantes intégrées à Django:
Classe d'opération | La description |
---|---|
CreateModel |
Crée un nouveau modèle et la table de base de données correspondante |
DeleteModel |
Supprime un modèle et supprime sa table de base de données |
RenommerModèle |
Renomme un modèle et renomme sa table de base de données |
AlterModelTable |
Renomme la table de base de données pour un modèle |
AlterUniqueTogether |
Change les contraintes uniques d'un modèle |
AlterIndexTogether |
Change les index d'un modèle |
AlterOrderWithRespectTo |
Crée ou supprime le _ordre colonne pour un modèle |
AlterModelOptions |
Modifie diverses options de modèle sans affecter la base de données |
AlterModelManagers |
Modifie les gestionnaires disponibles lors des migrations |
Ajouter le champ |
Ajoute un champ à un modèle et à la colonne correspondante dans la base de données |
RemoveField |
Supprime un champ d'un modèle et supprime la colonne correspondante de la base de données |
AlterField |
Modifie la définition d’un champ et modifie sa colonne de la base de données si nécessaire |
RenameField |
Renomme un champ et éventuellement sa colonne de base de données |
AddIndex |
Crée un index dans la table de base de données pour le modèle |
RemoveIndex |
Supprime un index de la table de base de données pour le modèle |
Notez que les opérations sont nommées en fonction des modifications apportées aux définitions de modèle, et non des actions effectuées sur la base de données. Lorsque vous appliquez une migration, chaque opération est chargée de générer les instructions SQL nécessaires pour votre base de données spécifique. Par exemple, CreateModel
générerait un CREER LA TABLE
Instruction SQL.
Les migrations prêtes à l'emploi prennent en charge toutes les bases de données standard prises en charge par Django. Ainsi, si vous vous en tenez aux opérations répertoriées ici, vous pourrez apporter plus ou moins de modifications à vos modèles, sans avoir à vous soucier du code SQL sous-jacent. Tout est fait pour vous.
Remarque: Dans certains cas, Django pourrait ne pas détecter correctement vos modifications. Si vous renommez un modèle et modifiez plusieurs de ses champs, Django pourrait le confondre avec un nouveau modèle.
Au lieu d'une RenommerModèle
et plusieurs AlterField
opérations, il va créer un DeleteModel
et un CreateModel
opération. Au lieu de renommer la table de base de données pour le modèle, il la supprimera et créera une nouvelle table avec le nouveau nom, supprimant ainsi toutes vos données!
Prenez l'habitude de vérifier les migrations générées et de les tester sur une copie de votre base de données avant de les exécuter sur les données de production.
Django fournit trois classes d'opération supplémentaires pour les cas d'utilisation avancés:
RunSQL
vous permet d'exécuter du code SQL personnalisé dans la base de données.RunPython
vous permet d'exécuter n'importe quel code Python.SeparateDatabaseAndState
est une opération spécialisée pour les utilisations avancées.
Avec ces opérations, vous pouvez essentiellement apporter les modifications souhaitées à votre base de données. Cependant, vous ne trouverez pas ces opérations dans une migration créée automatiquement avec le makemigrations
commande de gestion.
Depuis Django 2.0, quelques opérations spécifiques à PostgreSQL sont disponibles dans django.contrib.postgres.operations
que vous pouvez utiliser pour installer diverses extensions PostgreSQL:
BtreeGinExtension
BtreeGistExtension
CITextExtension
CryptoExtension
HStoreExtension
TrigramExtension
UnaccentExtension
Notez qu'une migration contenant l'une de ces opérations nécessite un utilisateur de base de données doté des privilèges de superutilisateur.
Enfin, vous pouvez également créer vos propres classes d'opération. Si vous souhaitez examiner cela, consultez la documentation de Django sur la création d'opérations de migration personnalisées.
Dépendances de la migration
le les dépendances
La liste dans une classe de migration contient toutes les migrations qui doivent être appliquées avant que cette migration puisse être appliquée.
dans le 0001_initial.py
la migration que vous avez vue ci-dessus, rien ne doit être appliqué auparavant, donc il n'y a pas de dépendances. Regardons la deuxième migration dans le prix_historique
app. Dans le fichier 0002_switch_to_decimals.py
, la les dépendances
attribut de Migration
a une entrée:
de django.db importation migrations, des modèles
classe Migration(migrations.Migration):
les dépendances = [[[[
('données historiques', '0001_initial'),
]
opérations = [[[[
migrations.AlterField(
nom du modèle='histoire de prix',
prénom='le volume',
champ=des modèles.DecimalField(décimal_places=3, max_digits=7),
),
]
La dépendance ci-dessus dit que la migration 0001_initial
de l'application données historiques
doit être exécuté en premier. Cela a du sens, car la migration 0001_initial
crée la table contenant le champ que la migration 0002_switch_to_decimals
veut changer.
Une migration peut également dépendre d'une migration d'une autre application, comme ceci:
classe Migration(migrations.Migration):
...
les dépendances = [[[[
('auth', '0009_alter_user_last_name_max_length'),
]
Cela est généralement nécessaire si un modèle a une clé étrangère qui pointe vers un modèle dans une autre application.
Alternativement, vous pouvez également exiger qu'une migration soit exécutée avant une autre migration utilisant l'attribut run_before
:
classe Migration(migrations.Migration):
...
run_before = [[[[
('third_party_app', '0001_initial'),
]
Les dépendances peuvent également être combinées afin que vous puissiez avoir plusieurs dépendances. Cette fonctionnalité offre beaucoup de flexibilité, car vous pouvez gérer des clés étrangères qui dépendent de modèles de différentes applications.
L’option de définir explicitement les dépendances entre les migrations signifie également que la numérotation des migrations (généralement 0001
, 0002
, 0003
,…) Ne représente pas strictement l’ordre dans lequel les migrations sont appliquées. Vous pouvez ajouter n'importe quelle dépendance et contrôler ainsi l'ordre sans avoir à renuméroter toutes les migrations.
Affichage de la migration
En général, vous n'avez pas à vous soucier du SQL généré par les migrations. Mais si vous voulez vérifier que le SQL généré a du sens ou si vous voulez juste savoir de quoi il a l'air, alors Django vous en informera. sqlmigrate
commande de gestion:
$ python manage.py sqlmigrate historical_data 0001
COMMENCER;
-
- Créer un modèle PriceHistory
-
CREATE TABLE "historique_données_prix_historique" (
"id" entier NON NUL PRIMARY KEY AUTOINCREMENT,
"date" datetime NON NULL,
"prix" décimal NON NULL,
"volume" entier non signé NON NUL
)
COMMETTRE;
Faire cela listera les requêtes SQL sous-jacentes qui seront générées par la migration spécifiée, en fonction de la base de données de votre settings.py
fichier. Quand vous passez le paramètre --en arrière
Django génère le code SQL pour désappliquer la migration:
$ python manage.py sqlmigrate --backwards historical_data 0001
COMMENCER;
-
- Créer un modèle PriceHistory
-
DROP TABLE "historique_data_prix_historique";
COMMETTRE;
Une fois que vous voyez la sortie de sqlmigrate
Pour une migration légèrement plus complexe, vous comprendrez que vous n’avez pas à concevoir tout ce SQL à la main!
Comment Django détecte les modifications apportées à vos modèles
Vous avez vu à quoi ressemble un fichier de migration et comment sa liste de Opération
classes définit les modifications apportées à la base de données. Mais comment Django sait-il exactement quelles opérations doivent être insérées dans un fichier de migration? Vous pourriez vous attendre à ce que Django compare vos modèles à votre schéma de base de données, mais ce n'est pas le cas.
Lors de l'exécution makemigrations
Django fait ne pas inspecter votre base de données. Il ne compare pas non plus votre fichier de modèle à une version antérieure. Au lieu de cela, Django parcourt toutes les migrations qui ont été appliquées et crée un état de projet de ce à quoi les modèles devraient ressembler. Cet état de projet est ensuite comparé à vos définitions de modèle actuelles et une liste d'opérations est créée. Elle permet, si elle est appliquée, de mettre l'état du projet à jour avec les définitions de modèle.
Jouer aux échecs avec Django
Vous pouvez considérer vos modèles comme un échiquier et Django est un grand maître des échecs qui vous surveille. Mais le grand maître ne surveille pas chacun de vos mouvements. Le grand maître ne regarde le tableau que lorsque vous criez makemigrations
.
Comme il n’ya qu’un nombre limité de mouvements possibles (et que le grand maître est un grand maître), elle peut imaginer les mouvements qui se sont produits depuis sa dernière visite au tableau. Elle prend des notes et vous laisse jouer jusqu'à ce que vous criiez makemigrations
encore.
La prochaine fois que le grand maître regarde le tableau, il ne se souvient pas à quoi ressemblait l’échiquier la dernière fois, mais elle peut parcourir ses notes des mouvements précédents et construire un modèle mental de ce à quoi l’échiquier ressemblait.
Maintenant, quand vous criez émigrer
, le grand maître rejouera tous les mouvements enregistrés sur un autre échiquier et notera dans un tableur quels de ses disques ont déjà été appliqués. Ce deuxième échiquier est votre base de données et la feuille de calcul est le django_migrations
table.
Cette analogie est tout à fait appropriée, car elle illustre bien certains comportements des migrations Django:
-
Les migrations Django tentent d’être efficaces: Tout comme le grand maître suppose que vous avez effectué le moins de mouvements possible, Django tentera de créer les migrations les plus efficaces. Si vous ajoutez un champ nommé
UNE
à un modèle, puis renommez-le enB
puis courirmakemigrations
puis Django créera une nouvelle migration pour ajouter un champ nomméB
. -
Les migrations Django ont leurs limites: Si vous faites beaucoup de mouvements avant de laisser la grand-maîtresse regarder l'échiquier, elle risque alors de ne pas être en mesure de retracer les mouvements exacts de chaque pièce. De même, Django pourrait ne pas proposer la migration correcte si vous apportez trop de modifications en même temps.
-
La migration de Django attend de vous que vous respectiez les règles: Lorsque vous faites quelque chose d’imprévu, comme prendre un morceau au hasard sur le tableau ou jouer avec les notes, le grand maître ne le remarquera peut-être pas au début, mais tôt ou tard, elle lèvera les mains et refusera de continuer. La même chose arrive quand vous jouez avec le
django_migrations
table ou modifiez votre schéma de base de données en dehors des migrations, par exemple en supprimant la table de base de données d'un modèle.
Compréhension SeparateDatabaseAndState
Maintenant que vous connaissez l’état du projet créé par Django, il est temps d’examiner de plus près le fonctionnement SeparateDatabaseAndState
. Cette opération peut faire exactement ce que son nom implique: elle peut séparer l’état du projet (le modèle mental construit par Django) de votre base de données.
SeparateDatabaseAndState
est instancié avec deux listes d'opérations:
state_operations
contient des opérations qui ne sont appliquées qu'à l'état du projet.opérations_base_de_données
contient des opérations qui ne sont appliquées qu'à la base de données.
Cette opération vous permet d’apporter tout type de modification à votre base de données, mais il vous incombe de vous assurer que l’état du projet correspond à la base de données par la suite. Exemple de cas d'utilisation pour SeparateDatabaseAndState
déplacez un modèle d'une application à une autre ou créez un index sur une énorme base de données sans temps d'arrêt.
SeparateDatabaseAndState
est une opération avancée et vous n’aurez pas besoin de travailler le premier jour avec les migrations et peut-être jamais du tout. SeparateDatabaseAndState
est similaire à la chirurgie cardiaque. Cela comporte pas mal de risques et n’est pas quelque chose que vous faites juste pour le plaisir, mais c’est parfois une procédure nécessaire pour garder le patient en vie.
Conclusion
Ceci conclut votre plongée dans les migrations Django. Toutes nos félicitations! Vous avez abordé un grand nombre de sujets avancés et vous comprenez maintenant mieux ce qui se passe sous le capot des migrations.
Vous avez appris que:
- Django suit les migrations appliquées dans la table des migrations Django.
- Les migrations Django se composent de fichiers Python simples contenant un
Migration
classe. - Django sait quels changements effectuer depuis le
opérations
liste dans leMigration
Des classes. - Django compare vos modèles à l'état du projet qu'il a construit à partir des migrations.
Grâce à ces connaissances, vous êtes maintenant prêt à aborder la troisième partie de la série sur les migrations Django, dans laquelle vous apprendrez à utiliser les migrations de données pour apporter en toute sécurité des modifications uniques à vos données. Restez à l'écoute!
Cet article utilisait le bitcoin_tracker
Projet Django intégré à Django Migrations: A Primer. Vous pouvez recréer ce projet en travaillant sur cet article ou télécharger le code source:
[ad_2]