Django - 如何使用 Django Rest Framework 按日期过滤?

Posted

技术标签:

【中文标题】Django - 如何使用 Django Rest Framework 按日期过滤?【英文标题】:Django - How to filter by date with Django Rest Framework? 【发布时间】:2016-09-08 02:41:57 【问题描述】:

我有一些带有时间戳字段的模型:

models.py

class Event(models.Model):
    event_type = models.CharField(
        max_length=100,
        choices=EVENT_TYPE_CHOICES,
        verbose_name=_("Event Type")
    )
    event_model = models.CharField(
        max_length=100,
        choices=EVENT_MODEL_CHOICES,
        verbose_name=_("Event Model")
    )
    timestamp = models.DateTimeField(auto_now=True, verbose_name=_("Timestamp"))

然后我使用 Django-rest-framework 为此类创建 API 端点,django-filter 提供如下过滤功能:

from .models import Event
from .serializers import EventSerializer
from rest_framework import viewsets, filters
from rest_framework import renderers
from rest_framework_csv import renderers as csv_renderers


class EventsView(viewsets.ReadOnlyModelViewSet):
    """
    A read only view that returns all audit events in JSON or CSV.
    """
    queryset = Event.objects.all()
    renderer_classes = (csv_renderers.CSVRenderer, renderers.JSONRenderer)
    serializer_class = EventSerializer
    filter_backends = (filters.DjangoFilterBackend,)
    filter_fields = ('event_type', 'event_model', 'timestamp')

使用以下设置:

REST_FRAMEWORK = 
    'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.DjangoFilterBackend',),

我可以按event_typeevent_model 进行过滤,但无法按时间戳字段进行过滤。本质上,我想进行相当于以下内容的 API 调用:

AuditEvent.objects.filter(timestamp__gte='2016-01-02 00:00+0000')

我希望我可以这样做:

response = self.client.get("/api/v1/events/?timestamp=2016-01-02 00:00+0000", **'HTTP_ACCEPT': 'application/json')

虽然这是不正确的。如何进行 API 调用以返回时间戳大于或等于某个值的所有对象?

【问题讨论】:

【参考方案1】:

您可以按如下方式创建特定的FilterSet

import django_filters
from rest_framework import filters
from rest_framework import viewsets

class EventFilter(filters.FilterSet):
    timestamp_gte = django_filters.DateTimeFilter(field_name="timestamp", lookup_expr='gte')
    class Meta:
        model = Event
        fields = ['event_type', 'event_model', 'timestamp', 'timestamp_gte']

class EventsView(viewsets.ReadOnlyModelViewSet):
    ...
    filter_class = EventFilter

你可以通过"/api/v1/events/?timestamp_gte=2016-01-02"过滤

编辑:为了澄清,这个例子使用了django-filter 库。

【讨论】:

嗯,我仍然得到 0 响应,而我应该得到 1。我尝试使用 django_filters.DateTimeFilterdjango_filters.IsoDateTimeFilter。知道为什么会这样吗? 它适用于我,但使用 DateFilter 而不是 DateTimeFilter。 @orange1【参考方案2】:

没有一个答案对我有用,但这确实有效:

class EventFilter(filters.FilterSet):
    start = filters.IsoDateTimeFilter(field_name="start", lookup_expr='gte')
    end = filters.IsoDateTimeFilter(field_name="end", lookup_expr='lte')

    class Meta:
        model = Event
        fields = 'start', 'end',

【讨论】:

【参考方案3】:

更好的方法是在 get_queryset 函数中过滤日期时间

def get_queryset(self):
    queryset = Event.objects.all()
    start_date = self.request.query_params.get('start_date', None)
    end_date = self.request.query_params.get('end_date', None)
    if start_date and end_date:
        queryset = queryset.filter(timstamp__range=[start_date, end_date])

【讨论】:

这不是一个很好的例子,尽管它可能适用于特定的快速和肮脏的解决方案,但一旦你有不同类型的请求,它就会失败。【参考方案4】:

IsoDateTimeFilter对输入格式很挑剔;而不是:

2016-01-02 00:00+0000

使用:

2016-01-02T00:00:00Z

【讨论】:

【参考方案5】:

为了扩展 Flaiming 的答案,如果您只打算通过 ISO 日期时间格式进行过滤,覆盖默认值以始终使用 IsoDateTimeFilter 会有所帮助。这可以通过每个过滤器集来完成,例如

from django.db import models as django_models
import django_filters
from rest_framework import filters
from rest_framework import viewsets

class EventFilter(filters.FilterSet):
    class Meta:
        model = Event
        fields = 
            'timestamp': ('lte', 'gte')
        

    filter_overrides = 
        django_models.DateTimeField: 
            'filter_class': django_filters.IsoDateTimeFilter
        ,
    

class EventsView(viewsets.ReadOnlyModelViewSet):
    ...
    filter_class = EventFilter

您不必担心为每个查找表达式和每个字段设置不同的过滤器。

【讨论】:

EventFillter 导致 django 后端过滤器不再工作 filters.FilterSet 在 Django 2.1 中不再存在 改用这个:from django_filters import rest_framework as filters

以上是关于Django - 如何使用 Django Rest Framework 按日期过滤?的主要内容,如果未能解决你的问题,请参考以下文章

Django - 如何使用 Django Rest Framework 按日期过滤?

如何使用 Django-oauth-toolkit 使用 Django-rest-framework 测试 API 端点以进行身份​​验证

如何使用 django-rest-auth 和 Mailgun 从 Django 发送密码重置电子邮件

如何在 django-rest-framework 中为 API 使用 TokenAuthentication

如何使用 Django Rest Framework 在 Django 中进行操作日志记录

如何使用 Django 通道为 Django Rest Api 打开 Websocket?