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?
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.
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.
IsoDateTimeFilter
ist sehr wählerisch in Bezug auf das Eingabeformat. anstatt:
benutzen:
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])