J'ai ajouté un nouveau champ non nullable à mon modèle Django et j'essaie d'utiliser les migrations pour déployer ce changement. Comment pourrais-je définir la valeur par défaut à utiliser pour que les modèles existants soient une fonction de ceux-ci modèles plutôt qu'une constante?
Par exemple, disons que j'avais précédemment un created_on
champ et je viens d'ajouter un updated_on
champ dont je veux définir initialement la valeur created_on
. Comment procéder dans une migration?
Voici ce que j'essaie de commencer:
migrations.AddField(
model_name='series',
name='updated_as',
field=models.DateTimeField(default=????, auto_now=True),
preserve_default=False,
),
Je viens d'apprendre à le faire avec une seule migration!
lors de l'exécution de makemigrations
Django devrait vous demander de définir une valeur unique par défaut. Définissez tout ce que vous pouvez ici pour le satisfaire, et vous vous retrouverez avec la migration AddField
vous avez mentionné.
migrations.AddField(
model_name='series',
name='updated_as',
field=models.DateTimeField(default=????, auto_now=True),
),
Modifiez cette opération en 3 opérations:
AlterField
) pour le rendre non nullable (comme ci-dessus, sans valeur par défaut).donc vous vous retrouvez avec quelque chose comme.
migrations.AddField(
model_name='series',
name='updated_as',
field=models.DateTimeField(null=True, auto_now=True),
),
migrations.RunPython(set_my_defaults, reverse_func),
migrations.AlterField(
model_name='series',
name='updated_as',
field=models.DateTimeField(auto_now=True),
),
avec vos fonctions définies comme quelque chose comme:
def set_my_defaults(apps, schema_editor):
Series = apps.get_model('myapp', 'Series')
for series in Series.objects.all().iterator():
series.updated_as = datetime.now() + timedelta(days=series.some_other_field)
series.save()
def reverse_func(apps, schema_editor):
pass # code for reverting migration, if any
Sauf, vous savez, pas terrible; pensez à utiliser expressions F et/ou fonctions de base de données pour augmenter les performances de migration pour les grandes bases de données.
Vous devez le faire en deux migrations. Tout d'abord, ajoutez votre champ, mais rendez nullable. Créez un fichier de migration comme d'habitude. Après cela, définissez votre champ sur non-nullable et exécutez à nouveau makemigrations, mais ne lancez pas encore la migration. Ouvrez la deuxième migration et définissez une fonction en haut:
def set_field_values(apps, schema_editor):
# use apps.get_model("app_name", "model_name") and set the defualt values
puis, dans votre fichier de migration, il y a une liste d'opérations. Avant l'ajout d'une opération de modification de champ
RunPython(set_field_values)
et ça devrait le faire
Vous devez également définir un inverse pour votre fonction set_my_defaults()
, au cas où vous annuleriez la migration à l'avenir.
def reverse_set_default(apps, schema_editor):
pass
Dans ce cas, la fonction inverse ne doit rien faire, car vous supprimez le champ.
Et ajoutez-le à RunPython:
migrations.RunPython(set_my_defaults, reverse_set_default),