django与数据库交互关于当前时间的坑

背景

在线上服务中使用时间进行数据库操作时发现异常,而在本地环境无法成功复现此问题,导致难以进行故障排查。

核心问题

view.py

class XxxViewSet(viewsets.ModelViewSet):queryset = Xxx.objects.with_status().order_by("status", "-start_time")

managers.py

def with_status(self):"""添加status排序字段"""cur_time = datetime.now(pytz.utc)queryset = self.annotate(status=Case(When(end_time__lt=cur_time, then=Value(2)),When(start_time__gt=cur_time, then=Value(1)),default=Value(0),output_field=IntegerField(),))return queryset

问题的关键点

由于viewsets.ModelViewSet中使用了queryset属性,程序不会在每次请求时都重新计算当前时间,而是使用缓存的查询集。这意味着时间过滤条件并不会随着时间实时更新,而是固定在视图集类被加载时的时间。

分析本地无法复现原因

本地开发经常使用热部署,即服务频繁重启,这导致定义的cur_time变量不断被重置。而线上环境服务不会如此频繁重启,因而很难注意到这个问题。建议在本地创建一条时间精确到秒的记录,以此来模拟线上环境并复现问题。

问题的根源

Django中与数据库交互时,应使用Django数据库函数中的当前时间而非Python标准库中的时间:

使用Django的Now函数:

from django.db.models.functions import Now

而不是使用python 的时间

from datetime import datetime

否则会把时间设置为定值

从sql的角度理解就是
在这里插入图片描述

最终方案

修改使用数据库时间
managers.py

from django.db.models.functions import Now
def with_status(self):"""添加status排序字段"""cur_time = Now()queryset = self.annotate(status=Case(When(end_time__lt=cur_time, then=Value(2)),When(start_time__gt=cur_time, then=Value(1)),default=Value(0),output_field=IntegerField(),))return queryset

结论与建议

使用Django django.db.models.functions.Now()函数替代Python datetime.datetime.now()在Django应用程序的时间处理中具有几个优点与潜在的缺点:

优点:

1.在Django数据库交互时,如果需要获取当前时间,应优先考虑使用django.db.models.functions.Now(),而不是datetime.datetime.now(),特别是当涉及到使用类属性queryset的情况。这样可以确保每次请求都能反映真实的当前时间,避免由于查询集缓存所导致的时间判断错误。确保时间数据的一致性与准确性。
2. 数据库兼容性Now()函数自动适应不同数据库系统的时间函数,降低了数据库之间兼容性问题的风险。
3. 性能:如果数据库后端支持,使用Now()可能会比从应用层传递时间戳到数据库更优化,因为时间运算直接在数据库层完成。
4. 时区一致性Now()函数遵守Django的时区设置,自动处理时区转换,减少了手动处理时区问题的复杂度。

缺点:

  1. 依赖数据库时钟:使用Now()函数意味着依赖数据库服务器的时钟。如果数据库服务器的时间配置不正确,可能会导致问题。
  2. 数据库执行时间:由于Now()函数在数据库执行查询时生成时间,如果一个请求涉及多个查询,而查询之间有延迟,这可能会导致时间上的微小不一致。
  3. 测试复杂性:使用Now()可能会使单元测试更复杂,因为在测试环境中控制或模拟数据库返回的Now()值通常比使用固定的datetime值更困难。

总结

  1. Django数据库交互时,如果需要获取当前时间,应优先考虑使用django.db.models.functions.Now(),而不是datetime.datetime.now(),特别是当涉及到使用类属性queryset的情况。这样可以确保每次请求都能反映真实的当前时间,避免由于查询集缓存所导致的时间判断错误。确保时间数据的一致性与准确性。
  2. 若使用queryset应该避免存在动态计算的情况,比如上述例子的status字段计算,queryset = Announcement.objects.all()程序不会在每次请求时都重新计算当前时间,而是使用缓存的查询集。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/266222.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Jeecg Boot 3 - 第二天】1.1、后端 docker-compose 部署 JEECGBOOT3

