Eoin Murray
Eoin Murray

Reputation: 1955

Django rest frameworok

Im trying to make a django-rest-framework serializer where a related model can be linked by list instead of by detail

class Device(models.Model):
    device_id = models.CharField(max_length=100)

class Log(models.Model):
    device = models.ForeignKey(Device, related_name='logs')

class DeviceSerializer(serializers.HyperlinkedModelSerializer):

    logs = serializers.HyperlinkedRelatedField(many=True, view_name='log-detail')
    class Meta:
        model = Device
        fields = ('logs', 'url', 'device_id')

If I navigate to 'api/devices' is will return a list of devices like so:

[
    {
        "device_id": "12345"
        "url": "http://localhost/api/devices/12345"
        "logs": [
            "http://localhost/api/logs/1",
            "http://localhost/api/logs/2"
            "http://localhost/api/logs/3"
            "http://localhost/api/logs/4"
        ]
    }
]

There can be many many logs. I don't want to write custom logic for pagination of logs inside the Device model, that should be handled by a Logs view.

I would like to have a result like this:

[
    {
        "device_id": "12345"
        "url": "http://localhost/api/devices/12345"
        "logs": [
            "http://localhost/api/logs?device_id=12345"
        ]
    }
]

And a api consumer can just navigate to the provided link to get the device logs.

It seems that serializer relations don't handle this use case. Can someone point me in the most framework idiomatic way to achieve this.

Upvotes: 0

Views: 50

Answers (1)

sinitsynsv
sinitsynsv

Reputation: 893

There is one of the solutions:

Create a method (or property) in the Device model called, for example, get_logs_url, that returned url for device logs:

class Device(models.Model):
    ...
    get_logs_url(self):
        # First parameter is the url name, 'device-logs' for example
        return reverse('device-logs', kwargs={'device_id': self.device_id})

Add field logs_url to DeviceSerializer

class DeviceSerializer(serializers.ModelSerializer):
    ...
    logs_url = serializers.CharField(source='get_logs_url', read_only=True)

Then the result would be like this

[
    {
        "device_id": "12345"
        "logs": "/api/logs?device_id=12345"
    }
]

If you want absolute url in result then your serializer should look something like this

class DeviceSerializer(serializers.ModelSerializer):
    logs_url = serializer.SerializerMethodField()

    def get_logs_url(self, device):
        return self.context['request'].build_absolute_uri(device.get_logs_url())

Then the result would be like this

[
    {
        "device_id": "12345"
        "logs": "http://localhost/api/logs?device_id=12345"
    }
]

Upvotes: 1

Related Questions