Add ability to set Schema fields through the serializer Meta class (#134)
* Add swagger_schema_fields attribute to serializer Meta class * Add documentation Closes #132.openapi3
parent
cc90bc1544
commit
256a052564
|
|
@ -3,6 +3,18 @@ Changelog
|
||||||
#########
|
#########
|
||||||
|
|
||||||
|
|
||||||
|
*********
|
||||||
|
**1.8.0**
|
||||||
|
*********
|
||||||
|
|
||||||
|
*Release date: Jun 01, 2018*
|
||||||
|
|
||||||
|
- **ADDED:** added a :ref:`swagger_schema_fields <swagger_schema_fields>` field on serializer ``Meta`` classes for
|
||||||
|
customizing schema generation
|
||||||
|
- **FIXED:** error responses from schema views are now rendered with ``JSONRenderer`` instead of throwing
|
||||||
|
confusing errors (:pr:`130`, :issue:`58`)
|
||||||
|
- **FIXED:** ``readOnly`` schema fields will now no longer be marked as ``required`` (:pr:`133`)
|
||||||
|
|
||||||
*********
|
*********
|
||||||
**1.7.4**
|
**1.7.4**
|
||||||
*********
|
*********
|
||||||
|
|
|
||||||
|
|
@ -169,13 +169,19 @@ You can define some per-serializer options by adding a ``Meta`` class to your se
|
||||||
class Meta:
|
class Meta:
|
||||||
... options here ...
|
... options here ...
|
||||||
|
|
||||||
Currently, the only option you can add here is
|
.. _swagger_schema_fields:
|
||||||
|
|
||||||
|
The available options are:
|
||||||
|
|
||||||
* ``ref_name`` - a string which will be used as the model definition name for this serializer class; setting it to
|
* ``ref_name`` - a string which will be used as the model definition name for this serializer class; setting it to
|
||||||
``None`` will force the serializer to be generated as an inline model everywhere it is used. If two serializers
|
``None`` will force the serializer to be generated as an inline model everywhere it is used. If two serializers
|
||||||
have the same ``ref_name``, both their usages will be replaced with a reference to the same definition.
|
have the same ``ref_name``, both their usages will be replaced with a reference to the same definition.
|
||||||
If this option is not specified, all serializers have an implicit name derived from their class name, minus any
|
If this option is not specified, all serializers have an implicit name derived from their class name, minus any
|
||||||
``Serializer`` suffix (e.g. ``UserSerializer`` -> ``User``, ``SerializerWithSuffix`` -> ``SerializerWithSuffix``)
|
``Serializer`` suffix (e.g. ``UserSerializer`` -> ``User``, ``SerializerWithSuffix`` -> ``SerializerWithSuffix``)
|
||||||
|
* ``swagger_schema_fields`` - a dictionary mapping :class:`.Schema` field names to values. These attributes
|
||||||
|
will be set on the :class:`.Schema` object generated from the ``Serializer``. Field names must be python values,
|
||||||
|
which are converted to Swagger ``Schema`` attribute names according to :func:`.make_swagger_name`.
|
||||||
|
Attribute names and values must conform to the `OpenAPI 2.0 specification <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#schemaObject>`_.
|
||||||
|
|
||||||
|
|
||||||
*************************
|
*************************
|
||||||
|
|
|
||||||
|
|
@ -22,12 +22,39 @@ class InlineSerializerInspector(SerializerInspector):
|
||||||
#: whether to output :class:`.Schema` definitions inline or into the ``definitions`` section
|
#: whether to output :class:`.Schema` definitions inline or into the ``definitions`` section
|
||||||
use_definitions = False
|
use_definitions = False
|
||||||
|
|
||||||
|
def add_manual_fields(self, serializer, schema):
|
||||||
|
"""Set fields from the ``swagger_schem_fields`` attribute on the serializer's Meta class. This method is called
|
||||||
|
only for serializers that are converted into ``openapi.Schema`` objects.
|
||||||
|
|
||||||
|
:param serializer: serializer instance
|
||||||
|
:param openapi.Schema schema: the schema object to be modified in-place
|
||||||
|
"""
|
||||||
|
serializer_meta = getattr(serializer, 'Meta', None)
|
||||||
|
swagger_schema_fields = getattr(serializer_meta, 'swagger_schema_fields', {})
|
||||||
|
if swagger_schema_fields:
|
||||||
|
for attr, val in swagger_schema_fields.items():
|
||||||
|
setattr(schema, attr, val)
|
||||||
|
|
||||||
def get_schema(self, serializer):
|
def get_schema(self, serializer):
|
||||||
return self.probe_field_inspectors(serializer, openapi.Schema, self.use_definitions)
|
result = self.probe_field_inspectors(serializer, openapi.Schema, self.use_definitions)
|
||||||
|
schema = openapi.resolve_ref(result, self.components)
|
||||||
|
self.add_manual_fields(serializer, schema)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def add_manual_parameters(self, serializer, parameters):
|
||||||
|
"""Add/replace parameters from the given list of automatically generated request parameters. This method
|
||||||
|
is called only when the serializer is converted into a list of parameters for use in a form data request.
|
||||||
|
|
||||||
|
:param serializer: serializer instance
|
||||||
|
:param list[openapi.Parameter] parameters: genereated parameters
|
||||||
|
:return: modified parameters
|
||||||
|
:rtype: list[openapi.Parameter]
|
||||||
|
"""
|
||||||
|
return parameters
|
||||||
|
|
||||||
def get_request_parameters(self, serializer, in_):
|
def get_request_parameters(self, serializer, in_):
|
||||||
fields = getattr(serializer, 'fields', {})
|
fields = getattr(serializer, 'fields', {})
|
||||||
return [
|
parameters = [
|
||||||
self.probe_field_inspectors(
|
self.probe_field_inspectors(
|
||||||
value, openapi.Parameter, self.use_definitions,
|
value, openapi.Parameter, self.use_definitions,
|
||||||
name=self.get_parameter_name(key), in_=in_
|
name=self.get_parameter_name(key), in_=in_
|
||||||
|
|
@ -36,12 +63,17 @@ class InlineSerializerInspector(SerializerInspector):
|
||||||
in fields.items()
|
in fields.items()
|
||||||
]
|
]
|
||||||
|
|
||||||
|
return self.add_manual_parameters(serializer, parameters)
|
||||||
|
|
||||||
def get_property_name(self, field_name):
|
def get_property_name(self, field_name):
|
||||||
return field_name
|
return field_name
|
||||||
|
|
||||||
def get_parameter_name(self, field_name):
|
def get_parameter_name(self, field_name):
|
||||||
return field_name
|
return field_name
|
||||||
|
|
||||||
|
def get_serializer_ref_name(self, serializer):
|
||||||
|
return get_serializer_ref_name(serializer)
|
||||||
|
|
||||||
def field_to_swagger_object(self, field, swagger_object_type, use_references, **kwargs):
|
def field_to_swagger_object(self, field, swagger_object_type, use_references, **kwargs):
|
||||||
SwaggerType, ChildSwaggerType = self._get_partial_types(field, swagger_object_type, use_references, **kwargs)
|
SwaggerType, ChildSwaggerType = self._get_partial_types(field, swagger_object_type, use_references, **kwargs)
|
||||||
|
|
||||||
|
|
@ -55,7 +87,7 @@ class InlineSerializerInspector(SerializerInspector):
|
||||||
if swagger_object_type != openapi.Schema:
|
if swagger_object_type != openapi.Schema:
|
||||||
raise SwaggerGenerationError("cannot instantiate nested serializer as " + swagger_object_type.__name__)
|
raise SwaggerGenerationError("cannot instantiate nested serializer as " + swagger_object_type.__name__)
|
||||||
|
|
||||||
ref_name = get_serializer_ref_name(field)
|
ref_name = self.get_serializer_ref_name(field)
|
||||||
|
|
||||||
def make_schema_definition():
|
def make_schema_definition():
|
||||||
properties = OrderedDict()
|
properties = OrderedDict()
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework_recursive.fields import RecursiveField
|
from rest_framework_recursive.fields import RecursiveField
|
||||||
|
|
@ -26,6 +28,15 @@ class TodoYetAnotherSerializer(serializers.ModelSerializer):
|
||||||
model = TodoYetAnother
|
model = TodoYetAnother
|
||||||
fields = ('title', 'todo')
|
fields = ('title', 'todo')
|
||||||
depth = 2
|
depth = 2
|
||||||
|
swagger_schema_fields = {
|
||||||
|
'example': OrderedDict([
|
||||||
|
('title', 'parent'),
|
||||||
|
('todo', OrderedDict([
|
||||||
|
('title', 'child'),
|
||||||
|
('todo', None),
|
||||||
|
])),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class TodoTreeSerializer(serializers.ModelSerializer):
|
class TodoTreeSerializer(serializers.ModelSerializer):
|
||||||
|
|
|
||||||
|
|
@ -1578,6 +1578,11 @@ definitions:
|
||||||
minLength: 1
|
minLength: 1
|
||||||
readOnly: true
|
readOnly: true
|
||||||
readOnly: true
|
readOnly: true
|
||||||
|
example:
|
||||||
|
title: parent
|
||||||
|
todo:
|
||||||
|
title: child
|
||||||
|
todo: null
|
||||||
UserSerializerrr:
|
UserSerializerrr:
|
||||||
required:
|
required:
|
||||||
- username
|
- username
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue