Skip to content

Commit

Permalink
Add per-user timezone setting
Browse files Browse the repository at this point in the history
The `0002` migration is to make it so it doesn't show as needing a
migration if Django's list of timezones ever changes.

https://dev.to/nessita/django-migrations-by-choice-32n7
  • Loading branch information
trey committed Jul 20, 2024
1 parent b74f85f commit cf1dc13
Show file tree
Hide file tree
Showing 10 changed files with 63 additions and 1 deletion.
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ repos:
rev: 23.3.0
hooks:
- id: black
exclude: ^core/migrations/
- repo: https://github.com/pycqa/flake8
rev: 6.0.0
hooks:
Expand Down
4 changes: 4 additions & 0 deletions config/settings.py-tpl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ from django.core.management.utils import get_random_secret_key
from pathlib import Path
from environs import Env
from warnings import filterwarnings
from pytz import common_timezones

env = Env()
# Read .env into os.environ
Expand Down Expand Up @@ -72,6 +73,7 @@ MIDDLEWARE = [
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"core.middleware.TimezoneMiddleware",
"debug_toolbar.middleware.DebugToolbarMiddleware",
"django_htmx.middleware.HtmxMiddleware",
"django_browser_reload.middleware.BrowserReloadMiddleware",
Expand Down Expand Up @@ -134,6 +136,8 @@ LANGUAGE_CODE = "en-us"

TIME_ZONE = "UTC"

TIME_ZONES = [(tz, tz) for tz in common_timezones]

USE_I18N = True

USE_TZ = True
Expand Down
2 changes: 1 addition & 1 deletion core/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class UserAdmin(DjangoUserAdmin):

fieldsets = (
(None, {"fields": ("email", "password")}),
(_("Personal info"), {"fields": ("first_name", "last_name")}),
(_("Personal info"), {"fields": ("first_name", "last_name", "timezone")}),
(
_("Permissions"),
{
Expand Down
24 changes: 24 additions & 0 deletions core/middleware.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import pytz
from django.utils import timezone
from django.conf import settings


class TimezoneMiddleware:
"""
Automatically set the timezone to what the user has chosen.
"""

def __init__(self, get_response):
self.get_response = get_response

def __call__(self, request):
if request.user.is_authenticated:
tzname = request.user.timezone
if tzname:
timezone.activate(pytz.timezone(tzname))
else:
timezone.activate(pytz.timezone(settings.TIME_ZONE))
else:
timezone.deactivate()

return self.get_response(request)
7 changes: 7 additions & 0 deletions core/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.contrib.auth.models import AbstractUser, BaseUserManager
from django.db import models
from django.utils.translation import gettext_lazy as _
from django.conf import settings


class UserManager(BaseUserManager):
Expand Down Expand Up @@ -42,6 +43,12 @@ class User(AbstractUser):

username = None
email = models.EmailField(_("email address"), unique=True)
timezone = models.CharField(
max_length=40,
blank=True,
choices=settings.TIME_ZONES,
default=settings.TIME_ZONE,
)
# Add more fields here.

objects = UserManager()
Expand Down
21 changes: 21 additions & 0 deletions dev/0002_adjust_timezone_migration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from django.db import migrations, models
from django.conf import settings


class Migration(migrations.Migration):
dependencies = [
("core", "0001_initial"),
]

operations = [
migrations.AlterField(
model_name="user",
name="timezone",
field=models.CharField(
blank=True,
choices=settings.TIME_ZONES,
default=settings.TIME_ZONE,
max_length=40,
),
),
]
1 change: 1 addition & 0 deletions dev/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ gum style --border normal --margin "1" --padding "0 2" --border-foreground 212 \
"Warming up $(gum style --foreground 212 'database') and $(gum style --foreground 212 'static files')"
gum spin --title "Collecting static files" -- python manage.py collectstatic
gum spin --title "Warming up the database" -- python manage.py makemigrations
gum spin --title "Warming up the database" -- mv dev/0002_adjust_timezone_migration.py core/migrations/0002_adjust_timezone_migration.py
gum spin --title "Warming up the database" -- python manage.py migrate
gum spin --title "Creating initial superuser account" -- python manage.py createsuperuser --noinput --email=$EMAIL

Expand Down
1 change: 1 addition & 0 deletions dev/test-build
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ case $yn in
.venv/bin/pip-compile --resolver=backtracking requirements/requirements.in
.venv/bin/python -m pip install -r requirements/requirements.txt
.venv/bin/python manage.py makemigrations
mv dev/0002_adjust_timezone_migration.py core/migrations/0002_adjust_timezone_migration.py
.venv/bin/python manage.py migrate --noinput
.venv/bin/python manage.py collectstatic --noinput
source $HOME/.nvm/nvm.sh
Expand Down
1 change: 1 addition & 0 deletions requirements/requirements.in
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ pip-lock
pip-tools
pre-commit
pytest-django
pytz
whitenoise
2 changes: 2 additions & 0 deletions requirements/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ pytest-django==4.8.0
# via -r requirements/requirements.in
python-dotenv==1.0.1
# via environs
pytz==2024.1
# via -r requirements/requirements.in
pyyaml==6.0.1
# via
# djlint
Expand Down

0 comments on commit cf1dc13

Please sign in to comment.