如何在Django Machina论坛中显示用户本地时区的帖子时间?
实现Django-Machina论坛帖子时间按用户本地时区显示
核心问题分析
你当前的localtime过滤器无效,是因为Django默认使用settings.TIME_ZONE作为当前请求的时区,即使开启了USE_TZ=True,也不会自动切换到用户本地时区。要实现需求,需要获取并激活用户的时区,让localtime过滤器基于该时区渲染时间。
具体实现步骤
1. 存储用户时区偏好(针对登录用户)
如果论坛支持用户登录,在用户模型中添加时区字段,让用户自行设置偏好:
# 你的app/models.py from django.db import models from django.contrib.auth.models import AbstractUser from pytz import all_timezones class CustomUser(AbstractUser): # 提供所有时区选项供用户选择 timezone = models.CharField( max_length=100, choices=[(tz, tz) for tz in all_timezones], default='UTC' )
记得在settings.py中配置自定义用户模型:
AUTH_USER_MODEL = 'your_app.CustomUser'
2. 编写中间件激活用户时区
创建中间件,在每次请求时根据用户设置(或浏览器时区)激活对应时区:
# 你的app/middleware.py from django.utils import timezone import pytz class UserTimezoneMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): # 优先使用登录用户的时区设置 user_timezone = None if request.user.is_authenticated: user_timezone = request.user.timezone # 未登录用户尝试从Cookie读取浏览器时区 else: user_timezone = request.COOKIES.get('user_timezone') # 验证时区有效性并激活 if user_timezone and user_timezone in pytz.all_timezones: timezone.activate(user_timezone) else: timezone.deactivate() response = self.get_response(request) return response
将中间件添加到settings.py的MIDDLEWARE列表中,注意要放在AuthenticationMiddleware之后:
MIDDLEWARE = [ # ... 其他中间件 'django.contrib.auth.middleware.AuthenticationMiddleware', 'your_app.middleware.UserTimezoneMiddleware', # ... ]
3. 自动获取未登录用户的浏览器时区
通过JS获取浏览器时区并存入Cookie,让未登录用户也能看到本地时间:
<!-- 在论坛基础模板(如base.html)中添加 --> <script> document.addEventListener('DOMContentLoaded', () => { if (!document.cookie.includes('user_timezone')) { // 获取浏览器默认时区 const browserTz = Intl.DateTimeFormat().resolvedOptions().timeZone; // 存入Cookie,有效期1年 document.cookie = `user_timezone=${browserTz}; path=/; max-age=31536000`; // 刷新页面使时区生效 window.location.reload(); } }); </script>
4. 修改Django-Machina模板中的时间渲染
找到Django-Machina对应显示时间的模板文件(比如machina/forum_conversation/templates/forum_conversation/posts_list.html中渲染帖子时间的部分),确保时间字段使用localtime过滤器:
<small>{{ post.created|localtime }}</small>
如果需要自定义时间格式,可以搭配date过滤器:
<small>{{ post.created|localtime|date:"Y-m-d H:i:s" }}</small>
验证效果
在模板中再次使用测试代码:
{% get_current_timezone as TIME_ZONE %} 当前时区:{{ TIME_ZONE }}
此时应该显示用户设置的时区(或浏览器时区),localtime过滤器也会基于该时区渲染时间。
内容的提问来源于stack exchange,提问作者Finn
相关产品推荐
相关产品推荐

