Extension for Django REST Framework 3 which allows for using content-type application/hal-json.
This fork of https://github.com/seebass/drf-hal-json is under active development. As soon as there is a stable version ready, we'll do a merge and push a PyPI package. Until then this should not be considered stable.
pip install drf-hal-json
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'drf_hal_json.pagination.HalPageNumberPagination',
'DEFAULT_PARSER_CLASSES': ('drf_hal_json.parsers.JsonHalParser',),
'DEFAULT_RENDERER_CLASSES': (
'drf_hal_json.renderers.JsonHalRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
),
# To make self links render as 'self' and not 'url', as per the HAL spec
'URL_FIELD_NAME': 'self',
}
- Python 3.5+
- Django 1.11+
- Django REST Framework 3
By using the HalModelSerializer the content is serialized in the HAL JSON format.
Pagination is supported and will produce next
and previous
links.
Model-level relations are both _linked
and _embedded
per default. For only
linking, use HalHyperlinkedRelatedField
in the serializer.
Serializer:
class ResourceSerializer(HalModelSerializer):
class Meta:
model = Resource
View:
class ResourceViewSet(HalCreateModelMixin, ModelViewSet):
serializer_class = ResourceSerializer
queryset = Resource.objects.all()
Request:
GET http://localhost/api/resources/1/ HTTP/1.1
Content-Type application/hal+json
{
"_links": {
"self": {"href": "http://localhost/api/resources/1/"},
"relatedResource": {"href": "http://localhost/api/related-resources/1/"}
},
"id": 1,
"_embedded": {
"subResource": {
"_links": {
"self": {"href": "http://localhost/resources/1/sub-resources/26/"},
"subSubResource": {"href": "http://localhost/resources/1/sub-resources/26/sub-sub-resources/3"}
},
"id": 26,
"name": "Sub Resource 26"
}
}
}
The HAL spec defines a number of optional link properties, such as title
.
These are supported in two different ways.
If the link relationship is based on a model-layer relationship, you can use
HalHyperlinkedRelatedField
, which supports a number of additional keyword
parameters, corresponding to the optional link properties in the HAL specification:
from drf_hal_json.fields import HalHyperlinkedRelatedField
class Resource1Serializer(HalModelSerializer):
# when using HalHyperlinkedRelatedField, the related resources
# will not be embedded, just linked.
related_resources = HalHyperlinkedRelatedField(
many=True, read_only=True, view_name='relatedresource-detail',
title_field='name') # .. also type_field, templated_field, etc.
class Meta:
model = Resource1
fields = ('self', 'related_resources')
The above will look up the name
field of the each related resource and
use that as the link title
.
There is also a HalHyperlinkedIdentityField
which behaves in the same way.
The other way to add custom properties to a link relation is to use
HalContributeToLinkField
. This requires a serializer method to be
added.
from drf_hal_json.fields import HalContributeToLinkField
class FileSerializer(HalModelSerializer):
file = HalFileField()
file_title = HalContributeToLinkField(place_on='file')
file_type = HalContributeToLinkField(place_on='file', property_name='type')
class Meta:
model = FileResource
fields = ('file', 'file_title', 'file_type')
def get_file_title(self, obj):
return str(obj.pk)
def get_file_type(self, obj):
return 'application/zip'
See the implementation of HalFileField
to see how a URL-producing
serializer (by default FileField
serializes to a URL) can be included
in _links
.
HalContributeToLinkField
can be used for any model-level relation
which are not explicitly linked using HalHyperlinkedRelatedField
.
In this case, HalContributeToLinkField
can be used to adorn the self
relation of the resource that is linked to with additional properties.
If you need to process a link URL, or need to insert a URL that is
completely separate from whatever model you are serializing, the
HalHyperlinkedPropertyField
can be used.
from drf_hal_json.fields import HalHyperlinkedPropertyField
class ResourceWithUrl(Model):
@property
def get_docs_url(self):
return '/docs/foo'
@property
def external_url(self):
return 'http://example.com/'
class CustomSerializer(HalModelSerializer):
docs_url = HalHyperlinkedPropertyField(
source='get_docs_url',
process_value=lambda val: val + '?bar')
external_url = HalHyperlinkedPropertyField()
class Meta:
model = ResourceWithUrl
fields = ('self', 'docs_url', 'external_url')
This will serialize into:
{
"_links": {
"docs_url": {
"href": "http://localhost/docs/foo?bar"
},
"external_url": {
"href": "http://example.com/"
}
}
}
See the tests for a complete example project that excercises all the features of this library.
Run tests:
$> make test