Closes #15131: Dynamic queryset annotations for REST API endpoints (#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
This commit is contained in:
Jeremy Stretch
2024-02-15 14:49:27 -05:00
committed by GitHub
parent b3f25a400b
commit 7abb2b2ab5
27 changed files with 204 additions and 221 deletions

View File

@@ -11,10 +11,13 @@ from rest_framework import status
from rest_framework.serializers import Serializer
from rest_framework.utils import formatting
from netbox.api.fields import RelatedObjectCountField
from netbox.api.exceptions import GraphQLTypeNotFound, SerializerNotFound
from utilities.utils import count_related
from .utils import dynamic_import
__all__ = (
'get_annotations_for_serializer',
'get_graphql_type_for_model',
'get_prefetches_for_serializer',
'get_serializer_for_model',
@@ -131,6 +134,26 @@ def get_prefetches_for_serializer(serializer_class, fields_to_include=None):
return prefetch_fields
def get_annotations_for_serializer(serializer_class, fields_to_include=None):
"""
Return a mapping of field names to annotations to be applied to the queryset for a serializer.
"""
annotations = {}
# If specific fields are not specified, default to all
if not fields_to_include:
fields_to_include = serializer_class.Meta.fields
model = serializer_class.Meta.model
for field_name, field in serializer_class._declared_fields.items():
if field_name in fields_to_include and type(field) is RelatedObjectCountField:
related_field = model._meta.get_field(field.relation).field
annotations[field_name] = count_related(related_field.model, related_field.name)
return annotations
def rest_api_server_error(request, *args, **kwargs):
"""
Handle exceptions and return a useful error message for REST API requests.