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

Annotate related objects counts on a REST API queryset only when the field is active on the serializer #15131

Closed
jeremystretch opened this issue Feb 13, 2024 · 1 comment
Assignees
Labels
status: accepted This issue has been accepted for implementation type: feature Introduction of new functionality to the application
Milestone

Comments

@jeremystretch
Copy link
Member

jeremystretch commented Feb 13, 2024

NetBox version

v3.7.2

Feature type

New functionality

Proposed functionality

Many REST API endpoints annotate the count of certain related objects. For example, the sites endpoint includes counts for assigned racks, devices, racks, etc.:

{
    ...
    "circuit_count": 1,
    "device_count": 2,
    "prefix_count": 0,
    "rack_count": 1,
    "virtualmachine_count": 0,
    "vlan_count": 0
}

These values are annotated on the queryset statically under the view class:

class SiteViewSet(NetBoxModelViewSet):
    queryset = Site.objects.annotate(
        device_count=count_related(Device, 'site'),
        rack_count=count_related(Rack, 'site'),
        prefix_count=count_related(Prefix, 'site'),
        vlan_count=count_related(VLAN, 'site'),
        circuit_count=count_related(Circuit, 'terminations__site'),
        virtualmachine_count=count_related(VirtualMachine, 'cluster__site')
    )

This issue proposes moving these annotations to the serializer class, effected as discrete fields which can be optionally included or omitted per the new functionality being introduced under #15087. (The current counts are retained by default to preserve existing behavior, but are omitted when the API client has requested a specific subset of fields which does not include the related object counts.)

This will require the introduction of a new field type which can be employed to automatically attach an annotation to the underlying queryset (similar to how we prefetch only relevant fields under #15087). I imagine something like this:

class SiteSerializer(NetBoxModelSerializer):
    ...
    rack_count = ObjectCountField(model='dcim.Rack', related_field='site')
    device_count = ObjectCountField(model='dcim.Device', related_field='site')
    circuit_count = ObjectCountField(model='circuits.Circuit', related_field='terminations__site')

The view class will likely need to be extended to automatically annotate the queryset for ObjectCountFields which are included for the request.

Use case

Moving these annotations to a serializer class and annotating their values only when necessary will greatly optimize the underlying querysets.

For instance, the devices list currently annotates counts for six different related object types: racks, devices, prefixes, VLANs, circuits, and virtual machines. These annotations are always computed and attached to the API results, even if their respective values are not conveyed in the response (due to the use of brief mode or because a subset of fields was requested). This can lead to significant unnecessary overhead when dealing with large numbers of objects.

Database changes

None; this change does not impact the underlying database schema in anyway, just the manner in which object relations are queried.

External dependencies

None

@jeremystretch jeremystretch added type: feature Introduction of new functionality to the application status: under review Further discussion is needed to determine this issue's scope and/or implementation labels Feb 13, 2024
@jeremystretch jeremystretch self-assigned this Feb 13, 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 13, 2024
@jeremystretch jeremystretch added this to the v4.0 milestone Feb 13, 2024
@jeremystretch
Copy link
Member Author

Tagging this for v4.0 as it will provide ancillary benefit to FR #15087

jeremystretch added a commit that referenced this issue Feb 15, 2024
…15152)

* Introduce RelatedObjectCountField

* Introduce get_annotations_for_serializer() and enable dynamic annotations

* Add RelatedObjectCountFields to serializers; remove static annotations from querysets

* Remove annotations cleanup logic from BriefModeMixin

* Annotate type for RelatedObjectCountField

* Remove redundant field on TagSerializer

* Add missing reverse relationship for power feeds to rack

* Refactor RelatedObjectCountField to take a single relationship name
@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 16, 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: feature Introduction of new functionality to the application
Projects
None yet
Development

No branches or pull requests

1 participant