3

I am using the ModelSerializer from the Django Rest Framework to create an API. The ModelSerializer works great for returning JSON lists of whatever I query the database for. But I need to have some additional fields at the root level of the JSON response. How can I bump the query result to another level and add custom fields at the root of the JSON object?

This is what the API query returns:

HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

[
    {
        "user": {
            "username": "myuser"
        },
        "content": "Another tweet",
        "timesince": "2 weeks, 3 days",
        "url": "/tweet/3/",
        "id": 3
    },
    {
        "user": {
            "username": "myuser"
        },
        "content": "a tweet",
        "timesince": "2 weeks, 3 days",
        "url": "/tweet/2/",
        "id": 2
    }
]

This is what I want:

HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "custom_field": "custom value",
    "result": [
            {
                "user": {
                    "username": "myuser"
                },
                "content": "Another tweet",
                "timesince": "2 weeks, 3 days",
                "url": "/tweet/3/",
                "id": 3
            },
            {
                "user": {
                    "username": "myuser"
                },
                "content": "a tweet",
                "timesince": "2 weeks, 3 days",
                "url": "/tweet/2/",
                "id": 2
            }
    ]
}

serializer.py:

from django.utils.timesince import timesince

from rest_framework import serializers

from tweets.models import Tweet
from accounts.api.serializers import UserDisplaySerializer

class TweetSerializer(serializers.ModelSerializer):
    user = UserDisplaySerializer(read_only=True)
    timesince = serializers.SerializerMethodField()
    url = serializers.CharField(source='get_absolute_url', read_only=True)

    class Meta:
        model = Tweet
        fields = [
            'user',
            'content',
            'timesince',
            'url',
            'id',
            ]

    def get_timesince(self, obj):
        return timesince(obj.created)

views.py:

from django.db.models import Q
from rest_framework import generics
from rest_framework import exceptions
from rest_framework import permissions

from tweets.models import Tweet
from tweets.api import serializers

class TweetListAPIView(generics.ListAPIView):
    serializer_class = serializers.TweetSerializer

    def get_queryset(self, *args, **kwargs):
        queryset = Tweet.objects.all()
        queryset = queryset.order_by('-id')

        return queryset

1 Answer 1

3

You can do this by overriding the list method of the ListAPIView and then adding this new field to the response:

from rest_framework.response import Response

def list(self, request, *args, **kwargs):
    queryset = self.get_queryset()
    serializer = self.get_serializer(queryset, many=True)

    response_data = {'custom_field': 'custom value',
                     'result': serializer.data}

    return Response(response_data)
Sign up to request clarification or add additional context in comments.

4 Comments

Yes, that works. Had to import rest_framework.response.Response
Yes.. Edited :)
works like a charm! thank you. To make the order of fields fixed, just use OrderedDict from collections library.
Also, check this answer if you need to apply filters and pagination to queryset.

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.