简体   繁体   English

如何使用自定义时区在Django中针对时间过滤查询集?

[英]How to filter queryset against time in django with custom timezone?

I know the question seems stupid, but for some reason I am not able to understand why my django app does not return the correct filtering results when I change my TIME_ZONE = 'UTC' to 'TIME_ZONE = 'Asia/Kolkata''. 我知道这个问题看起来很愚蠢,但是由于某种原因,当我将TIME_ZONE = 'UTC'更改为'TIME_ZONE ='Asia / Kolkata'时,为什么我的django应用程序无法返回正确的过滤结果。 Everything else is working just fine, but when I change the timezone to my local timezone, it does not give any error, but the function in views.py also gives 0 matching results. 其他所有工作都很好,但是当我将时区更改为本地时区时,它没有给出任何错误,但是views.py中的函数也给出了0个匹配结果。

This question is also related to this question . 这个问题也与此问题有关

This is my function in views.py importing the data in the Itembatch model: 这是我在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)

This is my function in views.py to render the objects : 这是我在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) 

And this is the model: 这是模型:

# 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

This is my models database: 这是我的模型数据库:

1个

What I tried 我尝试了什么

A fellow SO user suggested I should try something like this, but it did not work either. 一位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

The problem is that __date , __hour and __minute are using the current timezone (whatever you defined as settings.TIME_ZONE ). 问题是__date__hour__minute使用的是当前时区(无论您定义为settings.TIME_ZONE )。 Whereas the python datetime object retrieved from the database with latest is always in UTC. 而从数据库中获取的latest的python datetime对象始终是UTC。

The thing to remember when being timezone aware is: All datetime objects passed around by Django are in UTC. 时区感知时要记住的事情是:Django传递的所有datetime对象都位于UTC中。 The timezone is in general only used when displaying these datetimes in templates (rendering to the user) or receiving input values from forms (input from the user). 通常仅在在模板中显示这些日期时间(呈现给用户)或从表单接收输入值(来自用户的输入)时才使用时区。

The exception here are the Trunc and Extract database functions, for which __date , __hour and __minute are shortcuts. TruncExtract数据库函数是这里的例外, __date__hour__minute是其快捷方式。 They use the settings.TIME_ZONE unless you explicitly set tzinfo to None or UTC . 他们使用settings.TIME_ZONE除非您将tzinfo显式设置为NoneUTC

So you need to be in the same timezone context for both queries. 因此,两个查询都需要处于相同的时区上下文中。 The easiest is to do the whole thing at the database level: 最简单的方法是在数据库级别完成整个操作:

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]))

Note: Make sure your queryset doesn't include any rows where the field is NULL (not possible in your case, since time cannot be NULL ), that will raise an exception when calling Trunc on it. 注意:确保您的查询集不包含字段为NULL任何行(在您的情况下,这是不可能的,因为time不能为NULL ),这将在对其调用Trunc时引发异常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM