Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for nested metadata representation of nested serializers #2915

Closed
Ernest0x opened this issue May 7, 2015 · 11 comments
Closed

Support for nested metadata representation of nested serializers #2915

Ernest0x opened this issue May 7, 2015 · 11 comments

Comments

@Ernest0x
Copy link
Contributor

Ernest0x commented May 7, 2015

Currently, the representation of metadata done with SimpleMetadata class for a serializer that includes nested serializers does not include metadata for the inner fields of the nested serializers. To support the inclusion of nested serializer's inner fields metadata in the representation, I wrote pull request #2911, which works like this:

  • introduces the 'serializer' type for fields that are nested serializers
  • introduces a 'fields' attribute for fields that are nested serializers, which contains a key/value structure:
    • keys are the field names of the nested serializer
    • values are the metadata representation of the nested serializer's fields

The above will work for nested serializers of arbitrary depth.

However, @tomchristie suggested that a discussion is first opened before going that way, as there may be other ways to represent this. So, let's start this discussion.

@tomchristie
Copy link
Member

tomchristie commented May 7, 2015

So, right place to start would be: provide simplest possible example, and show:

  • What the current OPTIONS output currently is.
  • What you'd propose to output instead.

@tomchristie
Copy link
Member

tomchristie commented May 7, 2015

(I realize that there's a similar description here, but it'd be good to have an example case laid out)

@Ernest0x
Copy link
Contributor Author

Ernest0x commented May 7, 2015

Sure.

Consider the following serializers:

class NestedSerializer(serializers.Serializer):
    some_text = serializers.CharField(max_length=100)
    another_text = serializers.CharField(max_length=100)

class RootSerializer(serializers.Serializer):
    nest = NestedSerializer()
    some_note = serializers.CharField(max_length=100)
    another_note = serializers.CharField(max_length=100)

And a view like this:

class RootList(generics.ListCreateAPIView):
    queryset = Root.objects.all()
    serializer_class = RootSerializer
    metadata_class = SimpleMetadata

As it is now, the representation of metadata in an OPTIONS request looks like this:

{
    "name": "Root List",
    "description": "List existing 'Root' items, or create a new item.",
    "renders": [
        "application/json",
        "text/html"
    ],
    "parses": [
        "application/json",
        "application/x-www-form-urlencoded",
        "multipart/form-data"
    ],
    "actions": {
        "POST": {
            "nest": {
                "type": "field",
                "required": true,
                "read_only": false,
                "label": "nest"
            },
            "some_note": {
                "type": "string",
                "required": true,
                "read_only": false,
                "label": "some note",
                "max_length": 100
            },
            "another_note": {
                "type": "string",
                "required": true,
                "read_only": false,
                "label": "another note",
                "max_length": 100
            }
        }
    }
}

With my suggestion, the representation of metadata in an OPTIONS request will look like this:

{
    "name": "Root List",
    "description": "List existing 'Root' items, or create a new item.",
    "renders": [
        "application/json",
        "text/html"
    ],
    "parses": [
        "application/json",
        "application/x-www-form-urlencoded",
        "multipart/form-data"
    ],
    "actions": {
        "POST": {
            "nest": {
                "type": "serializer",
                "required": true,
                "read_only": false,
                "label": "nest",
                "fields": {
                     "some_text": {
                         "type": "string",
                         "required": true,
                         "read_only": false,
                         "label": "some text",
                         "max_length": 100
                     },
                     "another_text": {
                         "type": "string",
                         "required": true,
                         "read_only": false,
                         "label": "another text",
                         "max_length": 100
                     }
                }
            },
            "some_note": {
                "type": "string",
                "required": true,
                "read_only": false,
                "label": "some note",
                "max_length": 100
            },
            "another_note": {
                "type": "string",
                "required": true,
                "read_only": false,
                "label": "another note",
                "max_length": 100
            }
        }
    }
}

As you can see, with my suggestion, metadata for the fields of the 'nest' field is included in the representation. So, you are getting the whole picture.

