68π
The only difference is, as in citation you included, that primary and foreign keys are represented by URLs that point to those resources, instead of just actual key values.
The benefit is that you will not have to construct resource URLs in your frontend when you want to retrieve related objects.
Another thing entirely is nested representations which allows you to inline related objects in your serializer output. This can be combined with both ModelSerializer
and HyperlinkedModelSerializer
when you think that it is more convenient for the API consumer to have related items right away instead of making additional requests to retrieve them.
Nested representations can be implemented via the Meta.depth
option or by using the related modelβs serializer instead of a RelatedField
.
As @xleon said in his comment using URLs as keys makes it easier for other developers to understand your API.
101π
We need to implement relationship between entities in Web API design.
There are several ways to do that (as mentions on DRF documentation):
- Using primary keys.
- Using hyperlinking between entities.
- Using a unique identifying slug field on the related entity.
- Using the default string representation of the related entity.
- Nesting the related entity inside the parent representation.
- Some other custom representation
The HyperlinkedModelSerializer has the following differences from ModelSerializer:
- It does not include the id field by default.
- It includes a url field, using HyperlinkedIdentityField.
- Relationships use HyperlinkedRelatedField, instead of PrimaryKeyRelatedField.
A simple example:
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('url', 'username', 'email', 'groups')
class GroupSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Group
fields = ('url', 'name')
bash> http -a admin:yourpassword http://127.0.0.1:8000/users/
"results": [
{
"email": "admin@min.com",
"groups": [
"http://127.0.0.1:8000/groups/1/",
"http://127.0.0.1:8000/groups/2/"
],
"url": "http://127.0.0.1:8000/users/1/",
"username": "admin"
}
]
But if you change
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('url', 'username', 'email', 'groups')
The result will be:
"results": [
{
"email": "admin@min.com",
"groups": [
1,
2
],
"url": "http://127.0.0.1:8000/users/1/",
"username": "admin"
}
]
- [Django]-How to stop gunicorn properly
- [Django]-Multiple Database Config in Django 1.2
- [Django]-Django models: mutual references between two classes and impossibility to use forward declaration in python
10π
One cost of HyperlinkedModelSerializers that should be noted is that if your API supports filtering or ordering via query parameters in the URL it is a bit more difficult for your frontend consumer to use the hyperlinked url fields for constructing query params because they have to parse out the pk from the URL rather than having the pk directly available.
For example, assuming an object on a route at /api/objects/12/
the consumer would need to parse the url
field to extract the 12
in order to construct a query filtering by this object on another endpoint: /api/otherobjects/?object=12
. Not a huge problem, but a bummer if you plan on doing lots of filtering.
- [Django]-Django MEDIA_URL and MEDIA_ROOT
- [Django]-Python 3 list(dictionary.keys()) raises error. What am I doing wrong?
- [Django]-Django admin make a field read-only when modifying obj but required when adding new obj