How can one customize Django Rest Framework serializers output?

16,127

Solution 1

Create a custom serializer field and implement to_native so that it returns the list you want.

If you use the source="*" technique then something like this might work:

class CustomField(Field):
    def to_native(self, obj):
        return obj.macAddresses.all()

I hope that helps.

Update for djangorestframework>=3.9.1

According to documentation, now you need override either one or both of the to_representation() and to_internal_value() methods. Example

class CustomField(Field):
    def to_representation(self, value)
        return {'id': value.id, 'name': value.name}

Solution 2

Carlton's answer will work do the job just fine. There's also a couple of other approaches you could take.

You can also use SlugRelatedField, which represents the relationship, using a given field on the target.

So for example...

class WindowsCompleteMappingSerializer(serializers.Serializer):
    id = serializers.Field()
    macAddresses = serializers.SlugRelatedField(slug_field='address', many=True, read_only=True)
    clientId = serializers.Field()

Alternatively, if the __str__ of the WindowsMacAddress simply displays the address, then you could simply use RelatedField, which is a basic read-only field that will give you a simple string representation of the relationship target.

# models.py
class WindowsMacAddress(models.Model):
    address = models.TextField(unique=True)
    mapping = models.ForeignKey('imaging.WindowsMapping', related_name='macAddresses')

    def __str__(self):
        return self.address

# serializers.py
class WindowsCompleteMappingSerializer(serializers.Serializer):
    id = serializers.Field()
    macAddresses = serializers.RelatedField(many=True)
    clientId = serializers.Field()

Take a look through the documentation on serializer fields to get a better idea of the various ways you can represent relationships in your API.

Share:
16,127
ereOn
Author by

ereOn

I love Golang, networking and security. If you need an open-source, free, multi-platform, VPN solution, you may want to check http://www.freelan.org which is basically how I spend my free time.

Updated on July 23, 2022

Comments

  • ereOn
    ereOn almost 2 years

    I have a Django model that is like this:

    class WindowsMacAddress(models.Model):
        address = models.TextField(unique=True)
        mapping = models.ForeignKey('imaging.WindowsMapping', related_name='macAddresses')
    

    And two serializers, defined as:

    class WindowsFlatMacAddressSerializer(serializers.Serializer):
        address = serializers.Field()
    
    class WindowsCompleteMappingSerializer(serializers.Serializer):
        id = serializers.Field()
        macAddresses = WindowsFlatMacAddressSerializer(many=True)
        clientId = serializers.Field()
    

    When accessing the serializer over a view, I get the following output:

    [
        {
            "id": 1, 
            "macAddresses": [
                {
                    "address": "aa:aa:aa:aa:aa:aa"
                }, 
                {
                    "address": "bb:bb:bb:bb:bb:bb"
                }
            ], 
            "clientId": null
        }
    ]
    

    Almost good, except that I'd prefer to have:

    [
        {
            "id": 1, 
            "macAddresses": [
                "aa:aa:aa:aa:aa:aa",
                "bb:bb:bb:bb:bb:bb"
            ],
            "clientId": null
        }
    ]
    

    How can I achieve that ?

  • Hieu Nguyen
    Hieu Nguyen over 10 years
    Hmm I thought RelatedField and SlugRelatedField only work with ModelSerializer?
  • Tom Christie
    Tom Christie over 10 years
    All the relational fields work with Django model relationships. They'll work just fine either used on a Serializer or a ModelSerializer class.
  • Hieu Nguyen
    Hieu Nguyen over 10 years
    Thanks! It will be useful for me later on.
  • vimal1083
    vimal1083 almost 8 years
    All the links given are broken, could you please update it