Bill_Flanders
Bill_Flanders

Reputation: 603

Django REST framework: Dynamic serializer relation field - POST pk but GET hyperlink

In my models, I have "states" and "countries". One country can have many states.

HTTP GET state with PK 1:

{
    "id": 1,
    "url": "http://test.com/states/1/",
    "name": "Ohio",
    "country": "http://test.com/countries/2/"
}

I like returning a hyperlinked related field for country in the representation above. However, it forces me to POST the hyperlinked URL when making updates to states, which can be cumbersome for clients. I would prefer to only POST the primary key of the country, like this:

HTTP PUT/POST:

{
    "id": 1,
    "url": "http://test.com/states/1/",
    "name": "Ohio",
    "country": 2
}

Is there an elegant way to do this?

For reference, here are other components:

Models.py

class State(models.Model):
    name = models.TextField()
    country = models.ForeignKey(Country, related_name='states', null=True)

class Country(models.Model):
    name = models.TextField()

Views.py

class StateViewSet(ExpandModelViewSet):
    queryset = State.objects.all()
    serializer_class = StateSerializer

class CountryViewSet(ExpandModelViewSet):
    queryset = Country.objects.all()
    serializer_class = CountrySerializer

Serializers.py

class StateSerializer(ExpandModelSerializer):

    country = serializers.HyperlinkedRelatedField(view_name='country-detail', queryset=Country.objects.all(), allow_null=True)

    class Meta:
        model = State
        fields = ('id', 'url', 'name', 'country')


class CountrySerializer(ExpandModelSerializer):

    class Meta:
        model = Country
        fields = ['id', 'url', 'name']

Upvotes: 4

Views: 1626

Answers (2)

Dhia
Dhia

Reputation: 10609

you have to set simply the readonly to true read_only=True, he does not oblige you to insert the whole link, just the id will be sufficient:

class StateSerializer(ExpandModelSerializer):

     country = serializers.HyperlinkedRelatedField(read_only=True, view_name='country-detail', queryset=Country.objects.all(), allow_null=True)

     class Meta:
        model = State
        fields = ('id', 'url', 'name', 'country')

and in your data send country_id key instead of country

Upvotes: 1

Erik Svedin
Erik Svedin

Reputation: 1286

I believe serializer method fields are what you are looking for, you can then in the serializer method grab and inspect the request method and with the help of that return your attribute serialized in your preferred way.

Reference: http://www.django-rest-framework.org/api-guide/fields/#serializermethodfield

Upvotes: 0

Related Questions