Here's the situation. I got a list on my Django REST API: /playerslist/
It returns me a list of players just like this one:
http://pastebin.com/JYA39gHT
This is exactly what I want for the moment. But now, I need this:
Going for /playerslist/1/
gives me different infos for the Player Number 1. The list is here only for listing players with basic informations. But I need detailed view for players, containing info from other models and with different serialization, it must be a basic issue, but as I'm totally new to Django and Python in general, I must misunderstanding something.
Here is my Viewset:
class PlayersListViewSet(viewsets.ModelViewSet):
queryset = Player.objects.all()
serializer_class = PlayersListSerializer
http_method_names = ['get', 'post']
pagination_class = None
filter_backends = [filters.OrderingFilter]
ordering_fields = ['name']
def get_queryset(self):
queryset = Player.objects.all()
team_id = self.request.query_params.get('team', None)
if team_id:
try:
queryset = queryset.filter(team=team_id)
except ValueError:
raise exceptions.ParseError()
return queryset
How can I achieve this ? Must I use @detail_route
to have something like playerslist/1/detail
? I've already tried but DRF's documentation only show a single example and it's not clear at all for me.
You can override the methods retrieve (returning one instance) or list (returning list obviously) as shown in first example in http://www.django-rest-framework.org/api-guide/viewsets/.
class PlayersListViewSet(viewsets.ModelViewSet):
queryset = Player.objects.all()
serializer_class = PlayersListSerializer
http_method_names = ['get', 'post']
pagination_class = None
filter_backends = [filters.OrderingFilter]
ordering_fields = ['name']
def get_queryset(self):
queryset = Player.objects.all()
team_id = self.request.query_params.get('team', None)
if team_id:
try:
queryset = queryset.filter(team=team_id)
except ValueError:
raise exceptions.ParseError()
return queryset
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
serializer = PlayerDetailSerializer(instance)
return Response(serializer.data)
Where PlayerDetailSerializer is another serializer with different fields (whatever you need) and there is no need to specify it in serializer_class.
To get different results when you do a 'detail' view, you want to change the serializer when doing a 'retrieve' call. I've done this with a custom mixin for a ModelViewSet, which expects a special "detail_serializer_class":
class DifferentDetailSerializerMixin(object):
"""
For a viewset, mix this in to use a different serializer class
for individual 'retrieve' views, different from the standard
serializer for lists.
"""
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.detail_serializer_class(instance, context=self.get_serializer_context())
return Response(serializer.data)
Your viewset is simply:
class PlayersListViewSet(DifferentDetailSerializerMixin, viewsets.ModelViewSet):
queryset = Player.objects.all()
serializer_class = PlayersListSerializer
detail_serializer_class = PlayersDetailSerializer
filter_backends = [filters.OrderingFilter]
ordering_fields = ['name']
Here, PlayersDetailSerializer is another Serializer that has more fields that you want to return.
As an aside, if you want to support optional filtering by teams, I would strongly recommend using django-filter. That way you don't have to worry about validation etc. Once installed, it's simply a case of adding this to your viewset:
filter_backends = (filters.OrderingFilter, filters.DjangoFilterBackend, )
filter_fields = ['team']
See the docs for more info.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With