serializers.py 8.6 KB

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