from rest_framework import serializers from orchestra.api import router from orchestra.utils import database_ready from .models import Resource, ResourceData class ResourceSerializer(serializers.ModelSerializer): name = serializers.SerializerMethodField('get_name') class Meta: model = ResourceData fields = ('name', 'used', 'allocated') read_only_fields = ('used',) def from_native(self, raw_data, files=None): data = super(ResourceSerializer, self).from_native(raw_data, files=files) if not data.resource_id: data.resource = Resource.objects.get(name=raw_data['name']) return data def get_name(self, instance): return instance.resource.name def get_identity(self, data): return data.get('name') # Monkey-patching section def insert_resource_serializers(): # clean previous state for related in Resource._related: viewset = router.get_viewset(related) fields = list(viewset.serializer_class.Meta.fields) try: fields.remove('resources') except ValueError: pass viewset.serializer_class.Meta.fields = fields # Create nested serializers on target models for ct, resources in Resource.objects.group_by('content_type').iteritems(): model = ct.model_class() try: router.insert(model, 'resources', ResourceSerializer, required=False, many=True, source='resource_set') except KeyError: continue # TODO this is a fucking workaround, reimplement this on the proper place def validate_resources(self, attrs, source, _resources=resources): """ Creates missing resources """ posted = attrs.get(source, []) result = [] resources = list(_resources) for data in posted: resource = data.resource if resource not in resources: msg = "Unknown or duplicated resource '%s'." % resource raise serializers.ValidationError(msg) resources.remove(resource) if not resource.on_demand and not data.allocated: data.allocated = resource.default_allocation result.append(data) for resource in resources: data = ResourceData(resource=resource) if not resource.on_demand: data.allocated = resource.default_allocation result.append(data) attrs[source] = result return attrs viewset = router.get_viewset(model) viewset.serializer_class.validate_resources = validate_resources old_metadata = viewset.metadata def metadata(self, request, resources=resources): """ Provides available resources description """ ret = old_metadata(self, request) ret['available_resources'] = [ { 'name': resource.name, 'on_demand': resource.on_demand, 'default_allocation': resource.default_allocation } for resource in resources ] return ret viewset.metadata = metadata if database_ready(): insert_resource_serializers()