@tomchristie
Copy link
Member

tomchristie commented May 7, 2015

Thought: "type": "object" might be more valid that "type": "serializer".
That'd be more of a data description, rather than an implementation description.

Also, how would we handle serializers with many = True?

@Ernest0x
Copy link
Contributor Author

Ernest0x commented May 11, 2015

Thought: "type": "object" might be more valid that "type": "serializer".
That'd be more of a data description, rather than an implementation description.

I agree.

Also, how would we handle serializers with many = True?

In that case, I suggest the metadata object be encapsulated in a list.

For example, with the following serializers:

class NestedSerializer(serializers.Serializer):
    some_text = serializers.CharField(max_length=100)
    another_text = serializers.CharField(max_length=100)

class RootSerializer(serializers.Serializer):
    nests = NestedSerializer(many=True)
    some_note = serializers.CharField(max_length=100)
    another_note = serializers.CharField(max_length=100)

the root serializer would have its metadata represented like this:

{
    "name": "Root List",
    "description": "List existing 'Root' items, or create a new item.",
    "renders": [
        "application/json",
        "text/html"
    ],
    "parses": [
        "application/json",
        "application/x-www-form-urlencoded",
        "multipart/form-data"
    ],
    "actions": {
        "POST": {
            "nests": [
                {
                    "type": "object",
                    "required": true,
                    "read_only": false,
                    "label": "nest",
                    "fields": {
                        "some_text": {
                            "type": "string",
                            "required": true,
                            "read_only": false,
                            "label": "some text",
                            "max_length": 100
                        },
                        "another_text": {
                            "type": "string",
                            "required": true,
                            "read_only": false,
                            "label": "another text",
                            "max_length": 100
                        }
                    }
                }
            ],
            "some_note": {
                "type": "string",
                "required": true,
                "read_only": false,
                "label": "some note",
                "max_length": 100
            },
            "another_note": {
                "type": "string",
                "required": true,
                "read_only": false,
                "label": "another note",
                "max_length": 100
            }

        }
    }
}

What do you think?

@Cediddi
Copy link

Cediddi commented Jul 7, 2015

Hi, I'm interested in this topic. In case a child serializer is many=true, we should add a flag to the output, like this:

"nest": {
                "type": "serializer",
                "required": true,
                "many": true,
                "read_only": false,
                "label": "nest",
                "fields": {
                     .........
                }
            },

@tomchristie
Copy link
Member

tomchristie commented Jul 7, 2015

We now support nested lists/many #3104 (but not yet nested serializers/mappings)

@catskul
Copy link

catskul commented Jul 14, 2015

I just ran into this issue as well.

catskul added a commit to HireAnEsquire/django-rest-framework that referenced this issue Jul 16, 2015
catskul added a commit to HireAnEsquire/django-rest-framework that referenced this issue Jul 16, 2015
push serialzer metadata into field info for field re encode#2915
@tomchristie
Copy link
Member

tomchristie commented Jul 16, 2015

Accepting this issue.

@tomchristie tomchristie added this to the 3.1.4 Release milestone Jul 16, 2015
@tomchristie
Copy link
Member

tomchristie commented Jul 16, 2015

Now resolved.

Eg:

OPTIONS request for serializer class containing this field...

nested_field = NestedField()

And this:

       class NestedField(serializers.Serializer):
           a = serializers.IntegerField()
           b = serializers.IntegerField()

Will include this in the OPTIONS output

                    'nested_field': {
                        'type': 'nested object',
                        'required': True,
                        'read_only': False,
                        'label': 'Nested field',
                        'children': {
                            'a': {
                                'type': 'integer',
                                'required': True,
                                'read_only': False,
                                'label': 'A'
                            },
                            'b': {
                                'type': 'integer',
                                'required': True,
                                'read_only': False,
                                'label': 'B'
                            }
                        }
                    }

@catskul
Copy link

catskul commented Jul 16, 2015

Awesome! Thanks! : )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants