Source code for request.serializers

from django.conf import settings
from rest_framework.exceptions import ValidationError
from rest_framework.serializers import ModelSerializer, SerializerMethodField

from .models import Request, FileRequest


class RequestSerializer(ModelSerializer):
    user_full_name = SerializerMethodField()
    restrict_permissions = SerializerMethodField()
    deep_seq_request_name = SerializerMethodField()
    deep_seq_request_path = SerializerMethodField()
    completed = SerializerMethodField()
    files = SerializerMethodField()
    number_of_samples = SerializerMethodField()

    class Meta:
        model = Request
        fields = (
            'pk',
            'name',
            'user',
            'user_full_name',
            'create_time',
            'cost_unit',
            'description',
            'total_sequencing_depth',
            'restrict_permissions',
            'completed',
            'deep_seq_request_name',
            'deep_seq_request_path',
            'files',
            'sequenced',
            'number_of_samples',
        )

    def get_user_full_name(self, obj):
        return obj.user.full_name

    def get_number_of_samples(self,obj):
        return len(obj.statuses)

    def get_restrict_permissions(self, obj):
        """
        Don't allow the users to modify the requests and libraries/samples
        if they have reached status 1 or higher (or failed).
        """
        return True if not obj.user.is_staff and obj.statuses.count(0) == 0 \
            else False

    def get_completed(self, obj):
        """ Return True if request's libraries and samples are sequenced. """
        return obj.statuses.count(6) > 0

    def get_deep_seq_request_name(self, obj):
        return obj.deep_seq_request.name.split('/')[-1] \
            if obj.deep_seq_request else ''

    def get_deep_seq_request_path(self, obj):
        return settings.MEDIA_URL + obj.deep_seq_request.name \
            if obj.deep_seq_request else ''

    def get_files(self, obj):
        files = [{
            'pk': file.pk,
            'name': file.name.split('/')[-1],
            'path': settings.MEDIA_URL + file.file.name,
        } for file in obj.files.all()]
        return files

    def to_internal_value(self, data):
        internal_value = super().to_internal_value(data)

        records = data.get('records', [])
        if not records:
            raise ValidationError({
                'records': ['No libraries or samples are provided.'],
            })

        files = data.get('files', [])

        libraries = []
        samples = []
        for obj in records:
            if obj['record_type'] == 'Library':
                libraries.append(int(obj['pk']))
            elif obj['record_type'] == 'Sample':
                samples.append(int(obj['pk']))

        internal_value.update({
            'libraries': libraries,
            'samples': samples,
            'files': files,
        })

        return internal_value

    def update(self, instance, validated_data):
        # Remember old files
        old_files = set(instance.files.all())
        instance.files.clear()

        # Update the request with new values
        instance = super().update(instance, validated_data)

        # Get new files
        new_files = set(instance.files.all())

        # Delete files which are not in the list of request's files anymore
        files_to_delete = list(old_files - new_files)
        for file in files_to_delete:
            file.delete()

        return instance


class RequestFileSerializer(ModelSerializer):
    size = SerializerMethodField()
    path = SerializerMethodField()

    class Meta:
        model = FileRequest
        fields = ('id', 'name', 'size', 'path')

    def get_size(self, obj):
        return obj.file.size

    def get_path(self, obj):
        return settings.MEDIA_URL + obj.file.name