在 DateField 上使用 Q 过滤器 _lte 进行 Django 查询(USE_TZ=True)不起作用(MySql DB)

问题描述 投票:0回答:1

我得到了一个 Invoice 模型,其字段

created_at
models.DateTimeField(),其中包含一些包含多个日期的记录:

使用 HTML 表单,我想按日期过滤

<input name="start" class="form-control me-3" type="date" value="{{ min_date|date:'Y-n-d' }}" />

我的结束日期有相同的字段,当我在视图中打印它们时,它们似乎采用正确的格式

2023-11-12 -> 2023-11-17

在我看来,我检查这两个字段是否包含值,如果是,我过滤我的 Invoice 查询集:

我尝试了很多组合进行查询集过滤,每次,__lte子句似乎都无法正常工作,并且结果不包括我的end日期。应用

__lt
而不是
__lte
。在我尝试过的这些组合中:

    if request.method == 'GET':
        # limit records number if no filter
        invoices = Invoice.objects.all()[:100]
        
    else:
        start = request.POST.get('startDate')
        end = request.POST.get('endDate')
        invoices = Invoice.objects.all()
        if start:
            invoices = invoices.filter(created_at__gte=start)
        if end:
            invoices = invoices.filter(created_at__lt=end)

也尝试过:

[...]    
    else:
        start = request.POST.get('start')
        end = request.POST.get('end')
        if start and end:
            invoices = invoices.filter(
                Q(created_at__gte=start) & Q(created_at__lte=end))
        if end and not start:
            invoices = invoices.filter(Q(created_at__lte=end))
        if not end and start:
            invoices = invoices.filter(Q(created_at__gte=start)) 

首先,我认为这是由于关于

("DateTimeField %s received a naive datetime (%s)
的警告,即使有了
make_aware
,问题仍然存在。我尝试在每一行上重建基本查询集。

    else:
    start = request.POST.get('start')
    end = request.POST.get('end')
    tz_start = make_aware(datetime.strptime(start, '%Y-%m-%d'))
    tz_end = make_aware(datetime.strptime(end, '%Y-%m-%d'))
    if not start and end:
        invoices = Invoice.objects.filter(Q(created_at__lte=tz_end))
    elif start and end:
        invoices = Invoice.objects.filter(
            Q(created_at__gte=tz_start) & Q(created_at__lte=tz_end))
    elif start and not end:
        invoices = Invoice.objects.filter(
            Q(created_at__gte=tz_start))
    else:
        invoices = Invoice.objects.all()
        messages.error(request, 'no filter applied')

是不是我错过了这么大的事情,以至于我都看不到它?

django datetime django-queryset
1个回答
0
投票

这个问题与 MySql、时区或其他与环境无关的问题之间没有关系。

经过 3 天的努力寻找解决方案,此页面让我走上了正确的道路

我不知道我的问题是否是因为我试图将日期输入与模型的 DateTimeField 进行比较,或者这种异常是否特定于使用 django_filters 进行日期过滤,但最后,django_filters.DateFromToRangeFilter拯救了我的一天(我应该说,我的一周)。代码减少了 3 倍,我的观点现在可以工作了。

过滤器.py

import django_filters
from websales.models import Invoice


class InvoiceFilter(django_filters.FilterSet):
    created_at = django_filters.DateFromToRangeFilter(
        field_name='created_at',
    )

    class Meta:
        model = Invoice
        fields = ['created_at']

views.py

def invoices_with_filter(request):
    invoice_filter = InvoiceFilter(request.GET, queryset=Invoice.objects.all())
    context = {}

    max_min = invoice_filter.qs.aggregate(Min(
        'created_at'), Max('created_at'))
    context['max_date'] = max_min['created_at__max']
    context['min_date'] = max_min['created_at__min']
    context['invoices'] = invoice_filter.qs
    context['form'] = invoice_filter.form
    if invoice_filter.qs.count() == 0:
        messages.error(request, 'Aucune donnée correspondant aux filtres !')
    return render(request, 'websales/invoices.html', context=context)

对于那些想要 boostrap5 轻松地在模板中使用表单的人(我也花了时间找到方法),只需将 invoice_filter.form 的输入名称命名如下:

created_at_before
 created_at_after

    <form method="get" action="{% url 'websales:invoices' %}" class="row gy-2 gx-3 align-items-center mb-4">
        {% csrf_token %}
        <div class="col-auto">
            <div class="input-group">
                <div class="input-group-text" id="start">Début</div>
                <input name="created_at_before" class="form-control me-3" type="date"
                    value="{{ min_date|date:'Y-n-d' }}" />
            </div>
        </div>
        <div class="col-auto me-4">
            <div class="input-group">
                <div class="input-group-text" id="end">fin</div>
                <input name="created_at_before" class="form-control" type="date" value="{{ max_date|date:'Y-n-d' }}" />
            </div>
        </div>
        <div class="col-auto">
            <button class="btn btn-success me-3" role="submit">Filtrer</button>
            <a class="btn btn-outline-secondary me-3" role="button" href="{% url 'websales:invoices' %}">Reset</a>
            <a class="btn btn-warning" role="button" href="#">Export CSV</a>
        </div>
    </form>

我还用 value="{{ max_date|date:'Y-n-d' }}"

 预填充了输入字段 
min/max

日期

瞧!

© www.soinside.com 2019 - 2024. All rights reserved.