drf_openapi
drf_openapi copied to clipboard
Nested serializer fields aren't described in the request body
- DRF OpenAPI version: 1.3.0
- Python version: 3.6.2
- Operating System: Ubuntu 16.04
Description
If main serializer has any nested serializers except ListSerializer (it's handled correctly), fields of this sub-serializers doesn't shown on html page with api description.
What I Did
class PersonSerializer(serializers.Serializer):
first_name = serializers.CharField()
last_name = serializers.CharField()
class DocumentSerializer(serializers.Serializer):
doc_type= serializers.IntegerField()
number = serializers.CharField()
class CheckDocRequestSerializer(serializers.Serializer):
person = PersonSerializer()
documents = serializers.ListField(child=DocumentSerializer())
Main serializer is CheckDocRequestSerializer
and in this case fields doc_type
, number
will be shown for DocumentSerializer
but PersonSerializer
will be described as object
without any sub-elements.
"Request example":
{
"person": {},
"documents": [
{
"doc_type": 0,
"number": "string"
}
]
}
I prepared code fixing (presumably) this issue. You can test it by installing pip install --upgrade git+https://github.com/jar3b/drf_openapi.git@issue_113
, code is here. If this works then i can create a PR.
That's great news, I'll give it a try
Thanks for looking into this unfortunately it doesn't seem to be working for me. I used the serializer below as the request_serializer and response_serializer and got the following JSON
SERIALIZER
class DummySerializer(serializers.Serializer):
class class1(serializers.Serializer):
class class1subclass(serializers.Serializer):
myNumber = serializers.FloatField()
myChar = serializers.CharField()
myInt = serializers.IntegerField()
singleItem = class1subclass()
multiItem = class1subclass(many=True)
myNumber = serializers.FloatField()
myChar = serializers.CharField()
myInt = serializers.IntegerField()
singleItem = class1()
multiItem = class1(many=True)
myNumber = serializers.FloatField()
myChar = serializers.CharField()
myInt = serializers.IntegerField()
REQUEST
{
"myNumber": 0,
"myChar": "string",
"multiItem": [
{
"myNumber": 0,
"myChar": "string",
"multiItem": [],
"myInt": 0,
"singleItem": {}
}
],
"myInt": 0,
"singleItem": {
"myNumber": 0,
"myChar": "string",
"multiItem": [],
"myInt": 0,
"singleItem": {}
}
}
RESPONSE
{
"myNumber": 0,
"myChar": "string",
"multiItem": [
{
"myNumber": 0,
"myChar": "string",
"multiItem": [],
"myInt": 0,
"singleItem": {}
}
],
"myInt": 0,
"singleItem": {
"myNumber": 0,
"myChar": "string",
"multiItem": [
{
"myNumber": 0,
"myChar": "string",
"myInt": 0
}
],
"myInt": 0,
"singleItem": {
"myNumber": 0,
"myChar": "string",
"myInt": 0
}
}
}
Unfortunately i've not tested serializers with more than one nesting level. I made an update for handling this and put it in same branch.
Some features / bugs of updated solution:
- If request method is 'PATCH', top-level properties have
required=False
(because of PATCH method doesn't requires all fields to be specified), but properties of nested objects (2nd and more level) have arequired
flag depending on what is specified in the serializer, not necessarilyFalse
. - Visual representation of object type (
"object"
string in most cases) is overwritten with the field name (for example:singleItem Required
instead ofobject Required
), i don't know whether this is a planned behavior or not.
Example view and serializer:
class DummySerializer(serializers.Serializer):
class class1(serializers.Serializer):
class class1subclass(serializers.Serializer):
myNumber = serializers.FloatField(help_text='a1')
myChar = serializers.CharField(help_text='b1', required=False)
myInt = serializers.IntegerField(help_text='c1')
singleItem = class1subclass(help_text='single2')
multiItem = class1subclass(many=True, help_text='multi2')
myNumber = serializers.FloatField()
myChar = serializers.CharField()
myInt = serializers.IntegerField(required=False)
singleItem = class1(help_text='single3')
multiItem = class1(many=True, help_text='multi3')
myNumber = serializers.FloatField(required=False)
myChar = serializers.CharField()
myInt = serializers.IntegerField()
class TestView(APIView):
"""
TEST
"""
permission_classes = (IsAuthenticated,)
serializer_class = DummySerializer
@view_config(response_serializer=DummySerializer, request_serializer=DummySerializer)
def post(self, request, version, format=None):
return Response(data={})
Request example
{
"singleItem": {
"singleItem": {
"myNumber": 0,
"myChar": "string",
"myInt": 0
},
"multiItem": [
{
"myNumber": 0,
"myChar": "string",
"myInt": 0
}
],
"myNumber": 0,
"myChar": "string",
"myInt": 0
},
"multiItem": [
{
"singleItem": {
"myNumber": 0,
"myChar": "string",
"myInt": 0
},
"multiItem": [
{
"myNumber": 0,
"myChar": "string",
"myInt": 0
}
],
"myNumber": 0,
"myChar": "string",
"myInt": 0
}
],
"myNumber": 0,
"myChar": "string",
"myInt": 0
}
Response example
{
"multiItem": [
{
"singleItem": {
"myNumber": 0,
"myChar": "string",
"myInt": 0
},
"multiItem": [
{
"myNumber": 0,
"myChar": "string",
"myInt": 0
}
],
"myNumber": 0,
"myChar": "string",
"myInt": 0
}
],
"myNumber": 0,
"myChar": "string",
"myInt": 0,
"singleItem": {
"multiItem": [
{
"myNumber": 0,
"myChar": "string",
"myInt": 0
}
],
"myNumber": 0,
"myChar": "string",
"myInt": 0,
"singleItem": {
"myNumber": 0,
"myChar": "string",
"myInt": 0
}
}
}
Fantastic! Works really well. Thanks you so much!
I updated the code, new features is:
- support for
max_length
,min_length
- support for enums (ChoiceField)
- support
format
for string values (date, datetime)
example request view
request example
{
"singleItem": {
"myIntEnum": 1,
"myStringEnum": "FOO",
"myBooleanEnum": true,
"myMixedEnum": true,
"myFloatEnum": 1.4
},
"multiItem": [
{
"myIntEnum": 1,
"myStringEnum": "FOO",
"myBooleanEnum": true,
"myMixedEnum": true,
"myFloatEnum": 1.4
}
],
"myChar1": "stringstri",
"myChar2": "string",
"myDateTime": "2018-01-26T08:06:47Z",
"myDate": "2018-01-26"
}
and serializer:
class DummySerializer2(serializers.Serializer):
class class1(serializers.Serializer):
myIntEnum = serializers.ChoiceField(choices=[1,2,3])
myStringEnum = serializers.ChoiceField(choices=["FOO", "BAR"])
myBooleanEnum = serializers.ChoiceField(choices=[True, False])
myMixedEnum = serializers.ChoiceField(choices=[True, 2, "123"])
myFloatEnum = serializers.ChoiceField(choices=[1.4, 2.4, 2.766])
singleItem = class1(help_text='single item')
multiItem = class1(many=True, help_text='multi item')
myChar1 = serializers.CharField(min_length=10, max_length=255)
myChar2 = serializers.CharField(max_length=255)
myDateTime = serializers.DateTimeField()
myDate = serializers.DateField()
i push in same branch because this feature set depends on original issue (nested field inspections)