python - sort - Django REST framework-filtrado contra param de consulta
filter serializer django (3)
Así que creé mi "API" usando el marco REST, ahora tratando de filtrarlo. Así es como se ven mis models.py
más o menos:
class Airline(models.Model):
name = models.TextField()
class Workspace(models.Model):
airline = models.ForeignKey(Airline)
name = models.CharField(max_length=100)
class Passenger(models.Model):
workspace = models.ForeignKey(Workspace)
title = models.CharField(max_length=200)
Así que me gustaría ver en mi archivo JSON "todos los pasajeros en un área de trabajo particular" o "todos los pasajeros en una aerolínea particular", etc.
Aquí está mi, serializers.py
class AirlineSerializer(serializers.ModelSerializer):
class Meta:
model = Airline
class WorkspaceSerializer(serializers.ModelSerializer):
class Meta:
model = Workspace
class PassengerSerializer(serializers.ModelSerializer):
class Meta:
model = Passenger
Y views.py
:
class AirlineList(generics.ListCreateAPIView):
model = Airline
serializer_class = AirlineSerializer
class AirlineDetail(generics.RetrieveUpdateDestroyAPIView):
model = Airline
serializer_class = AirlineSerializer
class WorkspaceList(generics.ListCreateAPIView):
model = Workspace
serializer_class = WorkspaceSerializer
class WorkspaceDetail(generics.RetrieveUpdateDestroyAPIView):
model = Workspace
serializer_class = WorkspaceSerializer
class PassengerList(generics.ListCreateAPIView):
model = Passenger
serializer_class = PassengerSerializer
class PassengerDetail(generics.RetrieveUpdateDestroyAPIView):
model = Passenger
serializer_class = PassengerSerializer
Es la primera vez que utilizo el marco REST, he comprobado los documentos, me han ayudado con lo que he hecho hasta ahora, me gustaría usar
Filtrado según el parámetro de consulta: http://www.django-rest-framework.org/api-guide/filtering/#filtering-against-query-parameters
Realmente no puedo conseguirlo ...
Así que con @limelights logré hacer lo que quería, aquí está el código:
class PassengerList(generics.ListCreateAPIView):
model = Passenger
serializer_class = PassengerSerializer
# Show all of the PASSENGERS in particular WORKSPACE
# or all of the PASSENGERS in particular AIRLINE
def get_queryset(self):
queryset = Passenger.objects.all()
workspace = self.request.query_params.get(''workspace'')
airline = self.request.query_params.get(''airline'')
if workspace:
queryset = queryset.filter(workspace_id=workspace)
elif airline:
queryset = queryset.filter(workspace__airline_id=airline)
return queryset
Esta github.com/manjitkumar/drf-url-filters aplica filtros en el conjunto de consultas de una vista usando los parámetros de consulta entrantes de una manera limpia y elegante.
Que se puede instalar con pip como pip install drf-url-filters
Ejemplo de uso
validations.py
from filters.schema import base_query_param_schema
from filters.validations import (
CSVofIntegers,
IntegerLike,
DatetimeWithTZ
)
# make a validation schema for players filter query params
players_query_schema = base_query_param_schema.extend(
{
"id": IntegerLike(),
"name": unicode,
"team_id": CSVofIntegers(), # /?team_id=1,2,3
"install_ts": DatetimeWithTZ(),
"update_ts": DatetimeWithTZ(),
}
)
vistas.py
from rest_framework import (
viewsets,
filters,
)
from .models import Player, Team
from .serializers import PlayerSerializer, TeamSerializer
from .pagination import ResultSetPagination
from .validations import teams_query_schema, players_query_schema
from filters.mixins import (
FiltersMixin,
)
class PlayersViewSet(FiltersMixin, viewsets.ModelViewSet):
"""
This viewset automatically provides `list`, `create`, `retrieve`,
`update` and `destroy` actions.
"""
serializer_class = PlayerSerializer
pagination_class = ResultSetPagination
filter_backends = (filters.OrderingFilter,)
ordering_fields = (''id'', ''name'', ''update_ts'')
ordering = (''id'',)
# add a mapping of query_params to db_columns(queries)
filter_mappings = {
''id'': ''id'',
''name'': ''name__icontains'',
''team_id'': ''teams'', # many-to-many relationship
''install_ts'': ''install_ts'',
''update_ts'': ''update_ts'',
''update_ts__gte'': ''update_ts__gte'',
''update_ts__lte'': ''update_ts__lte'',
}
# add validation on filters
filter_validation_schema = players_query_schema
def get_queryset(self):
"""
Optionally restricts the queryset by filtering against
query parameters in the URL.
"""
query_params = self.request.query_params
queryset = Player.objects.prefetch_related(
''teams'' # use prefetch_related to minimize db hits.
).all()
# This dict will hold filter kwargs to pass in to Django ORM calls.
db_filters = {}
# update filters dict with incoming query params and then pass as
# **kwargs to queryset.filter()
db_filters.update(
self.get_queryset_filters(
query_params
)
)
return queryset.filter(**db_filters)
Puede obtener la misma funcionalidad fuera de la caja simplemente usando el paquete django-filter como se indica en los documentos http://www.django-rest-framework.org/api-guide/filtering/#djangofilterbackend
from rest_framework import filters
class PassengerList(generics.ListCreateAPIView):
model = Passenger
serializer_class = PassengerSerializer
queryset = Passenger.objects.all()
filter_backends = (filters.DjangoFilterBackend,)
filter_fields = (''workspace'', ''workspace__airline'')
En este caso, tendrá que realizar el filtrado utilizando ''workspace = 1'' o ''workspace__airline = 1''