Django's DateField and DateTimeField fields have two options that can be set to automatically set the field to the current date and time when a new record is created or updated:
auto_now: Automatically sets the field to the current date and time every time the record is saved.auto_now_add: Automatically sets the field to the current date and time when the record is first created.
A common use case for these options is setting created_at and updated_at fields in a model:
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
However, if you want to migrate some data you might stumble into a problem.
from django.db import migrations, models
def create_old_article(apps, schema_editor):
Article = apps.get_model('blog', 'Article')
old_article = {
'title': 'My old article',
'created_at': '2020-01-01 12:00:00',
'updated_at': '2024-01-01 12:00:00',
}
Article.objects.create(**old_article)
class Migration(migrations.Migration):
dependencies = [
('blog', '0001_initial'),
]
operations = [
migrations.RunPython(create_old_article),
]
Running this migration would set created_at and updated_at to the current date and time, not the specified historical dates.
To preserve the historical dates during migration, you can temporarily disable the auto_now and auto_now_add behavior:
...
def create_old_article(apps, schema_editor):
Article = apps.get_model('blog', 'Article')
old_article = {
'title': 'My old article',
'created_at': '2020-01-01 12:00:00',
'updated_at': '2024-01-01 12:00:00',
}
# Disable the auto_now and auto_now_add behavior
Article._meta.get_field('created_at').auto_now_add = False
Article._meta.get_field('updated_at').auto_now = False
Article.objects.create(**old_article)
# Re-enable the `auto_now` and `auto_now_add` behavior
# in case there are other operations within the migration
Article._meta.get_field('created_at').auto_now_add = True
Article._meta.get_field('updated_at').auto_now = True
...
This approach disables the automated logic for the duration of the migration, allowing the fields to be set to the specified values.
Enjoyed this? Please consider supporting my work.