from django.db.models import Prefetch, Q from rest_framework.response import Response from rest_framework.views import APIView from contest.models import RatingHistory, RealtimeMatch from .models import UserAbility, UserPet class ProgressionProfileView(APIView): def get(self, request): pet, _ = UserPet.objects.get_or_create(user=request.user) existing = {ability.dimension: ability for ability in request.user.abilities.all()} abilities = [] for dimension, label in UserAbility.Dimension.choices: ability = existing.get(dimension) if ability is None: ability = UserAbility.objects.create(user=request.user, dimension=dimension) abilities.append( { "dimension": dimension, "label": label, "level": ability.level, "fragments": ability.fragments, } ) matches = ( RealtimeMatch.objects.filter( Q(player_one=request.user) | Q(player_two=request.user), status=RealtimeMatch.Status.COMPLETED, ) .select_related("contest", "player_one", "player_two", "winner") .prefetch_related( Prefetch( "rating_changes", queryset=RatingHistory.objects.filter(user=request.user), to_attr="viewer_rating_changes", ) ) .order_by("-completed_at")[:10] ) recent_matches = [] for match in matches: opponent = ( match.player_two if match.player_one_id == request.user.id else match.player_one ) rating_change = ( match.viewer_rating_changes[0] if match.viewer_rating_changes else None ) recent_matches.append( { "match_id": match.id, "contest": match.contest.title, "opponent": opponent.nickname if opponent else "未知对手", "result": ( "draw" if match.winner_id is None else "win" if match.winner_id == request.user.id else "loss" ), "rating_delta": rating_change.delta if rating_change else 0, "rating_after": ( rating_change.rating_after if rating_change else request.user.rating ), "completed_at": match.completed_at, } ) return Response( { "pet": { "name": pet.name, "level": pet.level, "experience": pet.experience, "appearance": pet.appearance, }, "abilities": abilities, "cards": [ { "slug": item.card.slug, "name": item.card.name, "mathematician": item.card.mathematician, "image": item.card.image, "acquired_at": item.acquired_at, } for item in request.user.cards.select_related("card") ], "recent_games": [ { "kind": attempt.kind, "label": attempt.get_kind_display(), "difficulty": attempt.get_difficulty_display(), "status": attempt.status, "score": attempt.score, "duration_ms": attempt.duration_ms, "started_at": attempt.started_at, } for attempt in request.user.math_game_attempts.all()[:10] ], "recent_matches": recent_matches, "story_marks": [ { "code": mark.code, "name": mark.name, "domain": mark.domain, "story": mark.story.title, "acquired_at": mark.acquired_at, } for mark in request.user.story_marks.select_related("story") ], } )