在Django2的前台页面里比较日期先后

正文

背景交代:由Django2.1 + Python 3.8 + AdminLTE3 构建的一个“风险大盘”首页,页面最后效果如下:
akb48

现在有一个需求,就是比较当前日期和“预计完结日期”,如果“超过了预计完结日期,风险还没完成”就是红色,反之就绿色。

在python里比较日期如果在同一个时区是很简单的,直接大于小于就可以实现。在Django里比较日期也差不多用这个方式,而template里默认的内置的模板标签语言表示今天的方法是now "Y-m-d",但是这个不能用于比较里,会报错Could not parse the remainder: '%' from '%'

用一个比较简单的方法,就是在views.pyimport datetime,然后传入context['today'] = date.today()通过render_to_response到前端页面,或者直接return render_to_response('template.html', {'today': date.today()}),然后:

1
2
3
4
<td style="color:{% if risk.risk_time|date:"Y-m-d" <= today|date:"Y-m-d" and risk.risk_stat == '未达标' %} red {% else %} green {% endif %}">
<!-- 这里的today是后台views.py里传进来的今天的日期 -->
{{ risk.risk_time|date:"Y-m-d" }}
</td>

还有一个比较骚的方法,将类似in_the_past(布尔值)的内容传递给extra_context,或者最好将其作为属性添加到模型中:

1
2
3
4
5
from datetime import date

@property
def is_past_due(self):
return date.today() > self.date

然后在前端页面:

1
2
3
4
5
{% if listing.is_past_due %}
In the past
{% else %}
{{ listing.date|date:"d M Y" }}
{% endif %}

不过我个人还是觉得第一个比较好,简单粗暴。

render_to_response多个参数问题

Django2的render_to_response是可以带多个参数的,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 编辑风险事件
def update_stresstest(request):
context = dict()
context["activities"] = Promotion.objects.all().order_by('-id') # 从Promotion数据库里获取所有
error = '' # 错误提示
risk_pk = request.GET.get('id')
risk_lists = Risk.objects.filter(pk=risk_pk)
obj = risk_lists[0] # 获取到具体对应的那个任务
if request.method == 'POST':
obj.risk_name = request.POST.get("risk_name", None) # 风险名称
obj.risk_level = request.POST.get("risk_level", None) # 风险级别
if all([obj.risk_name, obj.risk_pm, obj.risk_domain, obj.risk_level, obj.risk_detail]): # 判断获取到的值同时不为空
obj.save() # 保存到数据库里
return redirect('/naxx/risk') # 使用redirect如果后面直接加.html就是在原有路径上加,所以这直接写路径,注意后面没有/
else:
error = "有必写数据为空,请重新检查"
return render_to_response('edit_risk.html', {'obj': obj, 'error': error, 'context':context})

这里就用了字典的形式给render_to_response返回了多个参数,但是此时在前端页面直接调用是没问题的,但是要直接调用就是空白,要在templates里这么用:

1
2
3
4
5
6
7
8
9
10
<label class="form-inline">*所属活动:
<div class="col-sm-7">
<select data-placeholder="选择大促项目..." class="form-control" name="promotion_name" id="promotion_name" required="required">
<option value="">请选择...</option>
{% for activity in context.activities %}
<option>{{ activity.promotionname }}</option>
{% endfor %}
</select>
</div>
</label>

这个就是一个下拉页,可以查询到历次的大促事件。可见这里要用context.activities,而不能直接像obj直接用,因为传入的是context,而如果是只传入一个context是不用写成context.activities的,直接写activities就行。

补充一句,context_instance=RequestContext(request)方法我是不好使了,可以直接不用考虑了。

AdminLTE3下拉菜单无法点击问题

AdminLTE3里的给下拉菜单的demo是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div class="btn-group">
<button type="button" class="btn btn-default">Action</button>
<button type="button" class="btn btn-default dropdown-toggle dropdown-hover dropdown-icon" data-toggle="dropdown">
<span class="sr-only">Toggle Dropdown</span>
<div class="dropdown-menu" role="menu">
<a class="dropdown-item" href="#">第一个链接</a>
<a class="dropdown-item" href="#">第二个链接</a>
<a class="dropdown-item" href="#">第三个链接</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">特殊的链接</a>
</div>
</div>
</button>
</div>

效果如图:
akb48

但是这个是不好使的,点击了链接href并不会生效,而右键“在新的标签页打开”是可以的。于是我改成这样:

1
2
3
4
5
6
7
8
9
<div class="btn-group">
<a class="dropdown-toggle btn btn-warning" data-toggle="dropdown" href="#">
操作... <span class="caret"></span>
</a>
<ul class="dropdown-menu" role="menu">
<li><a class="dropdown-item" href="/naxx/edit_risk/?id={{ risk.id }}">编辑</a></li>
<li><a class="dropdown-item" href="/naxx/del_risk/?id={{ risk.id }}">删除</a></li>
</ul>
</div>

这样直接点击就OK了。

补充一下,如果使用Django的ORM实现,以某列为准,某行出现的次序排序的语句是:

1
Risk.objects.filter(risk_stat='未达标').values('risk_domain').annotate(total=Count('risk_domain')).order_by('-total')[0:3]

这句话的意思是:在Risk数据表里,以risk_stat='未达标'为准找出risk_domain出现的从高到低最多的列,同时只截取了前三名。

akb48

感谢您请我喝咖啡~O(∩_∩)O,如果要联系请直接发我邮箱chenx1242@163.com,我会回复你的
-------------本文结束感谢您的阅读-------------