Open webjunkie opened 5 years ago
I solved this now in a same fashion as suggested in https://github.com/axnsan12/drf-yasg/issues/92#issuecomment-378539214
Here is a sample:
class HalModelSerializerInspector(FieldInspector):
def process_result(self, result: openapi.Schema, method_name: str, obj: Serializer,
**kwargs: Dict[Any, Any]) -> openapi.Schema:
if isinstance(obj, serializers.HalModelSerializer) and method_name == 'field_to_swagger_object':
model_response = self.formatted_model_result(result, obj)
if obj.parent is None and self.view.action != 'list':
# It will be top level object not in list, decorate with data
return model_response
return model_response
return result
@staticmethod
def generate_link(field: Field) -> Tuple[str, openapi.Schema]:
field_schema = openapi.Schema(
title='Relationship object',
type=openapi.TYPE_OBJECT,
properties=OrderedDict((
('href', openapi.Schema(
type=openapi.TYPE_STRING,
title='Link to related resource',
)),
))
)
return field.field_name, field_schema
@staticmethod
def _is_link_field(field: Field) -> bool:
# ManyRelatedField could wrap any type so we need to analyze the underlying type
if isinstance(field, ManyRelatedField):
field = field.child_relation
return isinstance(field, serializers.HalIncludeInLinksMixin)
@staticmethod
def _is_embedded_field(field: Field) -> bool:
return isinstance(field, BaseSerializer)
@staticmethod
def grab_fields_from_schema(field_names: Set[str], schema: openapi.Schema,
title: str) -> Optional[openapi.Schema]:
subset_fields = [(key, val) for key, val in schema.properties.items() if key in field_names]
if subset_fields:
return openapi.Schema(title=title, type=openapi.TYPE_OBJECT, properties=OrderedDict(subset_fields))
return None
def generate_links(self, obj: Serializer) -> Optional[openapi.Schema]:
relationships_properties = []
for field in obj.fields.values():
if self._is_link_field(field):
relationships_properties.append(self.generate_link(field))
if relationships_properties:
return openapi.Schema(
title='Relationships of object',
type=openapi.TYPE_OBJECT,
properties=OrderedDict(relationships_properties),
)
return None
def formatted_model_result(self, result: openapi.Schema, obj: Serializer) -> openapi.Schema:
schema = openapi.resolve_ref(result, self.components)
field_names_embeds = set(p for p in obj.fields.keys() if self._is_embedded_field(obj.fields[p]))
field_names_links = set(p for p in obj.fields.keys() if self._is_link_field(obj.fields[p]))
if getattr(schema, 'properties', {}):
real_properties = OrderedDict(
(key, val)
for key, val in schema.properties.items() if key not in field_names_embeds | field_names_links
)
embeds = self.grab_fields_from_schema(field_names=field_names_embeds, schema=schema,
title='Embedded objects')
if embeds:
real_properties.update({'_embedded': embeds})
real_properties.move_to_end('_embedded', last=False)
links = self.generate_links(obj)
if links:
real_properties.update({'_links': links})
real_properties.move_to_end('_links', last=False)
schema.properties = real_properties
if getattr(schema, 'required', []):
req = list(filter(lambda x: x not in field_names_embeds | field_names_links, schema.required))
if req:
schema.required = req
return result
How would you add compatibility between the two libraries?
I co-maintain Artory/drf-hal-json, so we could add the inspectors there?
How would you add compatibility between the two libraries?
I co-maintain Artory/drf-hal-json, so we could add the inspectors there?
I'm not generally opposed to adding third-party specific glue code (see djangorestframework-camel-case and django-rest-framework-recursive).
However, it's probably best to have it in your codebase, so any functional changes can be kept in sync with the schema.
I'm using https://github.com/Artory/drf-hal-json/ that basically provides custom base serializers that add dynamically fields like
_links
into the response via theto_representation
method.I tried to somehow get that into the schema as well, but I'm getting stuck. Are there any directions on what I need to provide/subclass/overwrite, so to make it work?
I imagine I could inspect my serializer objects, since they have a property which dynamic fields need to be added the the schema.
Any help or ideas where to look would be appreciated. Thanks!