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

时间:2016-05-12 10:17:03

标签: python django rest django-rest-framework django-filter

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

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调用以返回时间戳大于或等于某个值的所有对象?

5 个答案:

答案 0 :(得分:9)

要扩展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

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

答案 1 :(得分:5)

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

import django_filters
from rest_framework import filters
from rest_framework import viewsets

class EventFilter(filters.FilterSet):
    timestamp_gte = django_filters.DateTimeFilter(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库。

答案 2 :(得分:3)

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

  • 2016-01-02 00:00 + 0000

使用:

  • 2016-01-02T00:00:00Z

答案 3 :(得分:0)

更好的方法是在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 :(得分:0)

没有一个答案对我有用,但是确实如此:

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',