Address PR feedback

This commit is contained in:
Jeremy Stretch
2026-01-28 13:59:22 -05:00
parent af46bbaed3
commit 4f1ee383af
3 changed files with 27 additions and 18 deletions

View File

@@ -250,13 +250,16 @@ Similarly, you can opt to omit only specific fields by passing the `omit` parame
GET /api/dcim/sites/?omit=circuit_count,device_count,virtualmachine_count
```
!!! note "The `omit` paramater was introduced in NetBox v4.5.2."
!!! note "The `omit` parameter was introduced in NetBox v4.5.2."
Strategic use of the `fields` and `omit` parameters can drastically improve REST API performance, as the exclusion of fields which reference related objects reduces the number and compelxity of underlying database queries needed to generate the response.
Strategic use of the `fields` and `omit` parameters can drastically improve REST API performance, as the exclusion of fields which reference related objects reduces the number and complexity of underlying database queries needed to generate the response.
!!! note
The `fields` and `omit` parameters should be considered mutually exclusive. If both are passed, `fields` takes precedence.
#### Brief Format
Most API endpoints support an optional "brief" format, which returns only a minimal representation of each object in the response. This is useful when you need only a list of available objects without any related data, such as when populating a drop-down list in a form. It's also more convenient than listing out individual fileds via the `fields` or `omit` parameters. As an example, the default (complete) format of a prefix looks like this:
Most API endpoints support an optional "brief" format, which returns only a minimal representation of each object in the response. This is useful when you need only a list of available objects without any related data, such as when populating a drop-down list in a form. It's also more convenient than listing out individual fields via the `fields` or `omit` parameters. As an example, the default (complete) format of a prefix looks like this:
```no-highlight
GET /api/ipam/prefixes/13980/

View File

@@ -1,9 +1,8 @@
from functools import cached_property
from rest_framework import serializers
from rest_framework.utils.serializer_helpers import BindingDict
from drf_spectacular.utils import extend_schema_field
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import extend_schema_field
from rest_framework import serializers
from utilities.api import get_related_object_by_attrs
from .fields import NetBoxAPIHyperlinkedIdentityField, NetBoxURLHyperlinkedIdentityField
@@ -26,9 +25,11 @@ class BaseModelSerializer(serializers.ModelSerializer):
:param nested: Set to True if this serializer is being employed within a parent serializer
:param fields: An iterable of fields to include when rendering the serialized object, If nested is
True but no fields are specified, Meta.brief_fields will be used.
:param omit: An iterable of fields to omit from the serialized object
"""
self.nested = nested
self._requested_fields = fields
self._include_fields = fields or []
self._omit_fields = omit or []
# Disable validators for nested objects (which already exist)
if self.nested:
@@ -36,8 +37,8 @@ class BaseModelSerializer(serializers.ModelSerializer):
# If this serializer is nested but no fields have been specified,
# default to using Meta.brief_fields (if set)
if self.nested and not fields:
self._requested_fields = getattr(self.Meta, 'brief_fields', None)
if self.nested and not fields and not omit:
self._include_fields = getattr(self.Meta, 'brief_fields', None)
super().__init__(*args, **kwargs)
@@ -63,16 +64,20 @@ class BaseModelSerializer(serializers.ModelSerializer):
@cached_property
def fields(self):
"""
Override the fields property to check for requested fields. If defined,
return only the applicable fields.
Override the fields property to return only specifically requested fields if needed.
"""
if not self._requested_fields:
return super().fields
fields = super().fields
# Include only requested fields
if self._include_fields:
fields = {
k: v for k, v in fields.items() if k in self._include_fields
}
# Remove omitted fields
for field_name in set(self._omit_fields):
fields.pop(field_name, None)
fields = BindingDict(self)
for key, value in self.get_fields().items():
if key in self._requested_fields:
fields[key] = value
return fields
@extend_schema_field(OpenApiTypes.STR)

View File

@@ -5,13 +5,13 @@ from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django.db import router, transaction
from django.db.models import ProtectedError, RestrictedError
from django_pglocks import advisory_lock
from netbox.constants import ADVISORY_LOCK_KEYS
from rest_framework import mixins as drf_mixins
from rest_framework import status
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet
from netbox.api.serializers.features import ChangeLogMessageSerializer
from netbox.constants import ADVISORY_LOCK_KEYS
from utilities.api import get_annotations_for_serializer, get_prefetches_for_serializer
from utilities.exceptions import AbortRequest
from utilities.query import reapply_model_ordering
@@ -75,6 +75,7 @@ class BaseViewSet(GenericViewSet):
@cached_property
def field_kwargs(self):
"""Return a dictionary of keyword arguments to be passed when instantiating the serializer."""
# An explicit list of fields was requested
if requested_fields := self.request.query_params.get('fields'):
return {'fields': requested_fields.split(',')}