Files
dota-random-builds-back/api/views.py
2025-12-11 18:15:56 +03:00

104 lines
3.7 KiB
Python

from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from api.models import Aspect, Hero, Item
from api.serializers import (
HeroSerializer,
ItemSerializer,
RandomizeBuildRequestSerializer,
)
from .data import generate_skill_build
class HeroesListView(APIView):
"""
GET: Return all available heroes for selection.
"""
def get(self, request):
heroes = Hero.objects.all().order_by("name")
return Response(HeroSerializer(heroes, many=True).data, status=status.HTTP_200_OK)
class RandomizeBuildView(APIView):
"""
POST: Generate a random Dota 2 build with hero, items, and optionally skills/aspects.
"""
def get_serializer(self, *args, **kwargs):
return RandomizeBuildRequestSerializer(*args, **kwargs)
def post(self, request):
serializer = RandomizeBuildRequestSerializer(data=request.data)
if not serializer.is_valid():
return Response(
{"message": self._format_errors(serializer.errors)},
status=status.HTTP_400_BAD_REQUEST,
)
validated_data = serializer.validated_data
include_skills = validated_data["includeSkills"]
include_aspect = validated_data["includeAspect"]
items_count = validated_data["itemsCount"]
hero_id = validated_data.get("heroId")
hero_count = Hero.objects.count()
item_count = Item.objects.count()
if hero_count == 0:
return Response(
{"message": "No heroes available. Load data first."},
status=status.HTTP_400_BAD_REQUEST,
)
if item_count < items_count:
return Response(
{"message": f"Not enough items available. Requested {items_count}, found {item_count}."},
status=status.HTTP_400_BAD_REQUEST,
)
if hero_id:
hero_obj = Hero.objects.filter(id=hero_id).first()
if not hero_obj:
return Response(
{"message": f"Hero with id {hero_id} not found."},
status=status.HTTP_400_BAD_REQUEST,
)
else:
hero_obj = Hero.objects.order_by("?").first()
item_objs = Item.objects.order_by("?")[:items_count]
response_data = {
"hero": HeroSerializer(hero_obj).data,
"items": ItemSerializer(item_objs, many=True).data,
}
if include_skills:
response_data["skillBuild"] = generate_skill_build()
if include_aspect:
hero_aspects = Aspect.objects.filter(hero=hero_obj)
if hero_aspects.exists():
aspect_obj = hero_aspects.order_by("?").first()
response_data["aspect"] = aspect_obj.name
return Response(response_data, status=status.HTTP_200_OK)
def _format_errors(self, errors: dict) -> str:
"""Format serializer errors into a readable message."""
messages = []
for field, field_errors in errors.items():
for error in field_errors:
if field == "itemsCount" and "greater than or equal to" in str(error):
messages.append("itemsCount must be at least 1.")
elif "valid" in str(error).lower() or "required" in str(error).lower():
if field in ("includeSkills", "includeAspect"):
messages.append("includeSkills and includeAspect must be boolean.")
elif field == "itemsCount":
messages.append("itemsCount must be a number.")
else:
messages.append(f"{field}: {error}")
return messages[0] if messages else "Invalid request data."