91 lines
3.3 KiB
Python
91 lines
3.3 KiB
Python
from rest_framework import serializers
|
|
|
|
from orchestra.api import router
|
|
from orchestra.utils.db import database_ready
|
|
|
|
from .models import Resource, ResourceData
|
|
|
|
|
|
class ResourceSerializer(serializers.ModelSerializer):
|
|
name = serializers.SerializerMethodField()
|
|
unit = serializers.ReadOnlyField()
|
|
|
|
class Meta:
|
|
model = ResourceData
|
|
fields = ('name', 'used', 'allocated', 'unit')
|
|
read_only_fields = ('used',)
|
|
|
|
def to_internal_value(self, raw_data):
|
|
data = super(ResourceSerializer, self).to_internal_value(raw_data)
|
|
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').items():
|
|
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_options = viewset.options
|
|
def options(self, request, resources=resources):
|
|
""" Provides available resources description """
|
|
metadata = old_options(self, request)
|
|
metadata.data['available_resources'] = [
|
|
{
|
|
'name': resource.name,
|
|
'on_demand': resource.on_demand,
|
|
'default_allocation': resource.default_allocation
|
|
} for resource in resources
|
|
]
|
|
return metadata
|
|
viewset.options = options
|
|
|
|
if database_ready():
|
|
insert_resource_serializers()
|