serializers.py 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  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.choices import *
  11. from extras.constants import *
  12. from extras.models import (
  13. ConfigContext, ExportTemplate, Graph, ImageAttachment, ObjectChange, ReportResult, Tag,
  14. )
  15. from tenancy.api.nested_serializers import NestedTenantSerializer, NestedTenantGroupSerializer
  16. from tenancy.models import Tenant, TenantGroup
  17. from users.api.nested_serializers import NestedUserSerializer
  18. from utilities.api import (
  19. ChoiceField, ContentTypeField, get_serializer_for_model, SerializerNotFound, SerializedPKRelatedField,
  20. ValidatedModelSerializer,
  21. )
  22. from virtualization.api.nested_serializers import NestedClusterGroupSerializer, NestedClusterSerializer
  23. from virtualization.models import Cluster, ClusterGroup
  24. from .nested_serializers import *
  25. #
  26. # Graphs
  27. #
  28. class GraphSerializer(ValidatedModelSerializer):
  29. type = ContentTypeField(
  30. queryset=ContentType.objects.filter(GRAPH_MODELS),
  31. )
  32. class Meta:
  33. model = Graph
  34. fields = ['id', 'type', 'weight', 'name', 'template_language', 'source', 'link']
  35. class RenderedGraphSerializer(serializers.ModelSerializer):
  36. embed_url = serializers.SerializerMethodField()
  37. embed_link = serializers.SerializerMethodField()
  38. type = ContentTypeField(
  39. queryset=ContentType.objects.all()
  40. )
  41. class Meta:
  42. model = Graph
  43. fields = ['id', 'type', 'weight', 'name', 'embed_url', 'embed_link']
  44. def get_embed_url(self, obj):
  45. return obj.embed_url(self.context['graphed_object'])
  46. def get_embed_link(self, obj):
  47. return obj.embed_link(self.context['graphed_object'])
  48. #
  49. # Export templates
  50. #
  51. class ExportTemplateSerializer(ValidatedModelSerializer):
  52. template_language = ChoiceField(
  53. choices=TemplateLanguageChoices,
  54. default=TemplateLanguageChoices.LANGUAGE_JINJA2
  55. )
  56. class Meta:
  57. model = ExportTemplate
  58. fields = [
  59. 'id', 'content_type', 'name', 'description', 'template_language', 'template_code', 'mime_type',
  60. 'file_extension',
  61. ]
  62. #
  63. # Tags
  64. #
  65. class TagSerializer(ValidatedModelSerializer):
  66. tagged_items = serializers.IntegerField(read_only=True)
  67. class Meta:
  68. model = Tag
  69. fields = ['id', 'name', 'slug', 'color', 'comments', 'tagged_items']
  70. #
  71. # Image attachments
  72. #
  73. class ImageAttachmentSerializer(ValidatedModelSerializer):
  74. content_type = ContentTypeField(
  75. queryset=ContentType.objects.all()
  76. )
  77. parent = serializers.SerializerMethodField(read_only=True)
  78. class Meta:
  79. model = ImageAttachment
  80. fields = [
  81. 'id', 'content_type', 'object_id', 'parent', 'name', 'image', 'image_height', 'image_width', 'created',
  82. ]
  83. def validate(self, data):
  84. # Validate that the parent object exists
  85. try:
  86. data['content_type'].get_object_for_this_type(id=data['object_id'])
  87. except ObjectDoesNotExist:
  88. raise serializers.ValidationError(
  89. "Invalid parent object: {} ID {}".format(data['content_type'], data['object_id'])
  90. )
  91. # Enforce model validation
  92. super().validate(data)
  93. return data
  94. @swagger_serializer_method(serializer_or_field=serializers.DictField)
  95. def get_parent(self, obj):
  96. # Static mapping of models to their nested serializers
  97. if isinstance(obj.parent, Device):
  98. serializer = NestedDeviceSerializer
  99. elif isinstance(obj.parent, Rack):
  100. serializer = NestedRackSerializer
  101. elif isinstance(obj.parent, Site):
  102. serializer = NestedSiteSerializer
  103. else:
  104. raise Exception("Unexpected type of parent object for ImageAttachment")
  105. return serializer(obj.parent, context={'request': self.context['request']}).data
  106. #
  107. # Config contexts
  108. #
  109. class ConfigContextSerializer(ValidatedModelSerializer):
  110. regions = SerializedPKRelatedField(
  111. queryset=Region.objects.all(),
  112. serializer=NestedRegionSerializer,
  113. required=False,
  114. many=True
  115. )
  116. sites = SerializedPKRelatedField(
  117. queryset=Site.objects.all(),
  118. serializer=NestedSiteSerializer,
  119. required=False,
  120. many=True
  121. )
  122. roles = SerializedPKRelatedField(
  123. queryset=DeviceRole.objects.all(),
  124. serializer=NestedDeviceRoleSerializer,
  125. required=False,
  126. many=True
  127. )
  128. platforms = SerializedPKRelatedField(
  129. queryset=Platform.objects.all(),
  130. serializer=NestedPlatformSerializer,
  131. required=False,
  132. many=True
  133. )
  134. cluster_groups = SerializedPKRelatedField(
  135. queryset=ClusterGroup.objects.all(),
  136. serializer=NestedClusterGroupSerializer,
  137. required=False,
  138. many=True
  139. )
  140. clusters = SerializedPKRelatedField(
  141. queryset=Cluster.objects.all(),
  142. serializer=NestedClusterSerializer,
  143. required=False,
  144. many=True
  145. )
  146. tenant_groups = SerializedPKRelatedField(
  147. queryset=TenantGroup.objects.all(),
  148. serializer=NestedTenantGroupSerializer,
  149. required=False,
  150. many=True
  151. )
  152. tenants = SerializedPKRelatedField(
  153. queryset=Tenant.objects.all(),
  154. serializer=NestedTenantSerializer,
  155. required=False,
  156. many=True
  157. )
  158. tags = serializers.SlugRelatedField(
  159. queryset=Tag.objects.all(),
  160. slug_field='slug',
  161. required=False,
  162. many=True
  163. )
  164. class Meta:
  165. model = ConfigContext
  166. fields = [
  167. 'id', 'name', 'weight', 'description', 'is_active', 'regions', 'sites', 'roles', 'platforms',
  168. 'cluster_groups', 'clusters', 'tenant_groups', 'tenants', 'tags', 'data',
  169. ]
  170. #
  171. # Reports
  172. #
  173. class ReportResultSerializer(serializers.ModelSerializer):
  174. class Meta:
  175. model = ReportResult
  176. fields = ['created', 'user', 'failed', 'data']
  177. class ReportSerializer(serializers.Serializer):
  178. module = serializers.CharField(max_length=255)
  179. name = serializers.CharField(max_length=255)
  180. description = serializers.CharField(max_length=255, required=False)
  181. test_methods = serializers.ListField(child=serializers.CharField(max_length=255))
  182. result = NestedReportResultSerializer()
  183. class ReportDetailSerializer(ReportSerializer):
  184. result = ReportResultSerializer()
  185. #
  186. # Scripts
  187. #
  188. class ScriptSerializer(serializers.Serializer):
  189. id = serializers.SerializerMethodField(read_only=True)
  190. name = serializers.SerializerMethodField(read_only=True)
  191. description = serializers.SerializerMethodField(read_only=True)
  192. vars = serializers.SerializerMethodField(read_only=True)
  193. def get_id(self, instance):
  194. return '{}.{}'.format(instance.__module__, instance.__name__)
  195. def get_name(self, instance):
  196. return getattr(instance.Meta, 'name', instance.__name__)
  197. def get_description(self, instance):
  198. return getattr(instance.Meta, 'description', '')
  199. def get_vars(self, instance):
  200. return {
  201. k: v.__class__.__name__ for k, v in instance._get_vars().items()
  202. }
  203. class ScriptInputSerializer(serializers.Serializer):
  204. data = serializers.JSONField()
  205. commit = serializers.BooleanField()
  206. class ScriptLogMessageSerializer(serializers.Serializer):
  207. status = serializers.SerializerMethodField(read_only=True)
  208. message = serializers.SerializerMethodField(read_only=True)
  209. def get_status(self, instance):
  210. return LOG_LEVEL_CODES.get(instance[0])
  211. def get_message(self, instance):
  212. return instance[1]
  213. class ScriptOutputSerializer(serializers.Serializer):
  214. log = ScriptLogMessageSerializer(many=True, read_only=True)
  215. output = serializers.CharField(read_only=True)
  216. #
  217. # Change logging
  218. #
  219. class ObjectChangeSerializer(serializers.ModelSerializer):
  220. user = NestedUserSerializer(
  221. read_only=True
  222. )
  223. action = ChoiceField(
  224. choices=ObjectChangeActionChoices,
  225. read_only=True
  226. )
  227. changed_object_type = ContentTypeField(
  228. read_only=True
  229. )
  230. changed_object = serializers.SerializerMethodField(
  231. read_only=True
  232. )
  233. class Meta:
  234. model = ObjectChange
  235. fields = [
  236. 'id', 'time', 'user', 'user_name', 'request_id', 'action', 'changed_object_type', 'changed_object_id',
  237. 'changed_object', 'object_data',
  238. ]
  239. @swagger_serializer_method(serializer_or_field=serializers.DictField)
  240. def get_changed_object(self, obj):
  241. """
  242. Serialize a nested representation of the changed object.
  243. """
  244. if obj.changed_object is None:
  245. return None
  246. try:
  247. serializer = get_serializer_for_model(obj.changed_object, prefix='Nested')
  248. except SerializerNotFound:
  249. return obj.object_repr
  250. context = {
  251. 'request': self.context['request']
  252. }
  253. data = serializer(obj.changed_object, context=context).data
  254. return data