【问题标题】:How to filter queryset against time in django with custom timezone?如何使用自定义时区在 django 中根据时间过滤查询集?
【发布时间】:2019-09-18 23:14:32
【问题描述】:

我知道这个问题看起来很愚蠢,但由于某种原因,当我将 TIME_ZONE = 'UTC' 更改为 'TIME_ZONE = 'Asia/Kolkata'' 时,我无法理解为什么我的 django 应用程序没有返回正确的过滤结果。其他一切都很好,但是当我将时区更改为本地时区时,它不会给出任何错误,但views.py中的函数也会给出0匹配结果。

这个问题也和this question有关。

这是我在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

【问题讨论】:

  • 哪个查询集给出 0 个结果?你说有一个将数据导入模型的函数,但在你展示的代码中看不到。
  • latest_item 是什么?如果没有在任何地方定义,这段代码如何工作?
  • @dirkgroten 已更新。除非我在 settings.py 中将时区更改为“UTC”,否则代码 ItemBatch.objects.filter(time__date=latest_item.time.date(), time__hour=latest_item.time.hour, time__minute=latest_item.time.minute) 返回一个空查询集
  • 你在使用 Django 2.2 和 postgreSQL 吗?
  • Django 2.0.1 和 postgresql 9

标签: python django timezone utc


【解决方案1】:

问题是__date__hour__minute 正在使用当前时区(无论您定义为settings.TIME_ZONE)。而使用latest 从数据库中检索到的python datetime 对象始终是UTC。

了解时区时要记住的一点是:Django 传递的所有 datetime 对象都使用 UTC。时区通常仅在模板中显示这些日期时间(呈现给用户)或从表单接收输入值(来自用户的输入)时使用。

这里的例外是 TruncExtract 数据库函数,__date__hour__minute 是它们的快捷方式。他们使用settings.TIME_ZONE,除非您将tzinfo 明确设置为NoneUTC

因此,您需要在相同的时区上下文中进行两个查询。最简单的方法是在数据库级别完成所有操作:

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', 'minute', output_field=DateTimeField()))\.filter(truncated_time=Subquery(latest.values('truncated_time')[:1]))
  • \ 是您可以在 python 中的表达式中换行的方式。如果你想在一行上写表达式当然删除 \
猜你喜欢
  • 2022-07-19
  • 2011-08-06
  • 2010-10-14
  • 2016-06-12
  • 2016-09-11
  • 2021-07-02
  • 2020-12-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多