10

Does anyone know how can I successfully retrieve the object count of a model, in JSON format, and how I need to configure my routing? I'm trying to achieve this using a APIView and returning a Response formatted by JSONRenderer.

UPDATE:

@api_view(['GET'])
@renderer_classes((JSONRenderer, JSONPRenderer))
def InfluenciasCountView(request, format=None):
    influencia_count = Influencia.objects.count()
    content = {'influencia_count': influencia_count}
    return Response(content)

Here's the route I'm using:

url(r'^influencias/count/$', views.InfluenciasCountView, name='influencias-count')

2 Answers 2

13

Check out this snippet of code (the second one). If this does not suit your need, please add some of your code (for better understanding).

UPDATE

For routing, DRF offers a default router for each view. This means that you can have the following configuration in your urls.py: (using the example from the previous link)

url(r'^users/count/$', views. UserCountView.as_view(), name='users-count')

Then, when you access the URL your_base_url/users/count/ you will see something like {'user_count': 10}.

UPDATE 2

The entire code should look like this:

class UserCountView(APIView):
    """
    A view that returns the count of active users.
    """
    renderer_classes = (JSONRenderer, )

    def get(self, request, format=None):
        user_count = User.objects.count()
        content = {'user_count': user_count}
        return Response(content)
Sign up to request clarification or add additional context in comments.

10 Comments

AdelaN, this snippet is perfect. I've tried to use exactly this one. But couldn't write the correct route for it. Could you help me?
Hi! It didn't work for me. I've updated my question above with the code I'm using, so you can check the details. Basically, I'm getting a 404 (Not Found) when I try to access the route, like this: HTTP 404 NOT FOUND Content-Type: application/json Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS Vary: Accept { "detail": "Not found" }
It didn't work. Anything I should do differently besides using the GenericAPIView?
Yes, you should change the method signature
I did it. It's like below right now. Any changes to the route? @api_view(['GET']) @renderer_classes((JSONRenderer, JSONPRenderer)) def InfluenciasCountView(request, format=None): influencia_count = Influencia.objects.count() content = {'influencia_count': influencia_count} return Response(content)
|
8

I am using routers from REST Framework to build my URLs. I tried above code but doesn't get it working. One of the problems is I cannot get /count/ into the router endpoints.

I checked DRF document (3.8.2) and found that there is a (new?) @action decorator (I was using 3.7.7 and it doesn't have it). So, here is my full solutions:

  1. Upgrade DRF to 3.8.2 (or above) in requirements.txt (or PipFile if you using that).
  2. Add a new action count method to the ModelViewSet
  3. Update get_permissions to include the newly added action count

Here is my views.py:

from rest_framework.decorators import action
from rest_framework.response import Response

class PostViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows recommend to be viewed or edited.
    """
    model = Post
    queryset = Post.objects.filter(is_active=True)
    serializer_class = serializers.PostSerializer
    filter_backends = (filters.SearchFilter, DjangoFilterBackend,)
    search_fields = ('title', 'body',)
    filter_fields = ('status', 'type')

    def get_permissions(self):
        if self.action in ('list', 'retrieve', 'create', 'count'):
            return (AllowAny()),
        if self.action in ('update', 'partial_update'):
            return (IsAdminUser()),
        return (IsAdminUser()),

    @action(detail=False)
    def count(self, request):
        queryset = self.filter_queryset(self.get_queryset())
        count = queryset.count()
        content = {'count': count}
        return Response(content)
  • To query count of posts: /api/posts/count/?format=json
  • To query count of published: /api/posts/count/?format=json&status=published

One of the important thing here is to use the queryset from filter_queryset(...), rather than Post.objects.all().

UPDATE

Since count is common, I created a mixin for that.

from rest_framework.decorators import action
from rest_framework.response import Response

class CountModelMixin(object):
    """
    Count a queryset.
    """
    @action(detail=False)
    def count(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        content = {'count': queryset.count()}
        return Response(content)

To use it, just add CountModelMixin to your ModelViewSet (also support nested ModelViewSet).

class PostViewSet(viewsets.ModelViewSet, CountModelMixin):

If you use permissions, also add 'count' to the list of granted action.

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.