serializers.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. from django.contrib.contenttypes.models import ContentType
  2. from django.core.exceptions import ObjectDoesNotExist
  3. from drf_yasg.utils import swagger_serializer_method
  4. from rest_framework import serializers
  5. from dcim.api.nested_serializers import (
  6. NestedDeviceSerializer, NestedDeviceRoleSerializer, NestedPlatformSerializer, NestedRackSerializer,
  7. NestedRegionSerializer, NestedSiteSerializer,
  8. )
  9. from dcim.models import Device, DeviceRole, Platform, Rack, Region, Site
  10. from extras.constants import *
  11. from extras.models import (
  12. ConfigContext, ExportTemplate, Graph, ImageAttachment, ObjectChange, ReportResult, Tag,
  13. )
  14. from tenancy.api.nested_serializers import NestedTenantSerializer, NestedTenantGroupSerializer
  15. from tenancy.models import Tenant, TenantGroup
  16. from users.api.nested_serializers import NestedUserSerializer
  17. from utilities.api import (
  18. ChoiceField, ContentTypeField, get_serializer_for_model, SerializerNotFound, SerializedPKRelatedField,
  19. ValidatedModelSerializer,
  20. )
  21. from .nested_serializers import *
  22. #
  23. # Graphs
  24. #
  25. class GraphSerializer(ValidatedModelSerializer):
  26. type = ChoiceField(choices=GRAPH_TYPE_CHOICES)
  27. class Meta:
  28. model = Graph
  29. fields = ['id', 'type', 'weight', 'name', 'source', 'link']
  30. class RenderedGraphSerializer(serializers.ModelSerializer):
  31. embed_url = serializers.SerializerMethodField()
  32. embed_link = serializers.SerializerMethodField()
  33. type = ChoiceField(choices=GRAPH_TYPE_CHOICES)
  34. class Meta:
  35. model = Graph
  36. fields = ['id', 'type', 'weight', 'name', 'embed_url', 'embed_link']
  37. def get_embed_url(self, obj):
  38. return obj.embed_url(self.context['graphed_object'])
  39. def get_embed_link(self, obj):
  40. return obj.embed_link(self.context['graphed_object'])
  41. #
  42. # Export templates
  43. #
  44. class ExportTemplateSerializer(ValidatedModelSerializer):
  45. template_language = ChoiceField(
  46. choices=TEMPLATE_LANGUAGE_CHOICES,
  47. default=TEMPLATE_LANGUAGE_JINJA2
  48. )
  49. class Meta:
  50. model = ExportTemplate
  51. fields = [
  52. 'id', 'content_type', 'name', 'description', 'template_language', 'template_code', 'mime_type',
  53. 'file_extension',
  54. ]
  55. #
  56. # Tags
  57. #
  58. class TagSerializer(ValidatedModelSerializer):
  59. tagged_items = serializers.IntegerField(read_only=True)
  60. class Meta:
  61. model = Tag
  62. fields = ['id', 'name', 'slug', 'color', 'comments', 'tagged_items']
  63. #
  64. # Image attachments
  65. #
  66. class ImageAttachmentSerializer(ValidatedModelSerializer):
  67. content_type = ContentTypeField(
  68. queryset=ContentType.objects.all()
  69. )
  70. parent = serializers.SerializerMethodField(read_only=True)
  71. class Meta:
  72. model = ImageAttachment
  73. fields = [
  74. 'id', 'content_type', 'object_id', 'parent', 'name', 'image', 'image_height', 'image_width', 'created',
  75. ]
  76. def validate(self, data):
  77. # Validate that the parent object exists
  78. try:
  79. data['content_type'].get_object_for_this_type(id=data['object_id'])
  80. except ObjectDoesNotExist:
  81. raise serializers.ValidationError(
  82. "Invalid parent object: {} ID {}".format(data['content_type'], data['object_id'])
  83. )
  84. # Enforce model validation
  85. super().validate(data)
  86. return data
  87. @swagger_serializer_method(serializer_or_field=serializers.DictField)
  88. def get_parent(self, obj):
  89. # Static mapping of models to their nested serializers
  90. if isinstance(obj.parent, Device):
  91. serializer = NestedDeviceSerializer
  92. elif isinstance(obj.parent, Rack):
  93. serializer = NestedRackSerializer
  94. elif isinstance(obj.parent, Site):
  95. serializer = NestedSiteSerializer
  96. else:
  97. raise Exception("Unexpected type of parent object for ImageAttachment")
  98. return serializer(obj.parent, context={'request': self.context['request']}).data
  99. #
  100. # Config contexts
  101. #
  102. class ConfigContextSerializer(ValidatedModelSerializer):
  103. regions = SerializedPKRelatedField(
  104. queryset=Region.objects.all(),
  105. serializer=NestedRegionSerializer,
  106. required=False,
  107. many=True
  108. )
  109. sites = SerializedPKRelatedField(
  110. queryset=Site.objects.all(),
  111. serializer=NestedSiteSerializer,
  112. required=False,
  113. many=True
  114. )
  115. roles = SerializedPKRelatedField(
  116. queryset=DeviceRole.objects.all(),
  117. serializer=NestedDeviceRoleSerializer,
  118. required=False,
  119. many=True
  120. )
  121. platforms = SerializedPKRelatedField(
  122. queryset=Platform.objects.all(),
  123. serializer=NestedPlatformSerializer,
  124. required=False,
  125. many=True
  126. )
  127. tenant_groups = SerializedPKRelatedField(
  128. queryset=TenantGroup.objects.all(),
  129. serializer=NestedTenantGroupSerializer,
  130. required=False,
  131. many=True
  132. )
  133. tenants = SerializedPKRelatedField(
  134. queryset=Tenant.objects.all(),
  135. serializer=NestedTenantSerializer,
  136. required=False,
  137. many=True
  138. )
  139. class Meta:
  140. model = ConfigContext
  141. fields = [
  142. 'id', 'name', 'weight', 'description', 'is_active', 'regions', 'sites', 'roles', 'platforms',
  143. 'tenant_groups', 'tenants', 'data',
  144. ]
  145. #
  146. # Reports
  147. #
  148. class ReportResultSerializer(serializers.ModelSerializer):
  149. class Meta:
  150. model = ReportResult
  151. fields = ['created', 'user', 'failed', 'data']
  152. class ReportSerializer(serializers.Serializer):
  153. module = serializers.CharField(max_length=255)
  154. name = serializers.CharField(max_length=255)
  155. description = serializers.CharField(max_length=255, required=False)
  156. test_methods = serializers.ListField(child=serializers.CharField(max_length=255))
  157. result = NestedReportResultSerializer()
  158. class ReportDetailSerializer(ReportSerializer):
  159. result = ReportResultSerializer()
  160. #
  161. # Change logging
  162. #
  163. class ObjectChangeSerializer(serializers.ModelSerializer):
  164. user = NestedUserSerializer(
  165. read_only=True
  166. )
  167. action = ChoiceField(
  168. choices=OBJECTCHANGE_ACTION_CHOICES,
  169. read_only=True
  170. )
  171. changed_object_type = ContentTypeField(
  172. read_only=True
  173. )
  174. changed_object = serializers.SerializerMethodField(
  175. read_only=True
  176. )
  177. class Meta:
  178. model = ObjectChange
  179. fields = [
  180. 'id', 'time', 'user', 'user_name', 'request_id', 'action', 'changed_object_type', 'changed_object',
  181. 'object_data',
  182. ]
  183. @swagger_serializer_method(serializer_or_field=serializers.DictField)
  184. def get_changed_object(self, obj):
  185. """
  186. Serialize a nested representation of the changed object.
  187. """
  188. if obj.changed_object is None:
  189. return None
  190. try:
  191. serializer = get_serializer_for_model(obj.changed_object, prefix='Nested')
  192. except SerializerNotFound:
  193. return obj.object_repr
  194. context = {
  195. 'request': self.context['request']
  196. }
  197. data = serializer(obj.changed_object, context=context).data
  198. return data