rest_framework_dso.serializers module

The serializers implement additional DSO responses features.

Most features can be implemented by the following means:

  1. Having the proper set of “fields” loaded in the serializer. These field classes determine the format of individual data types.

  2. Overriding to_representation() where needed.

There are 2 layers of serializers, just like standard DRF:

The non-model serializers implement the bits that are not dependant on database ORM logic like models or querysets. These serializers are therefore more limited in functionality, but useful to implement DSO-style responses for other data sources (e.g. remote API responses).

The model-serializers depend on the ORM logic, and support features like object embedding and constructing serializer fields based on the model field metadata.

class rest_framework_dso.serializers.DSOListSerializer(*args, **kwargs)

Bases: ExpandableSerializer, ListSerializer

Fix pagination for lists.

This should be used together with the DSO…Pagination class when results are paginated. It outputs the _embedded section for the HAL-JSON spec: https://tools.ietf.org/html/draft-kelly-json-hal-08

__init__(*args, results_field=None, **kwargs)

Allow to override the results_field on construction

bind(field_name, parent)

Initializes the field name and parent for the field instance. Called when a field is added to the parent serializer instance.

property data
expanded_fields

Retrieve the embedded fields for this serializer

requires_context = True
results_field = None

The field name for the results envelope

class rest_framework_dso.serializers.DSOModelListSerializer(*args, **kwargs)

Bases: DSOListSerializer

Perform object embedding for lists.

This subclass implements the ORM-specific bits that the DSOListSerializer can’t provide.

This should be used together with the DSO…Pagination class when results are paginated. It outputs the _embedded section for the HAL-JSON spec: https://tools.ietf.org/html/draft-kelly-json-hal-08

get_prefetch_lookups() list[Union[django.db.models.query.Prefetch, str]]

Tell which fields should be included for a prefetch_related().

get_queryset_iterator(queryset: QuerySet) Iterable[Model]

Get the most optimal iterator to traverse over a queryset.

to_representation(data)

Improved list serialization.

  • It includes the data for the HAL “_embedded” section.

  • It reads the database with a streaming iterator to reduce memory.

  • It collects any embedded sections, and queries them afterwards

class rest_framework_dso.serializers.DSOModelSerializer(*args, **kwargs)

Bases: DSOSerializer, DSOModelSerializerBase

DSO-compliant serializer for Django models.

This serializer can be used inside a list (by DSOModelListSerializer when many=True is given), or standalone for a detail page.

This supports the following extra’s:

  • The self-URL can be generated when this serializer is used for a _links section.

  • Embedded relations are returned in an _embedded section.

To use the embedding feature, include an EmbeddedField field in the class:

class SomeSerializer(DSOModelSerializer):
    embedded_field = EmbeddedField(SerializerClass)

    class Meta:
        model = ...
        fields = [...]

The embedded support works on all relational fields.

to_representation(instance)

Check whether the geofields need to be transformed.

class rest_framework_dso.serializers.DSOModelSerializerBase(*args, **kwargs)

Bases: HyperlinkedModelSerializer

A base serializer that only handles the field layout.

This base class does not do any request parameter handling at all.

serializer_field_mapping = {<class 'django.db.models.fields.AutoField'>: <class 'rest_framework.fields.IntegerField'>, <class 'django.db.models.fields.BigIntegerField'>: <class 'rest_framework.fields.IntegerField'>, <class 'django.db.models.fields.BooleanField'>: <class 'rest_framework.fields.BooleanField'>, <class 'django.db.models.fields.CharField'>: <class 'rest_framework.fields.CharField'>, <class 'django.db.models.fields.CommaSeparatedIntegerField'>: <class 'rest_framework.fields.CharField'>, <class 'django.db.models.fields.DateField'>: <class 'rest_framework.fields.DateField'>, <class 'django.db.models.fields.DateTimeField'>: <class 'rest_framework.fields.DateTimeField'>, <class 'django.db.models.fields.DecimalField'>: <class 'rest_framework.fields.DecimalField'>, <class 'django.db.models.fields.DurationField'>: <class 'rest_framework.fields.DurationField'>, <class 'django.db.models.fields.EmailField'>: <class 'rest_framework.fields.EmailField'>, <class 'django.db.models.fields.Field'>: <class 'rest_framework.fields.ModelField'>, <class 'django.db.models.fields.files.FileField'>: <class 'rest_framework.fields.FileField'>, <class 'django.db.models.fields.FloatField'>: <class 'rest_framework.fields.FloatField'>, <class 'django.db.models.fields.files.ImageField'>: <class 'rest_framework.fields.ImageField'>, <class 'django.db.models.fields.IntegerField'>: <class 'rest_framework.fields.IntegerField'>, <class 'django.db.models.fields.NullBooleanField'>: <class 'rest_framework.fields.BooleanField'>, <class 'django.db.models.fields.PositiveIntegerField'>: <class 'rest_framework.fields.IntegerField'>, <class 'django.db.models.fields.PositiveSmallIntegerField'>: <class 'rest_framework.fields.IntegerField'>, <class 'django.db.models.fields.SlugField'>: <class 'rest_framework.fields.SlugField'>, <class 'django.db.models.fields.SmallIntegerField'>: <class 'rest_framework.fields.IntegerField'>, <class 'django.db.models.fields.TextField'>: <class 'rest_framework.fields.CharField'>, <class 'django.db.models.fields.TimeField'>: <class 'rest_framework.fields.TimeField'>, <class 'django.db.models.fields.URLField'>: <class 'rest_framework_dso.fields.DSOURLField'>, <class 'django.db.models.fields.UUIDField'>: <class 'rest_framework.fields.UUIDField'>, <class 'django.db.models.fields.GenericIPAddressField'>: <class 'rest_framework.fields.IPAddressField'>, <class 'django.db.models.fields.FilePathField'>: <class 'rest_framework.fields.FilePathField'>, <class 'django.db.models.fields.json.JSONField'>: <class 'rest_framework.fields.JSONField'>, <class 'django.contrib.postgres.fields.hstore.HStoreField'>: <class 'rest_framework.fields.HStoreField'>, <class 'django.contrib.postgres.fields.array.ArrayField'>: <class 'rest_framework.fields.ListField'>, <class 'django.contrib.postgres.fields.jsonb.JSONField'>: <class 'rest_framework.fields.JSONField'>, <class 'django.contrib.gis.db.models.fields.GeometryField'>: <class 'rest_framework_dso.fields.DSOGeometryField'>, <class 'django.contrib.gis.db.models.fields.PointField'>: <class 'rest_framework_dso.fields.DSOGeometryField'>, <class 'django.contrib.gis.db.models.fields.LineStringField'>: <class 'rest_framework_dso.fields.DSOGeometryField'>, <class 'django.contrib.gis.db.models.fields.PolygonField'>: <class 'rest_framework_dso.fields.DSOGeometryField'>, <class 'django.contrib.gis.db.models.fields.MultiPointField'>: <class 'rest_framework_dso.fields.DSOGeometryField'>, <class 'django.contrib.gis.db.models.fields.MultiLineStringField'>: <class 'rest_framework_dso.fields.DSOGeometryField'>, <class 'django.contrib.gis.db.models.fields.MultiPolygonField'>: <class 'rest_framework_dso.fields.DSOGeometryField'>, <class 'django.contrib.gis.db.models.fields.GeometryCollectionField'>: <class 'rest_framework_dso.fields.DSOGeometryField'>}

Define that relations will also be generated as {“href”: …, “title”: …}.

alias of DSORelatedLinkField

serializer_url_field

alias of DSOSelfLinkField

url_field_name = 'self'
class rest_framework_dso.serializers.DSOSerializer(*args, **kwargs)

Bases: ExpandableSerializer, Serializer

Basic non-model serializer logic.

This class implements all logic that can be used by all serializers, including those which are not based on database models:

  • Geometry values are converted into a single coordinate reference system.

  • The ?_fields parameter can limit the returned fields.

  • request.response_content_crs is filled with the used CRS value.

The geometry values are transformed using the CRS object found in request.accept_crs.

__init__(*args, fields_to_display=None, **kwargs)
expanded_fields

Retrieve the embedded fields for this serializer

fields_always_included = {'_links'}
fields_param = '_fields'
property fields_to_display: FieldsToDisplay

Define which fields should be included only.

get_fields() dict[str, rest_framework.fields.Field]

Override DRF logic so fields can be removed from the response.

When looking deeper inside DRF logic, you’ll find that get_fields() makes a deepcopy of self._declared_fields. This approach allows making changes to the statically defined fields on this serializer instance. Only once all fields are created, the mapping is assigned to self.fields and field.bind() is called on each field. At that point, the fields know their own field name and serializer parent.

Omitting a field from the serializer is the most efficient way to avoid returning data, since the serializer won’t query/format the data at all. This may also avoid additional queries in case of relational fields.

get_valid_field_names(fields: dict[str, rest_framework.fields.Field]) set[str]

Tell which fields are valid to use in the ?_fields=.. query. This returns additional entries for relationships and expandable (virtual)fields, as these should not trigger error messages when those names are mentioned.

limit_return_fields(fields: dict[str, rest_framework.fields.Field]) dict[str, rest_framework.fields.Field]

Tell which fields should be included in the response. Any field that is omitted will not be outputted, nor queried.

classmethod many_init(*args, **kwargs)

The initialization for many=True.

This overrides the default list_serializer_class so it also returns HAL-style pagination and possibly embedding.

requires_context = True
to_representation(instance)

Check whether the geofields need to be transformed.

This method also sets request.response_content_crs so the response rendering can tell which Coordinate Reference System is used by all geometry fields.

class rest_framework_dso.serializers.ExpandableSerializer(*args, **kwargs)

Bases: BaseSerializer

A serializer class that handles ?_expand / ?_expandScope parameters.

This is a separate class because the parameter needs to be handled in 2 separate classes: DSOListSerializer and the regular DSOSerializer.

This class can be added as a mixin in case the serializer should be a ModelSerializer or ListSerializer.

__init__(*args, fields_to_expand=<class 'rest_framework.fields.empty'>, **kwargs)
expand_all_param = '_expand'
expand_field = '_embedded'
expand_param = '_expandScope'
property expand_scope: ExpandScope

Retrieve the requested expand. For the top-level serializer the request is parsed. Deeper nested serializers only return expand information when this is explicitly provided by their parent serializer.

property expanded_fields: list[rest_framework_dso.embedding.EmbeddedFieldMatch]

Retrieve the embedded fields for this request.

property field_name_prefix: str

For debugging, give the fully dotted field name.

classmethod get_embedded_field(field_name, prefix='') AbstractEmbeddedField

Retrieve an embedded field from the serializer class.

get_embedded_objects_by_id(embedded_field: AbstractEmbeddedField, id_list: list[Union[str, int]]) Union[QuerySet, Iterable[Model]]

Retrieve a number of embedded objects by their identifier.

While the embedded field typically collects the related objects by their primary key, the reverse and M2M field types use a custom identifier to find the related objects through a different/reverse relationship.

This method can be overwritten to support other means of object retrieval, e.g. fetching the objects from a remote endpoint. When an queryset is returned, it will be optimized to run most efficiently with relationships.

has_expand_scope_override() bool

Tell whether the ‘fields_to_expand’ is set by the code instead of request.

is_toplevel

Tell whether the current serializer is the top-level serializer. Nested serializers shouldn’t handle request-parsing logic.

class rest_framework_dso.serializers.HALRawIdentifierLinkSerializer(*args, **kwargs)

Bases: Serializer

Tagging interface to recognize serializers that don’t receive objects.

This is an empty class that is used to tag a ‘_links’ subfield that only receives a raw identifier as its ‘source’ value. This information is necessary to determine the runtime behavior, for example when resolving the prefetch lookups for a queryset.