J'ai un modèle avec un champ d'horodatage:
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"))
J'utilise ensuite Django-rest-framework pour créer un point de terminaison API pour cette classe, avec Django-filter fournissant une fonctionnalité de filtrage comme suit:
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')
avec les paramètres suivants:
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.DjangoFilterBackend',),
}
Je peux filtrer par event_type
et event_model
, mais j'ai du mal à filtrer par le champ d'horodatage. Essentiellement, je veux faire un appel API qui équivaut à ce qui suit:
AuditEvent.objects.filter(timestamp__gte='2016-01-02 00:00+0000')
que je m'attendrais à pouvoir faire comme suit:
response = self.client.get("/api/v1/events/?timestamp=2016-01-02 00:00+0000", **{'HTTP_ACCEPT': 'application/json'})
bien que ce soit de l'incorect. Comment effectuer un appel d'API qui renvoie tous les objets avec un horodatage supérieur ou égal à une certaine valeur?
Pour développer la réponse de Flaiming, si vous ne souhaitez filtrer que via les formats de date et d'heure ISO, cela aide à remplacer les valeurs par défaut pour toujours utiliser le IsoDateTimeFilter
. Cela peut être fait par jeu de filtres avec par exemple.
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
Vous n'aurez alors plus à vous soucier de définir un filtre différent pour chaque expression de recherche et chaque champ.
Vous pouvez créer des FilterSet
spécifiques comme suit:
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
Que vous pouvez filtrer par "/api/v1/events/?timestamp_gte=2016-01-02"
EDIT: Juste pour clarifier, cet exemple utilise la bibliothèque Django-filter .
IsoDateTimeFilter
est très pointilleux sur le format d'entrée; au lieu de:
utilisation:
Une meilleure façon est de filtrer datetime dans la fonction 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])