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

Use primary serializers for nested object relationships #15278

Closed
jeremystretch opened this issue Feb 26, 2024 · 0 comments
Closed

Use primary serializers for nested object relationships #15278

jeremystretch opened this issue Feb 26, 2024 · 0 comments
Assignees
Labels
status: accepted This issue has been accepted for implementation type: housekeeping Changes to the application which do not directly impact the end user
Milestone

Comments

@jeremystretch
Copy link
Member

Proposed Changes

Following the work completed in #15235, it is no longer necessary to define separate nested serializers to represent related objects. We can instead pass an arbitrary list of fields to include when rendering the serialized object.

For example, the Site serializer currently utilizes nested serializers to display the region to which a site is assigned:

class SiteSerializer(NetBoxModelSerializer):
    region = NestedRegionSerializer(  # Nested serializer
        required=False,
        allow_null=True
)

Instead, we can use the primary serializers for each of these related models, passing the specific fields we want the nested representation to include:

class SiteSerializer(NetBoxModelSerializer):
    region = RegionSerializer(  # Primary serializer
        requested_fields=['id', 'url', 'display', 'name', 'slug'],
        required=False,
        allow_null=True
    )

Because the desired set of fields typically matches brief_fields set on the related serializer's Meta class, we can reference it directly. (Passing an arbitrary list of fields where necessary is still possible.)

class SiteSerializer(NetBoxModelSerializer):
    region = RegionSerializer(
        requested_fields=RegionSerializer.Meta.brief_fields,
        required=False,
        allow_null=True
    )

As this approach is a bit verbose, it would be prudent to provide a shortcut in the form of a designated keyword argument when initializing the serializer. For instance, we could pass nested=True to imply that only the serializer's brief_fields should be included. (This would be handled under the base serializer class' __init__() method.)

class SiteSerializer(NetBoxModelSerializer):
    region = RegionSerializer(
        nested=True,
        required=False,
        allow_null=True
    )

Although this change will obviate the need for many of the current nested serializers, IMO we should retain these in the code base for at least one release cycle, to provide a smooth migration path for plugins which may still utilize them.

Justification

This approach provides two substantial benefits. First, it obviates the need to maintain dedicated nested serializers solely for the purpose of representing related objects. For instance, NestedManufacturerSerializer exists only to represent the related manufacturer when viewing a device or module type. With the approach above, it is no longer needed.

Second, we can now include arbitrary fields for additional context. For instance, when representing the site to which a rack is assigned, we might want to include its rack_count, and when representing a device, instead include its device_count.

It's worth noting that this does not automatically negate the need for all nested serializers. There are at least two scenarios where separate serializers must be defined:

  • When representing recursive hierarchies. For example, RegionSerializer cannot be used to represent a region's parent region.
  • To avoid circular logic. For example, DeviceSerialzer must represent the virtual chassis to which a device is assigned (if any), yet VirtualChassisSerializer must also represent its master device. A nested serializer must be used in one direction or the other to resolve this circular logic.
@jeremystretch jeremystretch added status: accepted This issue has been accepted for implementation type: housekeeping Changes to the application which do not directly impact the end user labels Feb 26, 2024
@jeremystretch jeremystretch added this to the v4.0 milestone Feb 26, 2024
@jeremystretch jeremystretch added status: under review Further discussion is needed to determine this issue's scope and/or implementation and removed status: accepted This issue has been accepted for implementation labels Feb 26, 2024
@jeremystretch jeremystretch removed this from the v4.0 milestone Feb 26, 2024
@jeremystretch jeremystretch self-assigned this Feb 26, 2024
@jeremystretch jeremystretch added status: accepted This issue has been accepted for implementation and removed status: under review Further discussion is needed to determine this issue's scope and/or implementation labels Feb 26, 2024
@jeremystretch jeremystretch added this to the v4.0 milestone Feb 26, 2024
jeremystretch added a commit that referenced this issue Mar 5, 2024
…serializers

Closes #15278: Use primary serializers when representing nested objects
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jun 4, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
status: accepted This issue has been accepted for implementation type: housekeeping Changes to the application which do not directly impact the end user
Projects
None yet
Development

No branches or pull requests

1 participant