api.py 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. import platform
  2. import sys
  3. from django.conf import settings
  4. from django.http import JsonResponse
  5. from django.urls import reverse
  6. from rest_framework import status
  7. from rest_framework.utils import formatting
  8. from netbox.api.exceptions import GraphQLTypeNotFound, SerializerNotFound
  9. from .utils import dynamic_import
  10. def get_serializer_for_model(model, prefix=''):
  11. """
  12. Dynamically resolve and return the appropriate serializer for a model.
  13. """
  14. app_name, model_name = model._meta.label.split('.')
  15. # Serializers for Django's auth models are in the users app
  16. if app_name == 'auth':
  17. app_name = 'users'
  18. serializer_name = f'{app_name}.api.serializers.{prefix}{model_name}Serializer'
  19. try:
  20. return dynamic_import(serializer_name)
  21. except AttributeError:
  22. raise SerializerNotFound(
  23. f"Could not determine serializer for {app_name}.{model_name} with prefix '{prefix}'"
  24. )
  25. def get_graphql_type_for_model(model):
  26. """
  27. Return the GraphQL type class for the given model.
  28. """
  29. app_name, model_name = model._meta.label.split('.')
  30. # Object types for Django's auth models are in the users app
  31. if app_name == 'auth':
  32. app_name = 'users'
  33. class_name = f'{app_name}.graphql.types.{model_name}Type'
  34. try:
  35. return dynamic_import(class_name)
  36. except AttributeError:
  37. raise GraphQLTypeNotFound(f"Could not find GraphQL type for {app_name}.{model_name}")
  38. def is_api_request(request):
  39. """
  40. Return True of the request is being made via the REST API.
  41. """
  42. api_path = reverse('api-root')
  43. return request.path_info.startswith(api_path) and request.content_type == 'application/json'
  44. def get_view_name(view, suffix=None):
  45. """
  46. Derive the view name from its associated model, if it has one. Fall back to DRF's built-in `get_view_name`.
  47. """
  48. if hasattr(view, 'queryset'):
  49. # Determine the model name from the queryset.
  50. name = view.queryset.model._meta.verbose_name
  51. name = ' '.join([w[0].upper() + w[1:] for w in name.split()]) # Capitalize each word
  52. else:
  53. # Replicate DRF's built-in behavior.
  54. name = view.__class__.__name__
  55. name = formatting.remove_trailing_string(name, 'View')
  56. name = formatting.remove_trailing_string(name, 'ViewSet')
  57. name = formatting.camelcase_to_spaces(name)
  58. if suffix:
  59. name += ' ' + suffix
  60. return name
  61. def rest_api_server_error(request, *args, **kwargs):
  62. """
  63. Handle exceptions and return a useful error message for REST API requests.
  64. """
  65. type_, error, traceback = sys.exc_info()
  66. data = {
  67. 'error': str(error),
  68. 'exception': type_.__name__,
  69. 'netbox_version': settings.VERSION,
  70. 'python_version': platform.python_version(),
  71. }
  72. return JsonResponse(data, status=status.HTTP_500_INTERNAL_SERVER_ERROR)