django-orchestra/orchestra/contrib/resources/serializers.py

91 lines
3.3 KiB
Python

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()
unit = serializers.ReadOnlyField()
class Meta:
model = ResourceData
fields = ('name', 'used', 'allocated', 'unit')
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').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()