Automatic nested serialization for OneToOneField

161 views
Skip to first unread message

Samuele Bonini

unread,
Jan 23, 2024, 10:17:57 AMJan 23
to Django REST framework
I came across some behavior that doesn't quite look right to me, and could possibly be a bug in the way Django REST treats automatic deep serialization.

The [depth argument](https://www.django-rest-framework.org/api-guide/serializers/#specifying-nested-serialization) of the ModelSerializer.Meta class is used to expand relations of the serialized models automatically.

It creates a NestedSerializer on the fly:

```
def build_nested_field(self, field_name, relation_info, nested_depth):
        """
        Create nested fields for forward and reverse relationships.
        """
        class NestedSerializer(ModelSerializer):
            class Meta:
                model = relation_info.related_model
                depth = nested_depth - 1
                fields = '__all__'

        field_class = NestedSerializer
        field_kwargs = get_nested_relation_kwargs(relation_info)

        return field_class, field_kwargs
```

This method is called on each relation field of the model, if the serializer has a `depth` parameter >0.

```
def build_field(self, field_name, info, model_class, nested_depth):
        """
        Return a two tuple of (cls, kwargs) to build a serializer field with.
        """
        if field_name in info.fields_and_pk:
            model_field = info.fields_and_pk[field_name]
            return self.build_standard_field(field_name, model_field)

        elif field_name in info.relations:
            relation_info = info.relations[field_name]
            if not nested_depth:
                return self.build_relational_field(field_name, relation_info)
            else:
                return self.build_nested_field(field_name, relation_info, nested_depth)

        # ...
```

The `info` object is obtained by calling this method:

```
def get_field_info(model):
    """
    Given a model class, returns a `FieldInfo` instance, which is a
    `namedtuple`, containing metadata about the various field types on the model
    including information about their relationships.
    """
    opts = model._meta.concrete_model._meta
   

    pk = _get_pk(opts)
    fields = _get_fields(opts)
    forward_relations = _get_forward_relationships(opts)
    reverse_relations = _get_reverse_relationships(opts)
    fields_and_pk = _merge_fields_and_pk(pk, fields)
    relationships = _merge_relationships(forward_relations, reverse_relations)

    return FieldInfo(pk, fields, forward_relations, reverse_relations,
                     fields_and_pk, relationships)
```

and the `_get_forward_relationships` method looks like this:

```
def _get_forward_relationships(opts):
    """
    Returns an `OrderedDict` of field names to `RelationInfo`.
    """
    forward_relations = OrderedDict()
    for field in [field for field in opts.fields if field.serialize and field.remote_field]:
        forward_relations[field.name] = RelationInfo(
            model_field=field,
            related_model=field.remote_field.model,
            to_many=False,
            to_field=_get_to_field(field),
            has_through_model=False,
            reverse=False
        )
    # ...
```

Apparently, the issue is that a OneToOne field has its `serialize` parameter set to False. As a result, it's not included in the `relations` dict and isn't expanded into a NestedSerializer, but just shown as a pk of the related object.

Is this the expected behavior? Shouldn't a OneToOne field behave like a ForeignKey, where the related object is serialized using a NestedSerializer?

Osama imran

unread,
Jan 23, 2024, 10:19:53 AMJan 23
to django-res...@googlegroups.com
Hello everyone
If anyone looking for expert python backend developer. I am available for full time. 

--
You received this message because you are subscribed to the Google Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-fram...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-rest-framework/c29c2c04-b101-4ea1-be5a-127c29f34506n%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages