Source code for aiohttp_json_api.fields.relationships
"""
Relationships
=============
"""
import typing
from collections import Mapping, OrderedDict
from .base import Relationship
from ..common import Relation
from ..errors import InvalidType
from ..helpers import is_collection
__all__ = (
'ToOne',
'ToMany',
)
[docs]class ToOne(Relationship):
"""
.. seealso::
* http://jsonapi.org/format/#document-resource-object-relationships
* http://jsonapi.org/format/#document-resource-object-linkage
Describes how to serialize, deserialize and update a *to-one* relationship.
"""
relation = Relation.TO_ONE
[docs] def validate_relationship_object(self, schema, data, sp):
"""
Checks additionaly to :meth:`Relationship.validate_relationship_object`
that the *data* member is a valid resource linkage.
"""
super(ToOne, self).validate_relationship_object(schema, data, sp)
if 'data' in data and data['data'] is not None:
self.validate_resource_identifier(schema, data['data'],
sp / 'data')
[docs] def serialize(self, schema, data, **kwargs) -> typing.MutableMapping:
"""Composes the final relationships object."""
document = OrderedDict()
if data is None:
document['data'] = data
elif isinstance(data, Mapping):
# JSON API resource linkage or JSON API relationships object
if 'type' in data and 'id' in data:
document['data'] = data
else:
# the related resource instance
document['data'] = \
schema.ctx.registry.ensure_identifier(data, asdict=True)
links = kwargs.get('links')
if links is not None:
document['links'] = links
return document
[docs]class ToMany(Relationship):
"""
.. seealso::
* http://jsonapi.org/format/#document-resource-object-relationships
* http://jsonapi.org/format/#document-resource-object-linkage
Describes how to serialize, deserialize and update a *to-many*
relationship. Additionally to *to-one* relationships, *to-many*
relationships must also support adding and removing relatives.
:arg aiohttp_json_api.pagination.PaginationABC pagination:
The pagination helper *class* used to paginate the *to-many*
relationship.
"""
relation = Relation.TO_MANY
def __init__(self, *, pagination=None, **kwargs):
super(ToMany, self).__init__(**kwargs)
self.pagination = pagination
[docs] def serialize(self, schema, data, links=None, pagination=None,
**kwargs) -> typing.MutableMapping:
"""Composes the final JSON API relationships object.
:arg ~aiohttp_json_api.pagination.PaginationABC pagination:
If not *None*, the links and meta members of the pagination
helper are added to the final JSON API relationship object.
"""
document = OrderedDict()
if is_collection(data):
document['data'] = [
schema.ctx.registry.ensure_identifier(item, asdict=True)
for item in data
]
if links is not None:
document['links'] = links
if pagination is not None:
document['links'].update(pagination.links())
document.setdefault('meta', OrderedDict())
document['meta'].update(pagination.meta())
return document
[docs] def validate_relationship_object(self, schema, data, sp):
"""
Checks additionaly to :meth:`Relationship.validate_relationship_object`
that the *data* member is a list of resource identifier objects.
"""
super(ToMany, self).validate_relationship_object(schema, data, sp)
if 'data' in data and not is_collection(data['data']):
detail = 'The "data" must be an array ' \
'of resource identifier objects.'
raise InvalidType(detail=detail, source_pointer=sp / 'data')
for i, item in enumerate(data['data']):
self.validate_resource_identifier(schema, item, sp / 'data' / i)