" }] And I" /> " }] And I" /> " }] And I"/>

Django REST API: ManyToManyField returns list of IDs, can I return list of JSON objects?

51 Views Asked by At

I have a Django REST API that returns something like this:

[{"Event": { 
  "province": "AB", 
  "event_labels": "[1, 2]"
}, 
"Image" : "<image_str>"
}]

And I want it to return something like this:

[{"Event": { 
  "province": "AB", 
  "event_labels": [{
         "label_name": "blah", 
         "alternate_name": "blah", 
         "grade_level": "Grade 9"
        },
        {
         "label_name": "blah", 
         "alternate_name": "blah", 
         "grade_level": "Grade 10"
        }]
}, 
"Image": "<image_str>"
}]

So far, I've added a serializer, but because of the way my models are nested, I can't seem to get the app to actually use the serializer. I have the labels nested inside Events which are inside and EventView object. Here's the API:

class EventDetailView(APIView):
    
    serializer_class = EventDetailSerializer
    # TODO: prefetch here or in Event class
    
    def get(self, request, username, event_id):
        try:
            user = CustomUser.objects.get(username=username)
        except CustomUser.DoesNotExist:
            return Response(json.dumps({}))

        ctx = EventDetailGetFunction(user, event_id)
        return Response(json.dumps(ctx,  ensure_ascii=False))

    def post(self, request, username, event_id):
        try:
            user = CustomUser.objects.get(username=username)
        except CustomUser.DoesNotExist:
            return Response(json.dumps({}))

        ctx = EventDetailPostFunction(user, event_id, None)
        return Response(json.dumps(ctx,  ensure_ascii=False))

Here is the EventDetailGetFunction:

def EventDetailGetFunction(user, event_id):
    context = {}

    event = Event.objects.get(pk=event_id)

    context['Event']    = serializers.serialize('json', Event.objects.filter(pk=event_id))
    context['Image']    = serializers.serialize('json', Image.objects.filter(event=event))

    # A whole bunch of other context[] field that are not relevant to the question

    return context

This is the Event object:

class Event(models.Model):

    # Returns many other fields which were not relevant so I did not include

    # event_labels = models.ManyToManyField(LabelSerializer(Label), blank=True, null=True)
    event_labels  = models.ManyToManyField(Label, blank=True, null=True)
    province = models.CharField(blank=False, default="AB", max_length=2, choices=PROVINCE_CHOICES)

I tried using the serializer directly in the Event model, however, I get an error when I try to run the API saying django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.. Here are my serializers:

class LabelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Label
        fields = ('label_name', 'alternate_name', 'grade')
        
class EventSerializer(models.Model):
    label = LabelSerializer(many=True)
    
class EventDetailSerializer(models.Model):
    event = EventSerializer()

I played around with a few things but am unsure where I could best use the serializers in my REST API and if I'm even taking the best approach. I'm somewhat new to django so hopefully it's an easy fix and I'm missing something obvious. I'm calling the ./get in from a react mobile app so this is where I'd like to see the end result.

Happy to provide any information that could be helpful. Thanks for your help!

1

There are 1 best solutions below

5
Hans Bambel On

The last error (about models not being ready) stems from this piece of code:

class LabelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Label
        fields = ('label_name', 'alternate_name', 'grade')
        
class EventSerializer(models.Model):
    label = LabelSerializer(many=True)
    
class EventDetailSerializer(models.Model):
    event = EventSerializer()

This code is supposed to be in your serializers.py, but you define a model here. I think you wanted to define an event serializer, right?

class LabelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Label
        fields = ['label_name', 'alternate_name', 'grade']
        
class EventSerializer(serializers.ModelSerializer):
    """Here we use the serializer defined from above"""
    event_labels = LabelSerializer(many=True)

    class Meta:
        model = Event
        fields = ["event_labels", "province"]
    
class EventDetailSerializer(EventSerializer):
    """Here I inherited from the original serializer since I do not know what you want to do differently here"""
    class Meta(EventSerializer.Meta):
        pass

I am not sure why you need EventDetailGetFunction. Is the event not linked to the user in any way (e.g. ForeignKey)? If they are linked, then you can get the event's data without needing a function and use a serializer instead.