Spaces:
Sleeping
Sleeping
| from rest_framework import serializers | |
| from .models import UserCheckpointProgress, UserProgress | |
| class UserProgressSerializer(serializers.ModelSerializer): | |
| resource_title = serializers.CharField(source='resource.title', read_only=True) | |
| has_checkpoints = serializers.SerializerMethodField() | |
| in_current_plan = serializers.SerializerMethodField() | |
| class Meta: | |
| model = UserProgress | |
| fields = ['id', 'resource', 'resource_title', 'status', 'progress', | |
| 'started_at', 'completed_at', 'has_checkpoints', | |
| 'in_current_plan'] | |
| read_only_fields = ['status', 'started_at', 'completed_at', | |
| 'resource_title', 'has_checkpoints', | |
| 'in_current_plan'] | |
| def get_has_checkpoints(self, obj) -> bool: | |
| # Prefer the annotated value from the list view's queryset; fall back | |
| # to a direct count on single-object endpoints. | |
| annotated = getattr(obj, 'resource_has_checkpoints', None) | |
| if annotated is not None: | |
| return annotated | |
| # ResourceProgressView (detail) sets no prefetch_related, so this is | |
| # one extra query on a single object — not an N+1, fine off the list. | |
| return len(obj.resource.checkpoints.all()) > 0 | |
| def get_in_current_plan(self, obj) -> bool: | |
| # Annotated by UserProgressListView.get_queryset. Single-object | |
| # endpoints (ResourceProgressView) don't annotate it; default False — | |
| # the frontend only consumes this flag on the list to disable | |
| # out-of-plan rows, so a conservative False off the detail path is safe. | |
| annotated = getattr(obj, 'in_current_plan_annot', None) | |
| return bool(annotated) if annotated is not None else False | |
| class UserCheckpointProgressSerializer(serializers.ModelSerializer): | |
| class Meta: | |
| model = UserCheckpointProgress | |
| fields = ['id', 'checkpoint', 'completed_at'] | |
| read_only_fields = ['completed_at'] | |