Как лучше всего сделать так, чтобы переменная сессии "django-timezone" устанавливалась на основе предпочтений профиля пользователя при каждом входе в систему?
Фон
Я прочитал этот раздел в документации Django под названием "Выбор текущего часового пояса", и мне стало ясно, как пользователь может выбрать предпочтительный часовой пояс для своей сессии (а затем промежуточное ПО убедится, что он будет использоваться в течение всей сессии):
- разработчик готовит словарь часовых поясов для выбора пользователем
- разработчик делает этот список доступным для пользователя в форме внутри шаблона, которая обслуживается
GET
запросом к представлению под названиемset_timezone
- пользователь выбирает часовой пояс с помощью этой формы и делает
POST
запрос set_timezone
представление использует простой однострочник для установки переменной"django-timezone"
сессии:request.session["django_timezone"] = request.POST["timezone"]
- Наконец, пользовательский класс
TimezoneMiddleware
, о котором говорится в документации, активирует часовой пояс для всех запросов представления в сессии с этого момента .
Вопрос
Если я храню предпочтение часового пояса пользователя в модели User или модели профиля User, какой лучший способ сделать так, чтобы переменная "django-timezone"
сессии всегда была установлена для всех его сессий (каждый раз, когда он входит в систему)?
Мысли/догадки
- Нужно ли мне модифицировать встроенный в Django класс промежуточного ПО аутентификации?
- Лучше всего будет расширить стандартный класс Django-стандарта
LoginView
изdjango.contrib.auth.views
? - Или вышеупомянутый класс
LoginView
уже сам справится с этим, если я правильно настрою поле для хранения часового пояса в модели User? (или что-то вроде этого?)
Расширение LoginView
Как предложил Кевин Кристофер Генри в комментариях, я расширил встроенное представление входа в систему (решил поместить логику в метод form_valid()
) после реализации того, что было предложено в документации Django под названием "Выбор текущего часового пояса". Я также покажу соответствующие части моей пользовательской модели, чтобы было понятно, как я храню предпочтения пользователей в отношении часовых поясов.
models.py
from django.contrib.auth.base_user import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.validators import ASCIIUsernameValidator
# third-party package
from timezone_field import TimeZoneField
TZ_CHOICES = [
(ZoneInfo('Pacific/Honolulu'), 'Pacific/Honolulu'),
(ZoneInfo('America/Anchorage'), 'America/Anchorage'),
(ZoneInfo('America/Los_Angeles'), 'America/Los_Angeles'),
(ZoneInfo('US/Arizona'), 'US/Arizona'),
(ZoneInfo('America/Denver'), 'America/Denver'),
(ZoneInfo('America/Chicago'), 'America/Chicago'),
(ZoneInfo('America/New_York'), 'America/New_York'),
]
class CustomUser(AbstractBaseUser, PermissionsMixin):
username_validator = ASCIIUsernameValidator()
"""A bunch of fields (username, email, etc.)"""
tz_preference = TimeZoneField(
use_pytz=False, default="America/Denver", choices=TZ_CHOICES, choices_display="STANDARD", verbose_name=_('Timezone Preference')
)
views.py
from django.contrib.auth.views import LoginView
from django.contrib.auth import login as auth_login
import zoneinfo
from django.utils import timezone
class CustomLoginView(LoginView):
def form_valid(self, form):
"""Security check complete. Log the user in."""
auth_login(self.request, form.get_user())
# now set session timezone according to user's preference
tzname = self.request.user.tz_preference.key
self.request.session["django_timezone"] = tzname
# and activate it (after this view, middleware will activate it)
timezone.activate(zoneinfo.ZoneInfo(tzname))
return HttpResponseRedirect(self.get_success_url())