Django类视图预处理模板数据:批量转换广告时间戳为相对时间
问题根因
原有代码存在几个核心问题,导致无法批量处理:
- 全局context仅存储单个
time_ago变量,循环赋值时会被持续覆盖,最终只会保留最后一条广告的计算结果 - 在
get_context_data中单独查询models.Catalogue.objects.all(),绕过了ListView自带的分页逻辑,导致分页功能完全失效 - 冗余的时间格式转换步骤(先转字符串再转回datetime对象)完全没必要
- 未处理
source_id != 3的场景,会导致这部分广告的时间变量未定义报错
调整方案
方案一:视图层给每条广告绑定时间属性
1. 修改 views.py
不再单独查询全量数据,直接基于ListView已经处理好的分页广告列表,给每个对象动态添加time_ago属性:
import datetime import timeago from django.views import generic from . import models class crawler(generic.ListView): paginate_by = 12 model = models.Catalogue template_name = 'index.html' def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # 获取当前分页后的广告列表,复用ListView的分页逻辑 catalogue_list = context['catalogue_list'] now = datetime.datetime.now() for cat in catalogue_list: # 非source_id=3的广告做兜底处理,避免报错 if cat.source_id != 3: cat.time_ago = '' # 可替换为其他需要的展示内容,比如原始时间 continue # 直接转换时间戳为datetime对象,省略冗余的字符串转换步骤 date = float(cat.datetime) d_datetime = datetime.datetime.fromtimestamp(date / 1000.0) cat.time_ago = timeago.format(d_datetime, now, 'fa_IR') return context
2. 修改模板 index.html
直接调用每条广告自身的time_ago属性,不再使用全局变量:
{% for Catalogue in catalogue_list %} <h4 class="card-title mt-3" dir="rtl" style="text-align:right;">{{ Catalogue.title }}</h4> <br>{{ Catalogue.source }} <div class="card-footer" dir="rtl" style="text-align:right"> <small id="datetime">{{ Catalogue.time_ago }}</small> </div> {% empty %} <p>There are no ads in database.</p> {% endfor %}
可选优化:将时间逻辑封装到模型中
如果后续多个场景都要用到这个相对时间,直接把计算逻辑封装到Catalogue模型的方法里,视图甚至不需要重写get_context_data,复用性更强:
1. 修改 models.py
在Catalogue模型中新增自定义方法:
import datetime import timeago from django.db import models class Catalogue(models.Model): # 原有字段定义保持不变 datetime = models.CharField() # 假设你的时间戳字段是字符串类型 source_id = models.IntegerField() def get_time_ago(self): if self.source_id != 3: return '' # 兜底逻辑 date = float(self.datetime) d_datetime = datetime.datetime.fromtimestamp(date / 1000.0) now = datetime.datetime.now() return timeago.format(d_datetime, now, 'fa_IR')
2. 模板直接调用方法
不需要改动任何视图代码,模板里直接用即可:
<small id="datetime">{{ Catalogue.get_time_ago }}</small>
内容的提问来源于stack exchange,提问作者omid jahadi
相关产品推荐
相关产品推荐

