8

Just getting into Django Rest Framework.

I have a simple example running where a model is being presented through the REST API. There are no Related fields in the model, just a bunch of strings.

What is the easiest way to present the get_absolute_url() value of that model into the JSON output?

I'm using serializers.HyperlinkedModelSerializer in preparation for moving into more complicated models that do have related fields.

Rahul Gupta
  • 46,769
  • 10
  • 112
  • 126
SimonMorris
  • 127
  • 1
  • 10
  • I found a lot of the answer in this [relevant post](http://stackoverflow.com/questions/18396547/django-rest-framework-adding-additional-field-to-modelserializer) – SimonMorris Oct 08 '15 at 14:21

3 Answers3

14

Approach-1 Using a SerializerMethodField:

You can use a SerializerMethodField in your serializer to add the get_absolute_url() value to the serialized representation of the object.

As per the SerializerMethodField docs:

This is a read-only field. It gets its value by calling a method on the serializer class it is attached to. It can be used to add any sort of data to the serialized representation of your object.

We will define a method get_my_abslute_url() for the my_absolute_url field in our serializer which will add the absolute url of the object to the serialized representation.

class MyModelSerializer(serializers.ModelSerializer):

    my_absolute_url = serializers.SerializerMethodField() # define a SerializerMethodField        

    def get_my_absolute_url(self, obj):
        return obj.get_absolute_url() # return the absolute url of the object

Approach-2 Using URLField with source argument:

You can also use a URLField and pass the method get_absolute_url to it. This will call the method get_absolute_url and return that value in the serialized representation.

From DRF docs on source argument:

The name of the attribute that will be used to populate the field. May be a method that only takes a self argument, such as URLField('get_absolute_url'), or may use dotted notation to traverse attributes, such as EmailField(source='user.email').

class MyModelSerializer(serializers.ModelSerializer):

    my_absolute_url = serializers.URLField(source='get_absolute_url', read_only=True) 

I would suggest using the 2nd approach as DRF has explicitly used this in its docs.

Rahul Gupta
  • 46,769
  • 10
  • 112
  • 126
2

Just had to deal with this myself. Basically you'll want to leverage the build_absolute_uri() method of the request available in the serializer's context, like so:

class FooSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Foo
        fields = ("web_url",)

    web_url = serializers.SerializerMethodField()

    def get_web_url(self, obj):
        obj_url = obj.get_absolute_url()
        return self.context["request"].build_absolute_uri(obj_url)
NiKo
  • 11,215
  • 6
  • 46
  • 56
0

This maybe the best way in the latest version of drf instead of URLField way or SerializerMethodField way:

# serializers.py
class DocumentSerializer(serializers.ModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name='page-detail')  # define a SerializerMethodField

# urls.py
router = DefaultRouter()
router.register(r'pages', xxx, basename='page') # will generate url named `page-detail` that can be reversed in `HyperlinkedIdentityField`
urlpatterns = router.urls

# Almost equal
# urlpatterns = [
#  path('page/', xxx, name='page-list'),
#   path('page/{pk}', xxx, name='page-detail'),
#]

After reading the source code of drf, source=get_absolute_url is not working now.

Sailist
  • 134
  • 8