一、场景 二、实战 ▶ 2.1 修改配置文件 > 目的一:将 dev 变更为生产环境 prod > 目的二:方便spring项目调用docker同个network下的redis和mysql ▶ 2.2 编写dockerfile ▶ 2.3 编写docker-compose.yaml ▶ 2.4 打…

参数占位符#{}和${}

#是预处理而$是直接替换 Mybatis在处理#{}时,会将SQL中的#{}替换成占位符?,再使用preparedStatement的set方法来赋值。而Mybatis在处理 时,是将 {}时,是将 时,是将{}直接替换成变量的值 我们分别使用#{}和…

外包干了2年,技术退步明显...

📢专注于分享软件测试干货内容,欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!📢交流讨论:欢迎加入我们一起学习!📢资源分享:耗时200小时精选的「软件测试」资…

[MySQL]SQL优化之索引的使用规则

🌈键盘敲烂,年薪30万🌈 目录 一、索引失效 📕最左前缀法则 📕范围查询> 📕索引列运算,索引失效 📕前模糊匹配 📕or连接的条件 📕字符串类型不加 …

【Spring】@SpringBootApplication注解解析

前言: 当我们第一次创建一个springboot工程时,我们会对启动类(xxxApplication)有许多困惑,为什么只要运行启动类我们在项目中自定义的bean无需配置类配置,扫描就能自动注入到IOC容器中?为什么我…

数据结构与算法-Rust 版读书笔记-2线性数据结构-双端队列

数据结构与算法-Rust 版读书笔记-2线性数据结构-双端队列 1、双端队列 deque又称为双端队列,双端队列是与队列类似的项的有序集合。deque有两个端部:首端和尾端。deque不同于队列的地方就在于项的添加和删除是不受限制的,既可以从首尾两端添…

基于JavaWeb+SpringBoot+Vue在线拍卖系统的设计和实现

基于JavaWebSpringBootVue在线拍卖系统系统的设计和实现 源码获取入口Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 源码获取入口 Lun文目录 摘 要 1 Abstract 1 1 系统概述 4 1.1 概述 4 1.2课题意义 4 1.3 主要内容 4 2 …

二叉树题目:在受污染的二叉树中查找元素

文章目录 题目标题和出处难度题目描述要求示例数据范围 前言解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 题目 标题和出处 标题:在受污染的二叉树中查找元素 出处:1261. 在受污染的二叉树中查找元素 难度 5 级 题目描述 要求…

12.11

1.q&#xff0c;w&#xff0c;e亮led1&#xff0c;2&#xff0c;3&#xff1b; a&#xff0c;s&#xff0c;d灭led1&#xff0c;2&#xff0c;3&#xff1b; main.c #include "uar1.h"#include "led.h"void delay(int ms){int i,j;for(i0;i<ms;i){for…

WampServer本地部署结合内网穿透实现公网访问本地服务

文章目录 前言1.WampServer下载安装2.WampServer启动3.安装cpolar内网穿透3.1 注册账号3.2 下载cpolar客户端3.3 登录cpolar web ui管理界面3.4 创建公网地址 4.固定公网地址访问 前言 Wamp 是一个 Windows系统下的 Apache PHP Mysql 集成安装环境&#xff0c;是一组常用来…

Altair Radioss碰撞 安全与冲击 衡祖仿真

Altair Radioss是解决瞬态加载工况下非线性问题的领先的结构分析求解器。其具备高扩展性、高品质、高鲁棒性&#xff0c;以及诸多功能&#xff1a;多域求解技术、高级材料功能(复合材料)等。Radioss求解器被广泛应用于汽车、航空航天、电子/家电、包装、轨道机车、生物医疗、能…

GoEasy使用手册

GoEasy官网 登录 - GoEasy 即时通讯聊天案例 GoEasy - GoEasy (gitee.com) 注意事项 接口使用人数上限为15&#xff0c;超出之后会请求超时返回408状态码&#xff0c;可以新建一个应用用来更换common Key 创建应用 ​ 添加应用名称&#xff0c;其余默认&#xff0c;点击…