如何使用自定义时区在 Django 中根据时间过滤查询集?
How to filter queryset against time in django with custom timezone?
我知道这个问题看起来很愚蠢,但出于某种原因我无法理解为什么当我将 TIME_ZONE = 'UTC'
更改为 'TIME_ZONE = 'Asia/Kolkata''。其他一切都工作正常,但是当我将时区更改为本地时区时,它没有给出任何错误,但是 views.py 中的函数也给出了 0 个匹配结果。
这个问题也与有关。
这是我在 views.py 导入 Itembatch 模型中的数据的功能:
@login_required
def upload_batch(request):
template_name = 'classroom/teachers/upload.html'
prompt = {'order':'Order of csv should be first_name, last_name, email, ip_address, message'}
if request.method == "GET":
return render(request,template_name,prompt)
csv_file = request.FILES['file']
data_set = csv_file.read().decode('UTF-8')
io_string = io.StringIO(data_set)
next(io_string)
uploaded_by = request.user
for column in csv.reader(io_string,delimiter=',',quotechar='|'):
_, created = ItemBatch.objects.update_or_create(
name = column[0],
pid = column[1],
quantity = column[2],
length = column[3],
width = column[4],
height = column[5],
volume = column[6],
weight = column[7],
truck_type = column[8],
origin = column[9],
destination = column[10],
uploaded_by = uploaded_by
)
context = {}
return render(request,template_name,context)
这是我在 views.py 中渲染对象的函数:
@method_decorator([login_required, teacher_required], name='dispatch')
class UploadedItems(ListView):
model = ItemBatch
ordering = ('name',)
context_object_name = 'quizzes'
template_name = 'classroom/teachers/item_list.html'
def get_queryset (self):
latest_item = ItemBatch.objects.latest('time')
return ItemBatch.objects.filter(time__date=latest_item.time.date(),
time__hour=latest_item.time.hour, time__minute=latest_item.time.minute)
这是模型:
# item upload
class ItemBatch(models.Model):
# uploaded_by = models.ForeignKey(Teacher, on_delete=models.CASCADE, related_name='uploaded_by')
ttypes =(('Open','Open'),('Container','Container'),('Trailer','Trailer'),('All','All'))
uploaded_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='uploaded_by')
name = models.CharField(max_length=30)
pid = models.CharField(max_length=30)
quantity = models.CharField(max_length=30)
length = models.CharField(max_length=100, blank=True)
width = models.CharField(max_length=100, blank=True)
height = models.CharField(max_length=100, blank=True)
volume = models.CharField(max_length=100, blank=True)
weight = models.CharField(max_length=100, blank=True)
truck_type = models.CharField(max_length=255,default=0, choices=ttypes)
origin = models.CharField(max_length=100, blank=True)
destination = models.CharField(max_length=100, blank=True)
time = models.DateTimeField(max_length=100, blank=True,default=now)
def __str__ (self):
return self.name
这是我的模型数据库:
我试过的
一位 SO 用户建议我尝试这样的方法,但它也没有用。
latest_item = ItemBatch.objects.latest('time')
from django.conf import settings
settings.USE_TZ = False
latest_items = ItemBatch.objects.filter(time__date=latest_item.time.date(), time__hour=latest_item.time.hour, time__minute=latest_item.time.minute)
settings.USE_TZ = True
问题是 __date
、__hour
和 __minute
正在使用当前时区(无论您定义为 settings.TIME_ZONE
)。而使用 latest
从数据库中检索到的 python datetime
对象始终采用 UTC。
注意时区时要记住的是:Django 传递的所有 datetime
对象都采用 UTC。时区通常仅在模板中显示这些日期时间(呈现给用户)或从表单接收输入值(来自用户的输入)时使用。
这里的例外是 Trunc
和 Extract
数据库函数,__date
、__hour
和 __minute
是它们的快捷方式。它们使用 settings.TIME_ZONE
,除非您将 tzinfo
明确设置为 None
或 UTC
。
所以你需要在相同的时区上下文中进行这两个查询。最简单的是在数据库级别完成整个事情:
from django.db.models.functions import Trunc
from django.db.models import DateTimeField, Subquery
latest = ItemBatch.objects.order_by('-time').annotate(truncated_time=Trunc(
'time', 'minute', output_field=DateTimeField())
qs = ItemBatch.objects.annotate(truncated_time=Trunc(
'time', 'minute', output_field=DateTimeField()))\
.filter(truncated_time=Subquery(latest.values('truncated_time')[:1]))
注意:确保您的查询集不包含字段为 NULL
的任何行(在您的情况下不可能,因为 time
不能是 NULL
),这将在其上调用 Trunc
时引发异常。
我知道这个问题看起来很愚蠢,但出于某种原因我无法理解为什么当我将 TIME_ZONE = 'UTC'
更改为 'TIME_ZONE = 'Asia/Kolkata''。其他一切都工作正常,但是当我将时区更改为本地时区时,它没有给出任何错误,但是 views.py 中的函数也给出了 0 个匹配结果。
这个问题也与
这是我在 views.py 导入 Itembatch 模型中的数据的功能:
@login_required
def upload_batch(request):
template_name = 'classroom/teachers/upload.html'
prompt = {'order':'Order of csv should be first_name, last_name, email, ip_address, message'}
if request.method == "GET":
return render(request,template_name,prompt)
csv_file = request.FILES['file']
data_set = csv_file.read().decode('UTF-8')
io_string = io.StringIO(data_set)
next(io_string)
uploaded_by = request.user
for column in csv.reader(io_string,delimiter=',',quotechar='|'):
_, created = ItemBatch.objects.update_or_create(
name = column[0],
pid = column[1],
quantity = column[2],
length = column[3],
width = column[4],
height = column[5],
volume = column[6],
weight = column[7],
truck_type = column[8],
origin = column[9],
destination = column[10],
uploaded_by = uploaded_by
)
context = {}
return render(request,template_name,context)
这是我在 views.py 中渲染对象的函数:
@method_decorator([login_required, teacher_required], name='dispatch')
class UploadedItems(ListView):
model = ItemBatch
ordering = ('name',)
context_object_name = 'quizzes'
template_name = 'classroom/teachers/item_list.html'
def get_queryset (self):
latest_item = ItemBatch.objects.latest('time')
return ItemBatch.objects.filter(time__date=latest_item.time.date(),
time__hour=latest_item.time.hour, time__minute=latest_item.time.minute)
这是模型:
# item upload
class ItemBatch(models.Model):
# uploaded_by = models.ForeignKey(Teacher, on_delete=models.CASCADE, related_name='uploaded_by')
ttypes =(('Open','Open'),('Container','Container'),('Trailer','Trailer'),('All','All'))
uploaded_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='uploaded_by')
name = models.CharField(max_length=30)
pid = models.CharField(max_length=30)
quantity = models.CharField(max_length=30)
length = models.CharField(max_length=100, blank=True)
width = models.CharField(max_length=100, blank=True)
height = models.CharField(max_length=100, blank=True)
volume = models.CharField(max_length=100, blank=True)
weight = models.CharField(max_length=100, blank=True)
truck_type = models.CharField(max_length=255,default=0, choices=ttypes)
origin = models.CharField(max_length=100, blank=True)
destination = models.CharField(max_length=100, blank=True)
time = models.DateTimeField(max_length=100, blank=True,default=now)
def __str__ (self):
return self.name
这是我的模型数据库:
我试过的
一位 SO 用户建议我尝试这样的方法,但它也没有用。
latest_item = ItemBatch.objects.latest('time')
from django.conf import settings
settings.USE_TZ = False
latest_items = ItemBatch.objects.filter(time__date=latest_item.time.date(), time__hour=latest_item.time.hour, time__minute=latest_item.time.minute)
settings.USE_TZ = True
问题是 __date
、__hour
和 __minute
正在使用当前时区(无论您定义为 settings.TIME_ZONE
)。而使用 latest
从数据库中检索到的 python datetime
对象始终采用 UTC。
注意时区时要记住的是:Django 传递的所有 datetime
对象都采用 UTC。时区通常仅在模板中显示这些日期时间(呈现给用户)或从表单接收输入值(来自用户的输入)时使用。
这里的例外是 Trunc
和 Extract
数据库函数,__date
、__hour
和 __minute
是它们的快捷方式。它们使用 settings.TIME_ZONE
,除非您将 tzinfo
明确设置为 None
或 UTC
。
所以你需要在相同的时区上下文中进行这两个查询。最简单的是在数据库级别完成整个事情:
from django.db.models.functions import Trunc
from django.db.models import DateTimeField, Subquery
latest = ItemBatch.objects.order_by('-time').annotate(truncated_time=Trunc(
'time', 'minute', output_field=DateTimeField())
qs = ItemBatch.objects.annotate(truncated_time=Trunc(
'time', 'minute', output_field=DateTimeField()))\
.filter(truncated_time=Subquery(latest.values('truncated_time')[:1]))
注意:确保您的查询集不包含字段为 NULL
的任何行(在您的情况下不可能,因为 time
不能是 NULL
),这将在其上调用 Trunc
时引发异常。