web-dev-qa-db-ger.com

Django - Wie filtere ich mit Django Rest Framework nach Datum?

Ich habe ein Modell mit einem Zeitstempelfeld:

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

Ich benutze dann das Django-Rest-Framework, um einen API-Endpunkt für diese Klasse zu erstellen. Der Django-Filter bietet folgende Filterfunktionen:

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

mit folgenden Einstellungen:

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

Ich kann nach event_type und event_model filtern, habe jedoch Probleme beim Filtern nach dem Zeitstempelfeld. Im Wesentlichen möchte ich einen API-Aufruf ausführen, der den folgenden entspricht:

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

was ich erwarten würde, könnte ich wie folgt tun:

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

obwohl das inkorrekt ist. Wie erstelle ich einen API-Aufruf, der alle Objekte mit einem Zeitstempel größer oder gleich einem bestimmten Wert zurückgibt?

7
orange1

Um die Antwort von Flaiming zu erweitern, ist es hilfreich, die Standardeinstellungen zu überschreiben, um immer die IsoDateTimeFilter zu verwenden, wenn Sie nur nach ISO-Datums-/Uhrzeitformaten filtern. Dies kann pro Filtersatz mit z.B.

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

Sie müssen sich dann nicht mehr darum kümmern, für jeden Suchausdruck und jedes Feld einen anderen Filter festzulegen.

8
clwainwright

Sie können bestimmte FilterSet wie folgt erstellen:

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

Dann können Sie nach "/api/v1/events/?timestamp_gte=2016-01-02" filtern

EDIT: Zur Verdeutlichung wird in diesem Beispiel Django-Filter library verwendet.

4
Flaiming

IsoDateTimeFilter ist sehr wählerisch in Bezug auf das Eingabeformat. anstatt:

  • 2016-01-02 00: 00 + 0000

benutzen:

  • 2016-01-02T00: 00: 00Z
3
Bruno Rino

Eine bessere Möglichkeit ist das Filtern der Datums- und Uhrzeitangabe in der Funktion 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])
0
Cookie Zhang