Salah
Salah

Reputation: 131

Serializer is displaying id instead of field names with Foreignkey

I'm building a Django app which uses django rest framework and it shows the lists of buses in between two stops given by the user. For this purpose, I wanted to produce a json output as shown below.

   [
    {
        "id": 1,
        "start_time": "09:48:52",
        "end_time": "09:48:53",
        "start_stop": "A",
        "end_stop": "B",
        "bus_in_route": "Bus1"
    },
    {
        "id": 2,
        "start_time": "10:00:00",
        "end_time": "10:10:00",
        "start_stop": "B",
        "end_stop": "C",
        "bus_in_route": "Bus2"
    }
]

But I'm getting the output in the form of IDs. The field values in the child models (Bus, BusStop) are replaced with their IDs.

[
    {
        "id": 1,
        "start_time": "09:48:52",
        "end_time": "09:48:53",
        "start_stop": 1,
        "end_stop": 2,
        "bus_in_route": 1
    },
    {
        "id": 2,
        "start_time": "10:00:00",
        "end_time": "10:10:00",
        "start_stop": 2,
        "end_stop": 3,
        "bus_in_route": 1
    }
]

Code: models.py

class BusStop(models.Model): # model to store several bus stops
    stop_name=models.CharField(max_length=255)
    def __str__(self):
        return str(self.stop_name)


class Bus(models.Model):  # model to store names of several buses
    bus_name=models.CharField(max_length=255)
    def __str__(self):
        return self.bus_name
    class Meta:
        verbose_name = 'Bus'
        verbose_name_plural = 'Buses'


class BusRoute(models.Model):  # lists out routes with start and end stops with the bus running between the stops
    start_stop = models.ForeignKey(BusStop,
                                related_name='start_stop',
                                on_delete=models.CASCADE)
    end_stop = models.ForeignKey(BusStop,
                                related_name='end_stop',
                                on_delete=models.CASCADE)
    bus_in_route = models.ForeignKey(Bus,
                                related_name='bus_in_route',
                                on_delete=models.CASCADE)
    start_time = models.TimeField()
    end_time = models.TimeField()

    def __str__(self):
        return str(self.start_stop)

serializers.py

class BusRouteSerializer(serializers.ModelSerializer):
    class Meta:
        model = BusRoute
        #fields=('firstname','lastname')
        fields='__all__'
        
class BusSerializer(serializers.ModelSerializer):
    bus_in_route = BusRouteSerializer(read_only=True,many=True)
    class Meta:
        model = Bus
        fields='__all__'

class BusStopSerializer(serializers.ModelSerializer):
    start_stop = BusRouteSerializer(read_only=True,many=True)
    end_stop = BusRouteSerializer(read_only=True,many=True)
    class Meta:
        model = BusStop
        fields='__all__'

views.py

class searchBusRoute(ListAPIView):
    serializer_class = BusRouteSerializer
    filter_backends = [SearchFilter, OrderingFilter]

    def get_queryset(self):
        queryset = BusRoute.objects.all()
        return queryset

Is the usage of ForeignKey right? In my views.py, I've tried printing the queryset using start_stop__stop_name. It correctly prints the stop names. I'm facing the mentioned problem when I'm using serializers.

Thanks in advance!

Upvotes: 0

Views: 752

Answers (1)

Sajjad Sanikhani
Sajjad Sanikhani

Reputation: 396

First you should note that related_name parameter given to ForeignKey field refers to its Model not its field.
For example in start_stop field, its related_name must be "start_routes" or something like this. It means that if you have an BusStop object named stop_obj, you can access routes that starts from this stop by stop_obj.start_routes.all().

Second for your problem, first you should remove bus_in_route from BusSerializer and also remove start_stop and end_stop from BusStopSerializer. If you want to show just name of models, also you can remove BusSerializer and BusStopSerializer entirely and then just convert BusRouteSerializer to this:


class BusRouteSerializer(serializers.ModelSerializer):

    start_stop = serializers.SerializerMethodField()
    end_stop = serializers.SerializerMethodField()
    bus_in_route = serializers.SerializerMethodField()
            
    class Meta:
        model = BusRoute
        fields = '__all__'
                
    def get_start_stop(self, obj):
        return obj.start_stop.stop_name
            
    def get_end_stop(self, obj):
        return obj.end_stop.stop_name
            
    def get_bus_in_route(self, obj):
        return obj.bus_in_route.bus_name

Upvotes: 1

Related Questions