11

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']
1

3 Answers 3

9

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 contains pk 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.

Sign up to request clarification or add additional context in comments.

1 Comment

As of 3.8, @detail_route and @list_route are pending deprecation in favor of @action(detail=True) and @action(detail=False). (These will be deprecated in 3.9 and removed in 3.10).
6

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)

Comments

0

First, create a viewsets.py file anywhere in the project and write the following code:

from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator

    
class ModelOptsMixin(object):
     """CBV mixin which adds model options to the context."""
    
     def get_context_data(self, **kwargs):
        """Returns the context data to use in this view."""
        ctx = super().get_context_data(**kwargs)
        if hasattr(self, "model"):
            ctx["opts"] = self.model._meta
        return ctx

class BaseListView(
    LoginRequiredMixin,
    PermissionRequiredMixin,
    ModelOptsMixin,
    HasPermissionsMixin,
    ListView,
):
    """ListView CBV with LoginRequiredMixin and PermissionRequiredMixin."""

    def base_paginator(self, instance):
        """
        Set paginator return context of paginator.
        """
        paginator = Paginator(instance, int(settings.DEFAULT_PAGINATION_SIZE))
        page = self.request.GET.get("page", 1)
        try:
            instance_paginator = paginator.page(page)
        except PageNotAnInteger:
            instance_paginator = paginator.page(1)
        except EmptyPage:
            instance_paginator = paginator.page(paginator.num_pages)

        return instance_paginator

Import BaseListView and use this.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.