2

Updated

I changed my simplified question into a real example.

I've created a working post response of data from the model using ModelSerialzer, which I call from a post method in a view class. I would like to add additional data to the response. This is the pertinent code from my CBV:

def post(self, request, format=None):
    user_profile = UserProfiles.objects.get(user=request.user.id)
    service_id = user_profile.service_id
    rec_filter = Recommendations.objects.values_list('resource')
    if service_id > 0:
        service_name = Services.objects.get(pk=service_id)
        programs = Programs.objects.filter(services=service_id)
        resources_filtered = Resources.objects.filter(program__in=programs).exclude(id__in=rec_filter)
    else:
        service_name = 'All Services'
        resources_filtered = Resources.objects.exclude(id__in=rec_filter)

    serializer = ResourceSerializer(resources_filtered, many=True)
    #serializer.data["service"] = service_name
    return Response(serializer.data)

The commented out line was my attempt to add data base on a similar post here. I get a 500 response in my API call. What is the correct way to do it? The response data is JSON if that's necessary to mention.

This is the ModelSerializer:

class ResourceSerializer(serializers.ModelSerializer):
organization = OrganizationSerializer(read_only=True)
program = ProgramSerializer(read_only=True)

class Meta:
    model = Resources
    fields = [
        'organization',
        'program',
        'link',
        'contact',
        'general_contact',
        'eligibility',
        'service_detail'
    ]

Test of the answer

Heres the updated code based on the answer with a correction to fix and error:

class ResourceSerializer(serializers.ModelSerializer):
organization = OrganizationSerializer(read_only=True)
program = ProgramSerializer(read_only=True)
service = serializers.SerializerMethodField()

def get_service(self, obj):
    return "All Services"

class Meta:
    model = Resources
    fields = [
        'organization',
        'program',
        'link',
        'contact',
        'general_contact',
        'eligibility',
        'service_detail',
        'service'
    ]

The problem with this approach is that the value "All Services" is repeated in every row serialized. It's only needed once. I'd also like to keep the data transmitted minimized.

curt
  • 4,422
  • 3
  • 42
  • 61
  • You can do this in your `ResourceSerializer`. Is this not an option? – Brian Destura Jul 07 '21 at 00:16
  • Please have a look at [“What to do when someone answers” - Don't be a chameleon, don't be a vandal](https://meta.stackoverflow.com/questions/332820/what-to-do-when-someone-answers-dont-be-a-chameleon-dont-be-a-vandal). As the post suggests, **don't** change your question wildly such that they invalidate existing answers! – Abdul Aziz Barkat Jul 07 '21 at 04:11
  • Also see [“Follow on” question vs edit to original - when to use which?](https://meta.stackoverflow.com/questions/290746/follow-on-question-vs-edit-to-original-when-to-use-which) which explains what you should have done instead. – Abdul Aziz Barkat Jul 07 '21 at 04:26
  • @bdbd The recouserserializer serializes a single table and its linked tables. In the interest of KISS, I wouldn't want to add code totally unrelated to its purpose. – curt Jul 07 '21 at 15:48

3 Answers3

2

The problem with the original attempt is that serializer.data is immutable. It's necessary to make a copy and add to it.

serializer = ResourceSerializer(resources_filtered, many=True)
augmented_serializer_data = list(serializer.data)
augmented_serializer_data.append({'service': 'All Services'})
return Response(augmented_serializer_data)

This answer is based on one given by @andre-machado in this question.

This code here is an example to coincide with the other answer given.

curt
  • 4,422
  • 3
  • 42
  • 61
1

You can do it in serializer itself. Define the new field required and add it in fields. Mark all the fields in serializer from resource model.

class ResourceSerializer(serializers.ModelSerializer):
    service = serializers.SerializerMethodField()

    def get_service(self):
            return "All Services"

    class Meta :
        model = Resources
        fields = ('service')           #Mark all the fields required here from resource model
  • Your answer looks like it would work. My issue is more complex than the original question. I've updated it to show exactly what I need. – curt Jul 07 '21 at 02:11
  • I tried the answer and it failed as detailed in the question. Did I screw it up somehow? In addition, the same data ("All services") will appear it each of the rows serialized. I only need it once. – curt Jul 07 '21 at 16:02
  • Fixed it. You need to add ", obj" to the get_service parms. – curt Jul 07 '21 at 16:27
0

You can do it from the serilaizer. In this case i was adding the field isOpen to the response and this is how i did it .timeDifference is the name of the function that was to generate data for the extra field . I hope it helps

class ShopSearchSerializer(serializers.ModelSerializer):
isOpen = serializers.SerializerMethodField('timeDifference')

def timeDifference(self,*args):
    requestTime = datetime.now()
    return requestTime

class Meta:
    model = Shop
    fields =['name','city','street','house','opening_time','closing_time','isOpen']
Insookwa
  • 89
  • 1
  • 5