Django中如何基于日期从DateTime字段的表中获取数据
Django按纯日期筛选DateTime类型字段数据解决方案
问题描述
表单提交纯日期数据(如from_date="2022-11-09"、to_date="2022-11-09"),但数据库表中created_at和updated_at字段为DateTime类型(包含日期与时间),需要在不修改表结构的前提下,实现按提交日期筛选对应数据。
用户原代码
views.py
from django.shortcuts import render import pymysql from django.http import HttpResponseRedirect from facligo_app.models import Scrapper from django.utils import timezone import datetime import pytz find_description = "" def index(request): if request.method == "POST": from_date = request.POST.get("from_date") print(from_date) to_date = request.POST.get("to_date") print(to_date) roles = Scrapper.objects.all() # for i in roles: # print(i.description) global find_description find_description = Scrapper.objects.all().filter(created_at=from_date,updated_at=to_date) print(find_description) return render(request, "home.html", {"scrappers": find_description})
models.py
from django.db import models from django.db import connections # Create your models here. class Scrapper(models.Model): id = models.IntegerField(primary_key=True) full_name = models.CharField(max_length=100) slug = models.CharField(max_length=100) description = models.TextField(max_length=100) created_at = models.DateTimeField(default=True) updated_at = models.DateTimeField(default=True) class Meta: db_table = "test_table_1"
解决方案
直接用字符串日期匹配DateTime字段会失败,因为DateTime字段包含时间部分。可以通过以下两种方式实现筛选:
方法1:使用__date查询条件
Django ORM支持对DateTime字段使用__date后缀,直接匹配日期部分,无需转换日期格式:
find_description = Scrapper.objects.filter( created_at__date=from_date, updated_at__date=to_date )
方法2:转换日期为DateTime范围(处理时区场景)
如果项目启用了时区(USE_TZ = True),建议将提交的日期转换为当日的起始和结束DateTime,避免时区偏差:
# 将字符串日期转为date对象 from_date_obj = datetime.datetime.strptime(from_date, "%Y-%m-%d").date() to_date_obj = datetime.datetime.strptime(to_date, "%Y-%m-%d").date() # 构造当日的起始和结束时间(带时区) start_datetime = timezone.make_aware(datetime.datetime.combine(from_date_obj, datetime.time.min)) end_datetime = timezone.make_aware(datetime.datetime.combine(to_date_obj, datetime.time.max)) # 筛选created_at在当日范围内,且updated_at在当日范围内的数据 find_description = Scrapper.objects.filter( created_at__range=(start_datetime, end_datetime), updated_at__range=(start_datetime, end_datetime) )
修改后的完整views.py
from django.shortcuts import render from django.http import HttpResponseRedirect from facligo_app.models import Scrapper from django.utils import timezone import datetime # 移除全局变量,改用局部变量避免并发污染 def index(request): scrappers = Scrapper.objects.all() # 默认显示全部数据 if request.method == "POST": from_date = request.POST.get("from_date") to_date = request.POST.get("to_date") if from_date and to_date: # 选用简洁的__date查询方式 scrappers = Scrapper.objects.filter( created_at__date=from_date, updated_at__date=to_date ) return render(request, "home.html", {"scrappers": scrappers})
注意事项
- 若使用
__date查询,需确保数据库支持该操作(MySQL、PostgreSQL等主流数据库均支持); - 启用时区时优先使用方法2,避免时区转换导致的日期匹配错误;
- 原代码中的全局变量容易引发并发请求数据污染,改用局部变量更符合Django视图最佳实践。
内容的提问来源于stack exchange,提问作者Ajay
相关产品推荐
相关产品推荐

