From 3bd28e2efe9d39d9992245c955d406c77b519e4b Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Fri, 1 Mar 2024 10:18:58 -0500 Subject: [PATCH] Improve serializer initialization performance --- netbox/netbox/api/serializers/base.py | 36 +++++++++++++++++++++------ 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/netbox/netbox/api/serializers/base.py b/netbox/netbox/api/serializers/base.py index bad53144e..4445f62da 100644 --- a/netbox/netbox/api/serializers/base.py +++ b/netbox/netbox/api/serializers/base.py @@ -1,4 +1,7 @@ +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 @@ -14,18 +17,22 @@ class BaseModelSerializer(serializers.ModelSerializer): display = serializers.SerializerMethodField(read_only=True) def __init__(self, *args, nested=False, fields=None, **kwargs): - super().__init__(*args, **kwargs) + """ + Extends the base __init__() method to support dynamic fields. + :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. + """ self.nested = nested + self._requested_fields = fields + # If this serializer is nested but no fields have been specified, + # default to using Meta.brief_fields (if set) if nested and not fields: - fields = getattr(self.Meta, 'brief_fields', None) + self._requested_fields = getattr(self.Meta, 'brief_fields', None) - # If specific fields have been requested, omit the others - if fields: - for field in list(self.fields.keys()): - if field not in fields: - self.fields.pop(field) + super().__init__(*args, **kwargs) def to_internal_value(self, data): @@ -37,6 +44,21 @@ class BaseModelSerializer(serializers.ModelSerializer): return super().to_internal_value(data) + @cached_property + def fields(self): + """ + Override the fields property to check for requested fields. If defined, + return only the applicable fields. + """ + if not self._requested_fields: + return super().fields + + 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) def get_display(self, obj): return str(obj)