alena
alena

Reputation: 61

Django REST Framework: Show only latest of nested object, return as un-nested JSON

What I'm trying to do in Django REST Framework: Return only latest nested object in list for an object and return it as JSON, with the sub-object un-nested.

My models:

class BaseObject(models.Model):
   name = models.TextField()
   object_type = models.ForeignKey(ObjectType)


class ObjectStatus(models.Model):
   baseobject_id = models.ForeignKey('objects.BaseObject', related_name='status')
   object_status = models.IntegerField()
   object_status_timestamp = models.DateTimeField()

My serializers:

class ObjectStatusSimplifiedSerializer(serializers.ModelSerializer):  #helper serializer to simplify status objects
   class Meta:
       model = ObjectStatus
       fields = ['object_status', 'object_status_timestamp']


class ObjectStatusListSerializer(serializers.ModelSerializer):  #request for last status of several objects
   status = ObjectStatusSimplifiedSerializer(many=True)

   class Meta:
       model = BaseObject
       fields = ['id', 'name', 'object_type', 'status']

My current view:

class ObjectStatusListView(generics.ListCreateAPIView):
   serializer_class = ObjectStatusListSerializer

   def get_queryset(self):
       queryset = BaseObject.objects.all()
       id = self.request.query_params.getlist('id')
       if id:
           queryset = queryset.filter(id__in=id)
           return queryset

Current URL:

url(r'^objectstatus/status/list$', views.ObjectStatusListView.as_view()),

So now, when going to, for example, [...]/objectstatus/status/list?id=9, the result I get looks like this:

[
    {
        "id": 9,
        "name": "r5",
        "object_type": "router",
        "status": [
            {
                "object_status": 1,
                "object_status_timestamp": "2019-10-24T09:40:15.605391Z"
            },
            {
                "object_status": 2,
                "object_status_timestamp": "2019-10-24T09:40:28.133296Z"
            },
            {
                "object_status": 3,
                "object_status_timestamp": "2019-10-24T09:40:40.829486Z"
            },
            {
                "object_status": 1,
                "object_status_timestamp": "2019-10-24T09:40:53.333332Z"
            }
        ]
    }
]

What I want is to display only the object status with the most recent timestamp.

Also, I can't figure out how to flatten the JSON object, like this:

[
    {
        "id": 9,
        "name": "r5",
        "object_type": "router",
        "object_status": 1,
        "object_status_timestamp": "2019-10-24T09:40:53.333332Z"
    }
]

Upvotes: 1

Views: 891

Answers (2)

Enthusiast Martin
Enthusiast Martin

Reputation: 3091

With the following serializer, you should get the desired output. We filter the status list and get only the latest one and then we flatten the structure as you need.

class ObjectStatusListSerializer(serializers.ModelSerializer):  #request for last status of several objects
   status = serializers.SerializerMethodField(read_only=True)

   class Meta:
       model = BaseObject
       fields = ['id', 'name', 'object_type', 'status']


    def get_status(self, obj):
       return ObjectStatusSimplifiedSerializer(instance=obj.status.order_by('object_status_timestamp').first()).data

    def to_representation(self, obj):
        """Move fields from status to main object representation."""
        representation = super().to_representation(obj)
        status_representation = representation.pop('status')
        for key in status_representation:
            representation[key] = status_representation[key]

        return representation

Upvotes: 1

Ngoc Pham
Ngoc Pham

Reputation: 1458

you can try change serializer to like this. I assum your ObjectType have field is name for line code object_type.name

class ObjectStatusSimplifiedSerializer(serializers.ModelSerializer):
    name = serializers.SerializerMethodField()
    object_type = serializers.SerializerMethodField()

    @staticmethod
    def get_name(instance):
        return instance.status.name

    @staticmethod
    def get_object_type(instance):
        return instance.status.object_type.name

    class Meta:
        model = ObjectStatus
        fields = ['id', 'name', 'object_type', 'object_status', 'object_status_timestamp']

class ObjectStatusListSerializer(serializers.ModelSerializer):
    status = serializers.SerializerMethodField()

    @staticmethod
    def get_status(instance):
        queryset = ObjectStatus.objects.filter(baseobject_id=instance).order_by('-object_status_timestamp')[:1]
        if queryset.count():
            return ObjectStatusSimplifiedSerializer(queryset, many=True).data
        return []

    class Meta:
        model = BaseObject
        fields = ['id', 'name', 'object_type', 'status']

Upvotes: 1

Related Questions