mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-18 05:28:16 -06:00
Enable dynamic field inclusion for REST API serializers
This commit is contained in:
parent
f41105d5e3
commit
d99928435a
@ -12,6 +12,15 @@ __all__ = (
|
|||||||
class BaseModelSerializer(serializers.ModelSerializer):
|
class BaseModelSerializer(serializers.ModelSerializer):
|
||||||
display = serializers.SerializerMethodField(read_only=True)
|
display = serializers.SerializerMethodField(read_only=True)
|
||||||
|
|
||||||
|
def __init__(self, *args, requested_fields=None, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# If specific fields have been requested, omit the others
|
||||||
|
if requested_fields:
|
||||||
|
for field in list(self.fields.keys()):
|
||||||
|
if field not in requested_fields:
|
||||||
|
self.fields.pop(field)
|
||||||
|
|
||||||
@extend_schema_field(OpenApiTypes.STR)
|
@extend_schema_field(OpenApiTypes.STR)
|
||||||
def get_display(self, obj):
|
def get_display(self, obj):
|
||||||
return str(obj)
|
return str(obj)
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
import logging
|
import logging
|
||||||
|
from functools import cached_property
|
||||||
|
|
||||||
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
|
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||||
|
from django.core.exceptions import FieldDoesNotExist, ObjectDoesNotExist, PermissionDenied
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.db.models import ProtectedError, RestrictedError
|
from django.db.models import ProtectedError, RestrictedError
|
||||||
|
from django.db.models.fields.related import ManyToOneRel, RelatedField
|
||||||
from django_pglocks import advisory_lock
|
from django_pglocks import advisory_lock
|
||||||
from netbox.constants import ADVISORY_LOCK_KEYS
|
from netbox.constants import ADVISORY_LOCK_KEYS
|
||||||
from rest_framework import mixins as drf_mixins
|
from rest_framework import mixins as drf_mixins
|
||||||
@ -40,6 +43,40 @@ class BaseViewSet(GenericViewSet):
|
|||||||
if action := HTTP_ACTIONS[request.method]:
|
if action := HTTP_ACTIONS[request.method]:
|
||||||
self.queryset = self.queryset.restrict(request.user, action)
|
self.queryset = self.queryset.restrict(request.user, action)
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
qs = super().get_queryset()
|
||||||
|
|
||||||
|
# Dynamically resolve prefetches for included serializer fields and attach them to the queryset
|
||||||
|
serializer_class = self.get_serializer_class()
|
||||||
|
model = serializer_class.Meta.model
|
||||||
|
fields_to_include = self.requested_fields or serializer_class.Meta.fields
|
||||||
|
prefetch = []
|
||||||
|
for field_name in fields_to_include:
|
||||||
|
try:
|
||||||
|
field = model._meta.get_field(field_name)
|
||||||
|
except FieldDoesNotExist:
|
||||||
|
continue
|
||||||
|
if isinstance(field, (RelatedField, ManyToOneRel, GenericForeignKey)):
|
||||||
|
# TODO: Use serializer field source if set, else use its name
|
||||||
|
prefetch.append(field_name)
|
||||||
|
if prefetch:
|
||||||
|
qs = qs.prefetch_related(*prefetch)
|
||||||
|
|
||||||
|
return qs
|
||||||
|
|
||||||
|
def get_serializer(self, *args, **kwargs):
|
||||||
|
|
||||||
|
# If specific fields have been requested, pass them to the serializer
|
||||||
|
if self.requested_fields:
|
||||||
|
kwargs['requested_fields'] = self.requested_fields
|
||||||
|
|
||||||
|
return super().get_serializer(*args, **kwargs)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def requested_fields(self):
|
||||||
|
requested_fields = self.request.query_params.get('include')
|
||||||
|
return requested_fields.split(',') if requested_fields else []
|
||||||
|
|
||||||
|
|
||||||
class NetBoxReadOnlyModelViewSet(
|
class NetBoxReadOnlyModelViewSet(
|
||||||
mixins.BriefModeMixin,
|
mixins.BriefModeMixin,
|
||||||
|
Loading…
Reference in New Issue
Block a user