Source code for akvo.rest.serializers.indicator_period

# -*- coding: utf-8 -*-

# Akvo RSR is covered by the GNU Affero General Public License.
# See more details in the license.txt file located at the root folder of the Akvo RSR module.
# For additional details on the GNU license please see < http://www.gnu.org/licenses/agpl.html >.

from akvo.rest.serializers.rsr_serializer import BaseRSRSerializer
from akvo.rest.serializers.indicator_period_data import (
    IndicatorPeriodDataFrameworkSerializer, IndicatorPeriodDataLiteSerializer)
from akvo.rest.serializers.indicator_period_disaggregation import (
    IndicatorPeriodDisaggregationLiteSerializer, IndicatorPeriodDisaggregationReadOnlySerializer)
from akvo.rsr.models import Indicator, IndicatorPeriod, IndicatorPeriodData, DisaggregationTarget
from akvo.utils import ensure_decimal, maybe_decimal

from rest_framework import serializers


[docs]def serialize_disaggregation_targets(period): return [ { 'id': t.id, 'value': t.value, 'dimension_value': t.dimension_value_id, 'period': period.id, } for t in period.disaggregation_targets.all() ]
[docs]def create_or_update_disaggregation_targets(instance, disaggregation_targets): for dt in disaggregation_targets: instance_key = 'indicator' if isinstance(instance, Indicator) else 'period' data = dict(dimension_value=dt['dimension_value']) data[instance_key] = instance defaults = dict(value=dt['value']) target, created = instance.disaggregation_targets.get_or_create(**data, defaults=defaults) if not created: target.value = dt['value'] target.save(update_fields=['value'])
[docs]class DisaggregationTargetNestedSerializer(BaseRSRSerializer): id = serializers.IntegerField()
[docs] class Meta: model = DisaggregationTarget fields = '__all__' read_only_fields = ('id', 'period')
[docs]class IndicatorPeriodSerializer(BaseRSRSerializer): indicator_unicode = serializers.ReadOnlyField(source='indicator.__str__') percent_accomplishment = serializers.ReadOnlyField() can_add_update = serializers.ReadOnlyField(source='can_save_update') disaggregations = IndicatorPeriodDisaggregationLiteSerializer(many=True, required=False, read_only=True) disaggregation_targets = DisaggregationTargetNestedSerializer(many=True, required=False)
[docs] class Meta: model = IndicatorPeriod fields = '__all__'
# TODO: add validation for parent_period
[docs] def validate_disaggregation_targets(self, data): for target in data: if 'value' not in target: raise serializers.ValidationError('Disaggregation targets should have a value') if 'dimension_value' not in target: raise serializers.ValidationError( 'Disaggregation targets should have "dimension_value"') return data
[docs] def create(self, validated_data): validated_data.pop('disaggregation_targets', []) return super().create(validated_data)
[docs] def update(self, instance, validated_data): disaggregation_targets = validated_data.pop('disaggregation_targets', []) instance = super().update(instance, validated_data) create_or_update_disaggregation_targets(instance, disaggregation_targets) return instance
[docs]class IndicatorPeriodFrameworkSerializer(BaseRSRSerializer): data = serializers.SerializerMethodField('get_updates') parent_period = serializers.ReadOnlyField(source='parent_period_id') percent_accomplishment = serializers.ReadOnlyField() disaggregations = IndicatorPeriodDisaggregationLiteSerializer(many=True, required=False, read_only=True) disaggregation_targets = serializers.SerializerMethodField()
[docs] class Meta: model = IndicatorPeriod fields = '__all__'
[docs] def get_disaggregation_targets(self, obj): return serialize_disaggregation_targets(obj)
[docs] def get_updates(self, obj): user = self.context['request'].user updates = IndicatorPeriodData.objects.filter(period=obj).select_related( 'period', 'user', 'approved_by', ).prefetch_related( 'comments', 'comments__user' ) updates = IndicatorPeriodData.get_user_viewable_updates(updates, user) serializer = IndicatorPeriodDataFrameworkSerializer(updates, many=True) return serializer.data
[docs]class IndicatorPeriodFrameworkLiteSerializer(BaseRSRSerializer): parent_period = serializers.ReadOnlyField(source='parent_period_id') percent_accomplishment = serializers.ReadOnlyField() disaggregation_targets = serializers.SerializerMethodField()
[docs] class Meta: model = IndicatorPeriod fields = '__all__'
[docs] def get_disaggregation_targets(self, obj): return serialize_disaggregation_targets(obj)
[docs]class IndicatorPeriodFrameworkNotSoLiteSerializer(BaseRSRSerializer): updates = serializers.SerializerMethodField() parent_period = serializers.ReadOnlyField(source='parent_period_id') percent_accomplishment = serializers.ReadOnlyField() disaggregations = IndicatorPeriodDisaggregationReadOnlySerializer(many=True, required=False, read_only=True) disaggregation_targets = serializers.SerializerMethodField() can_add_update = serializers.ReadOnlyField(source='can_save_update') actual_value = serializers.SerializerMethodField() target_value = serializers.SerializerMethodField()
[docs] def get_actual_value(self, obj): return ensure_decimal(obj.actual_value)
[docs] def get_target_value(self, obj): return ensure_decimal(obj.target_value)
[docs] def get_disaggregation_targets(self, obj): return [ { 'id': t.id, 'category': t.dimension_value.name.name, 'category_id': t.dimension_value.name.id, 'type': t.dimension_value.value, 'type_id': t.dimension_value.id, 'value': maybe_decimal(t.value), } for t in obj.disaggregation_targets.all() ]
[docs] def get_updates(self, obj: IndicatorPeriod): # FIXME: this is a very slow method # The more projects there are, the slower user = self.context['request'].user project_id = obj.indicator.result.project_id viewable_updates = user.viewable_indicator_updates(project_id) if not user.is_anonymous else [] if viewable_updates: # Using filter will throw away prefetched objects updates = [datum for datum in obj.data.all() if datum.id in viewable_updates] serializer = IndicatorPeriodDataLiteSerializer(updates, many=True) return serializer.data else: return []
[docs] class Meta: model = IndicatorPeriod fields = '__all__'