Je prévois de renommer plusieurs modèles dans un projet Django existant où de nombreux autres modèles ont des relations de clé étrangère avec les modèles que je souhaite renommer. Je suis assez certain que cela nécessitera plusieurs migrations, mais je ne suis pas sûr de la procédure exacte.
Disons que je commence avec les modèles suivants dans une application Django appelée myapp
:
class Foo(models.Model):
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
class AnotherModel(models.Model):
foo = models.ForeignKey(Foo)
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
foo = models.ForeignKey(Foo)
is_ridonkulous = models.BooleanField()
Je veux renommer le Foo
modèle parce que le nom n'a pas vraiment de sens et sème la confusion dans le code, ce Bar
qui rendrait un nom beaucoup plus clair.
D'après ce que j'ai lu dans la documentation de développement Django, je suppose la stratégie de migration suivante:
Étape 1
Modifier models.py
:
class Bar(models.Model): # <-- changed model name
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
class AnotherModel(models.Model):
foo = models.ForeignKey(Bar) # <-- changed relation, but not field name
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
foo = models.ForeignKey(Bar) # <-- changed relation, but not field name
is_ridonkulous = models.BooleanField()
Notez que le AnotherModel
nom du champ pour foo
ne change pas, mais la relation est mise à jour avec le Bar
modèle. Mon raisonnement est que je ne devrais pas trop changer à la fois et que si je change ce nom de champ enbar
je risquerais de perdre les données de cette colonne.
Étape 2
Créez une migration vide:
python manage.py makemigrations --empty myapp
Étape 3
Modifiez la Migration
classe dans le fichier de migration créé à l'étape 2 pour ajouter l' RenameModel
opération à la liste des opérations:
class Migration(migrations.Migration):
dependencies = [
('myapp', '0001_initial'),
]
operations = [
migrations.RenameModel('Foo', 'Bar')
]
Étape 4
Appliquez la migration:
python manage.py migrate
Étape 5
Modifiez les noms de champs associés dans models.py
:
class Bar(models.Model):
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
class AnotherModel(models.Model):
bar = models.ForeignKey(Bar) # <-- changed field name
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
bar = models.ForeignKey(Bar) # <-- changed field name
is_ridonkulous = models.BooleanField()
Étape 6
Créez une autre migration vide:
python manage.py makemigrations --empty myapp
Étape 7
Modifiez la Migration
classe dans le fichier de migration créé à l'étape 6 pour ajouter la ou les RenameField
opérations pour tous les noms de champs associés à la liste des opérations:
class Migration(migrations.Migration):
dependencies = [
('myapp', '0002_rename_fields'), # <-- is this okay?
]
operations = [
migrations.RenameField('AnotherModel', 'foo', 'bar'),
migrations.RenameField('YetAnotherModel', 'foo', 'bar')
]
Étape 8
Appliquer la 2ème migration:
python manage.py migrate
Hormis la mise à jour du reste du code (vues, formulaires, etc.) pour refléter les nouveaux noms de variables, est-ce essentiellement ainsi que la nouvelle fonctionnalité de migration fonctionnerait?
En outre, cela semble être beaucoup d'étapes. Les opérations de migration peuvent-elles être condensées d'une manière ou d'une autre?
Merci!
la source
apps.get_model
. m'a pris beaucoup de temps pour comprendre cela../manage.py makemigrations myapp
commande vous demandera si vous avez renommé votre modèle. Exemple: avez-vous renommé le modèle myapp.Foo en Bar? [o / N] Si vous répondez «y», votre migration contiendra lesmigration.RenameModel('Foo', 'Bar')
mêmesmanage.py makemigrations myapp
peut toujours échouer: "Vous devrez peut-être ajouter manuellement ceci si vous changez le nom du modèle et un certain nombre de ses champs à la fois; dans le détecteur automatique, cela ressemblera à vous avez supprimé un modèle avec l'ancien nom et en avez ajouté un nouveau avec un nom différent, et la migration qu'il crée perdra toutes les données de l'ancienne table. " Django 2.1 Docs Pour moi, il suffisait de créer une migration vide, d'y ajouter le nom du modèle, puis de l'exécutermakemigrations
comme d'habitude.Au début, je pensais que la méthode de Fiver fonctionnait pour moi parce que la migration fonctionnait bien jusqu'à l'étape 4. Cependant, les changements implicites «ForeignKeyField (Foo)» en «ForeignKeyField (Bar)» n'étaient liés à aucune migration. C'est pourquoi la migration a échoué lorsque j'ai voulu renommer les champs de relation (étape 5-8). Cela peut être dû au fait que mon 'AnotherModel' et 'YetAnotherModel' sont distribués dans d'autres applications dans mon cas.
J'ai donc réussi à renommer mes modèles et mes champs de relation en suivant les étapes ci-dessous:
J'ai adapté la méthode à partir de cela et en particulier le truc de l'otranzer.
Donc, comme Fiver, disons que nous avons dans myapp :
Et dans myotherapp :
Étape 1:
Transformez chaque OneToOneField (Foo) ou ForeignKeyField (Foo) en IntegerField (). (Cela conservera l'identifiant de l'objet Foo associé comme valeur du champ entier).
ensuite
Étape 2: (comme l'étape 2-4 de Fiver)
Changer le nom du modèle
Créez une migration vide:
Puis modifiez-le comme:
Finalement
Étape 3:
Transformez votre IntegerField () en leur ancien ForeignKeyField ou OneToOneField mais avec le nouveau modèle de barre. (Le champ entier précédent stockait l'id, donc django comprend cela et rétablit la connexion, ce qui est cool.)
Alors fais:
Très important, à cette étape, vous devez modifier toutes les nouvelles migrations et ajouter la dépendance aux migrations RenameModel Foo-> Bar. Donc, si AnotherModel et YetAnotherModel sont tous les deux dans myotherapp, la migration créée dans myotherapp doit ressembler à ceci:
ensuite
Étape 4:
Finalement, vous pouvez renommer vos champs
puis renommer automatiquement
(django devrait vous demander si vous avez réellement renommé le nom du modèle, dites oui)
Et c'est tout!
Cela fonctionne sur Django1.8
la source
IntegerField
. Cela a parfaitement fonctionné pour moi et a l'avantage supplémentaire de les recréer avec le nom correct. Naturellement, je conseillerais de revoir toutes les migrations avant de les exécuter!ForeignKey
deIntegerField
s a sauvé ma journée aujourd'hui!J'avais besoin de faire la même chose et de suivre. J'ai changé le modèle en une seule fois (étapes 1 et 5 ensemble de la réponse de Fiver). Ensuite, vous avez créé une migration de schéma, mais l'avez modifiée comme suit:
Cela a parfaitement fonctionné. Toutes mes données existantes sont apparues, toutes les autres tables référencées Bar fine.
à partir d'ici: https://hanmir.wordpress.com/2012/08/30/rename-model-django-south-migration/
la source
Pour Django 1.10, j'ai réussi à changer deux noms de classe de modèle (y compris un ForeignKey et avec des données) en exécutant simplement Makemigrations, puis Migrate pour l'application. Pour l'étape Makemigrations, j'ai dû confirmer que je voulais changer les noms de table. Migrate a changé les noms des tables sans problème.
Ensuite, j'ai changé le nom du champ ForeignKey pour qu'il corresponde, et Makemigrations m'a de nouveau demandé de confirmer que je voulais changer le nom. Migrer que faire le changement.
J'ai donc pris cela en deux étapes sans aucune modification de fichier spéciale. J'ai eu des erreurs au début parce que j'ai oublié de changer le fichier admin.py, comme mentionné par @wasibigeek.
la source
J'ai également fait face au problème décrit par v.thorey et j'ai trouvé que son approche est très utile mais peut être condensée en moins d'étapes qui sont en fait les étapes 5 à 8 comme Fiver décrit sans les étapes 1 à 4 sauf que l'étape 7 doit être modifiée comme mon ci-dessous l'étape 3. Les étapes générales sont les suivantes:
Étape 1: modifiez les noms de champs associés dans models.py
Étape 2: créer une migration vide
Étape 3: modifiez la classe de migration dans le fichier de migration créé à l'étape 2
Étape 4: appliquer la migration
Terminé
PS j'ai essayé cette approche sur Django 1.9
la source
J'utilise Django version 1.9.4
J'ai suivi les étapes suivantes: -
Je viens de renommer le modèle oldName en NewName Run
python manage.py makemigrations
. Il vous demandera deDid you rename the appname.oldName model to NewName? [y/N]
sélectionner YCourez
python manage.py migrate
et il vous demanderaLes types de contenu suivants sont obsolètes et doivent être supprimés:
Tous les objets liés à ces types de contenu par une clé étrangère seront également supprimés. Voulez-vous vraiment supprimer ces types de contenu? Si vous n'êtes pas sûr, répondez «non».
Il renomme et migre toutes les données existantes vers une nouvelle table nommée pour moi.
la source
Malheureusement, j'ai trouvé des problèmes (chaque django 1.x) avec la migration de changement de nom qui laissent d'anciens noms de table dans la base de données.
Django n'essaye même rien sur l'ancienne table, il suffit de renommer son propre modèle. Le même problème avec les clés étrangères et les index en général - les changements ne sont pas suivis correctement par Django.
La solution la plus simple (solution de contournement):
La vraie solution (un moyen simple de basculer tous les index, contraintes, déclencheurs, noms, etc. en 2 commits, mais plutôt pour des tables plus petites ):
commettre A:
Bar
uniquement avec le nouveau modèle . (y compris toutes les relations sur le schéma)Dans la migration, préparez
RunPython
, qui copient les données de Foo vers Bar (y comprisid
de Foo)commit B: (pas de précipitation, faites-le quand une équipe entière est migrée)
Foo
nettoyage supplémentaire:
bug dans Django:
la source
Je voulais juste confirmer et ajouter un commentaire ceasaro. Django 2.0 semble faire cela automatiquement maintenant.
Je suis sur Django 2.2.1, tout ce que j'avais à faire pour renommer le modèle et l'exécuter
makemigrations
.Ici, il demande si j'avais renommé la classe spécifique de
A
àB
, j'ai choisi oui et j'ai exécuté migrate et tout semble fonctionner.Remarque Je n'ai renommé l'ancien nom de modèle dans aucun des fichiers du dossier project / migrations.
la source
J'avais besoin de renommer quelques tables. Mais un seul changement de nom de modèle a été remarqué par Django. Cela s'est produit parce que Django itère sur les modèles ajoutés, puis supprimés. Pour chaque paire, il vérifie si elles appartiennent à la même application et ont des champs identiques . Une seule table n'avait aucune clé étrangère vers les tables à renommer (les clés étrangères contiennent le nom de la classe de modèle, comme vous vous en souvenez). En d'autres termes, une seule table n'avait aucun changement de champ. C'est pourquoi cela a été remarqué.
La solution consiste donc à renommer une table à la fois, en modifiant
models.py
éventuellement le nom de la classe de modèleviews.py
et en effectuant une migration. Après cela, inspectez votre code pour d'autres références (noms de classe de modèle, noms (de requête) associés, noms de variables). Effectuez une migration, si nécessaire. Ensuite, combinez éventuellement toutes ces migrations en une seule (assurez-vous de copier également les importations).la source
Je ferais des mots @ceasaro, les miens sur son commentaire sur cette réponse .
Les nouvelles versions de Django peuvent détecter les changements et demander ce qui a été fait. J'ajouterais également que Django pourrait mélanger l'ordre d'exécution de certaines commandes de migration.
Il serait sage d'appliquer de petits changements et courir
makemigrations
etmigrate
si l'erreur se produit le fichier de migration peut être modifié.L'ordre d'exécution de certaines lignes peut être modifié pour éviter les erreurs.
la source
migrations.SeparateDatabaseAndState
peut aider?Si vous utilisez un bon IDE comme PyCharm, vous pouvez faire un clic droit sur le nom du modèle et faire un refactor -> renommer. Cela vous évite d'avoir à parcourir tout votre code qui fait référence au modèle. Ensuite, exécutez makemigrations et migrez. Django 2+ confirmera simplement le changement de nom.
la source
J'ai mis à jour Django de la version 10 à la version 11:
(
-U
pour "mise à niveau") et cela a résolu le problème.la source