ImportError in old migrations (django.utils.timezone.utc) after upgrading Python and Django
I recently upgraded my project from Django 3.2 to Django 5.2 and also updated Python to 3.13.
During this process, I noticed that some of my old migration files do not explicitly import timezone from django.utils.
import datetime
from django.conf import settings
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
from django.utils.timezone import utc
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('app', '0002_auto_20200712_1404'),
]
After the upgrade, I encountered an error when running:
python manage.py makemigrations
Error:
ImportError: cannot import name 'utc' from 'django.utils.timezone'
Problematic migration file:
An old migration contains:
from django.utils.timezone import utc
These migrations are already applied in production
I understand that:
Django 5 removed
django.utils.timezone.utcIt should be replaced with
datetime.timezone.utc
What I tried
Option 1: Monkey patch (works, but feels hacky)
from datetime import timezone
import django.utils.timezone as django_timezone
if not hasattr(django_timezone, "utc"):
django_timezone.utc = timezone.utc
I added this to manage.py and wsgi.py, and it works.
However, I'm not sure if this is safe for production.
Option 2: Modify migration
from datetime import timezone
utc = timezone.utc
This also works, but I'm concerned about modifying migrations that are already applied in production.
My questions
Is it safe to modify old migration files just to fix imports like this?
Or is there a recommended approach to avoid modifying migrations?
- (e.g. monkey patching
django.utils.timezone.utc)
- (e.g. monkey patching
it is safe to modify an old migration if you are only fixing the import, not changing the migration logic.
the clean fix is to update the migration from:
from django.utils.timezone import utc
to:
import datetime
utc = datetime.timezone.utc
This is usually safe as it doesn't alter the migration's work or the state of the database it only changes a path of an import that has been removed.
I would avoid monkey-patching django.utils.timezone.utc in manage.py / wsgi.py except as a temporary workaround, because it hides the actual compatibility issue and makes the project depend on runtime patching.