Changing timezone per user in Django Admin
Lets first have a background on storing and displaying timestamps:
- It is preferable to store timestamps in UTC in a database
- Not everyone understands UTC timestamps
- Users get to see the timestamps in their own timezone
Some things to keep in mind when converting timestamps from one timezone to another:
- Refrain from converting timezones during data transfer and computation
- Make sure to convert to UTC when storing timestamps in database
- Make sure to convert to user’s timezone when displaying
Starting from scratch, we create a new Django project:
django-admin startproject myproject
cd myproject
Then we install required packages in a virtual environment (install poetry):
poetry init -n poetry add django django-timezone-field
Then we create a Django app:
poetry run python manage.py startapp custom_user
We then modify custom_user/models.py
to add timezone
field in our custom User
model:
from django.db import models from django.contrib.auth.models import AbstractUser from timezone_field import TimeZoneField class User(AbstractUser): timezone = TimeZoneField(default="Asia/Kolkata")
Now we register the User
model in custom_user/admin.py
so that we can edit user
information like timezone
, username
, etc.
from django.contrib import admin from django.contrib.auth.admin import UserAdmin from custom_user.models import User @admin.register(User) class CustomUserAdmin(UserAdmin): model = User def get_fieldsets(self, request, obj=None): fieldsets = super().get_fieldsets(request, obj) fieldsets[0][1]["fields"] += ("timezone",) return fieldsets
What we did was registering timezone information per user. Now, we need to
intercept each request using Django’s middleware so that we can activate the
timezone specific to the user currently logged in. For this we need to add the
following in custom_user/middleware.py
:
from django.utils import timezone def set_timezone(get_response): def get_response_wrapper(request): if request.user.is_authenticated: timezone.activate(request.user.timezone) else: timezone.deactivate() return get_response(request) return get_response(request)
Next we register our app, middleware and user model in myproject/settings.py
:
INSTALLED_APPS += ['custom_user'] MIDDLEWARE += ['custom_user.middleware.set_timezone'] AUTH_USER_MODEL = "custom_user.User"
Now we just need to migrate our changes to database and run the server:
poetry run python manage.py makemigrations poetry run python manage.py migrate
poetry run python manage.py createsuperuser
poetry run python manage.py runserver