I have a tv channel model and created a django-restframework viewlet which gives me a list and a detail view out of the box. On top I added two custom single-object views called all_events and now_and_next_event, as described here: Marking extra methods for routing. That works great so far.
class ChannelViewSet(viewsets.ModelViewSet):
"""
A viewset for viewing and editing channel instances.
"""
serializer_class = serializers.ChannelSerializer
queryset = Channel.objects.all()
@link()
def now_and_next_event(self, request, pk):
''' Show current and next event of single channel. '''
...
Now I would like to add a custom view which is NOT a single-object view but a list-like view:
class CurrentEvents(generics.ListCreateAPIView):
''' Show current event of all channels. '''
model = Event
serializer_class = serializers.EventSerializer
def get(self, request):
...
When I disable my viewlet and add a manual url pattern for it, it works as well. But I haven't figured out how to make them both work with the same 'api/channel/' prefix, or what I would like more, how to add the custom list view class into my viewlet.
Here are my viewlet url patterns:
^api/channel/$ [name='channel-list']
^api/channel/(?P<pk>[^/]+)/$ [name='channel-detail']
^api/channel/(?P<pk>[^/]+)/all_events/$ [name='channel-all-events']
^api/channel/(?P<pk>[^/]+)/now_and_next_event/$ [name='channel-now-and-next-event']
And I would like to access my list view like:
^api/channel/current_events/$ [name='event-current']
A ViewSet class is simply a type of class-based View, that does not provide any method handlers such as . get() or . post() , and instead provides actions such as . list() and . create() .
While regular views act as handlers for HTTP methods, viewsets give you actions, like create or list . The great thing about viewsets is how they make your code consistent and save you from repetition. Every time you write views that should do more than one thing, a viewset is the thing that you want to go for.
APIView allow us to define functions that match standard HTTP methods like GET, POST, PUT, PATCH, etc. Viewsets allow us to define functions that match to common API object actions like : LIST, CREATE, RETRIEVE, UPDATE, etc.
lookup_field - The model field that should be used to for performing object lookup of individual model instances. Defaults to 'pk' . Note that when using hyperlinked APIs you'll need to ensure that both the API views and the serializer classes set the lookup fields if you need to use a custom value.
if you want list of objects then you need list method in your ListApiView: For example, model is ModelName and serializer class is SerializerClassname then code will be:
class ExampleView(ListAPIView):
model = ModelNmae
serializer_class = SerializerClassName
permission_classes = (IsAuthenticated,)
def get_queryset(self):
"""
"""
queryset = ModelName.objects.all()
q = self.request.query_params.get('q', None)
if q is not None:
queryset =queryset.filter(name__icontains=q)
return queryset
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
result = [ x.values()[0] for x in serializer.data ]
return Response(result)
As of Django REST Framework 2.4, you can now decorate ViewSet
methods with @list_route
to get what you are looking for.
From the documentation
The
@detail_route
decorator containspk
in its URL pattern and is intended for methods which require a single instance. The@list_route
decorator is intended for methods which operate on a list of objects.
These replace the old @link
and @action
decorators which were only able to work as detail routes.
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