from collections import OrderedDict import json from django.urls import reverse from rest_framework import serializers from drf_spectacular.utils import extend_schema_field # pylint: disable=redefined-builtin # PokeAPI v2 serializers in order of dependency from .models import * ######################### # SUMMARY SERIALIZERS # ######################### # Summary serializers are just for list and reference behavior # Putting summary serializers up top so there are no conflicts # with reference accross models due to script running order class AbilitySummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Ability fields = ("name", "url") class BerryFirmnessSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = BerryFirmness fields = ("name", "url") class BerryFlavorSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = BerryFlavor fields = ("name", "url") class BerrySummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Berry fields = ("name", "url") class CharacteristicSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Characteristic fields = ("url",) class ContestEffectSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = ContestEffect fields = ("url",) class ContestTypeSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = ContestType fields = ("name", "url") class EggGroupSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = EggGroup fields = ("name", "url") class EncounterConditionSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = EncounterCondition fields = ("name", "url") class EncounterConditionValueSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = EncounterConditionValue fields = ("name", "url") class EncounterMethodSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = EncounterMethod fields = ("name", "url") class EvolutionTriggerSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = EvolutionTrigger fields = ("name", "url") class EvolutionChainSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = EvolutionChain fields = ("url",) class GenerationSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Generation fields = ("name", "url") class GenderSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Gender fields = ("name", "url") class GrowthRateSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = GrowthRate fields = ("name", "url") class ItemPocketSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = ItemPocket fields = ("name", "url") class ItemCategorySummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = ItemCategory fields = ("name", "url") class ItemAttributeSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = ItemAttribute fields = ("name", "url") class ItemFlingEffectSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = ItemFlingEffect fields = ("name", "url") class ItemSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Item fields = ("name", "url") class LanguageSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Language fields = ("name", "url") class LocationSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Location fields = ("name", "url") class LocationAreaSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = LocationArea fields = ("name", "url") class MachineSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Machine fields = ("url",) class MoveBattleStyleSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = MoveBattleStyle fields = ("name", "url") class MoveDamageClassSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = MoveDamageClass fields = ("name", "url") class MoveMetaAilmentSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = MoveMetaAilment fields = ("name", "url") class MoveMetaCategorySummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = MoveMetaCategory fields = ("name", "url") class MoveTargetSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = MoveTarget fields = ("name", "url") class MoveSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Move fields = ("name", "url") class MoveLearnMethodSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = MoveLearnMethod fields = ("name", "url") class NatureSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Nature fields = ("name", "url") class PalParkAreaSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = PalParkArea fields = ("name", "url") class PokeathlonStatSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = PokeathlonStat fields = ("name", "url") class PokedexSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Pokedex fields = ("name", "url") class PokemonColorSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = PokemonColor fields = ("name", "url") class PokemonHabitatSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = PokemonHabitat fields = ("name", "url") class PokemonShapeSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = PokemonShape fields = ("name", "url") class PokemonSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Pokemon fields = ("name", "url") class PokemonSpeciesSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = PokemonSpecies fields = ("name", "url") class PokemonFormSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = PokemonForm fields = ("name", "url") class RegionSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Region fields = ("name", "url") class StatSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Stat fields = ("name", "url") class SuperContestEffectSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = SuperContestEffect fields = ("url",) class TypeSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Type fields = ("name", "url") class VersionSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Version fields = ("name", "url") class VersionGroupSummarySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = VersionGroup fields = ("name", "url") ##################### # MAP SERIALIZERS # ##################### class BerryFlavorMapSerializer(serializers.ModelSerializer): berry = BerrySummarySerializer() flavor = BerryFlavorSummarySerializer(source="berry_flavor") class Meta: model = BerryFlavorMap fields = ("potency", "berry", "flavor") class ItemAttributeMapSerializer(serializers.ModelSerializer): item = ItemSummarySerializer() attribute = ItemAttributeSummarySerializer(source="item_attribute") class Meta: model = ItemAttributeMap fields = ( "item", "attribute", ) class MoveMetaStatChangeSerializer(serializers.ModelSerializer): stat = StatSummarySerializer() move = MoveSummarySerializer() class Meta: model = MoveMetaStatChange fields = ("change", "move", "stat") class NaturePokeathlonStatSerializer(serializers.ModelSerializer): pokeathlon_stat = PokeathlonStatSummarySerializer() nature = NatureSummarySerializer() class Meta: model = NaturePokeathlonStat fields = ("max_change", "nature", "pokeathlon_stat") class PokemonAbilitySerializer(serializers.ModelSerializer): pokemon = PokemonSummarySerializer() ability = AbilitySummarySerializer() class Meta: model = PokemonAbility fields = ("is_hidden", "slot", "ability", "pokemon") class PokemonAbilityPastSerializer(serializers.ModelSerializer): generation = GenerationSummarySerializer() ability = AbilitySummarySerializer() class Meta: model = PokemonAbilityPast fields = ("is_hidden", "pokemon", "generation", "slot", "ability") class PokemonDexEntrySerializer(serializers.ModelSerializer): entry_number = serializers.IntegerField(source="pokedex_number") pokedex = PokedexSummarySerializer() class Meta: model = PokemonDexNumber fields = ("entry_number", "pokedex") class PokemonTypeSerializer(serializers.ModelSerializer): pokemon = PokemonSummarySerializer() type = TypeSummarySerializer() class Meta: model = PokemonType fields = ("slot", "pokemon", "type") class PokemonFormTypeSerializer(serializers.ModelSerializer): pokemon_form = PokemonFormSummarySerializer() type = TypeSummarySerializer() class Meta: model = PokemonFormType fields = ("slot", "pokemon_form", "type") class PokemonTypePastSerializer(serializers.ModelSerializer): generation = GenerationSummarySerializer() type = TypeSummarySerializer() class Meta: model = PokemonTypePast fields = ("pokemon", "generation", "slot", "type") class PokedexVersionGroupSerializer(serializers.ModelSerializer): pokedex = PokedexSummarySerializer() version_group = VersionGroupSummarySerializer() class Meta: model = PokedexVersionGroup fields = ("pokedex", "version_group") class VersionGroupMoveLearnMethodSerializer(serializers.ModelSerializer): version_group = VersionGroupSummarySerializer() move_learn_method = MoveLearnMethodSummarySerializer() class Meta: model = ItemAttributeMap fields = ("version_group", "move_learn_method") class VersionGroupRegionSerializer(serializers.ModelSerializer): version_group = VersionGroupSummarySerializer() region = RegionSummarySerializer() class Meta: model = ItemAttributeMap fields = ( "version_group", "region", ) class EncounterConditionValueMapSerializer(serializers.ModelSerializer): condition_value = EncounterConditionValueSummarySerializer( source="encounter_condition_value" ) class Meta: model = EncounterConditionValueMap fields = ("condition_value",) ################################ # CHARACTERISTIC SERIALIZERS # ################################ class CharacteristicDescriptionSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = CharacteristicDescription fields = ("description", "language") class CharacteristicDetailSerializer(serializers.ModelSerializer): descriptions = CharacteristicDescriptionSerializer( many=True, read_only=True, source="characteristicdescription" ) highest_stat = StatSummarySerializer(source="stat") gene_modulo = serializers.IntegerField(source="gene_mod_5") possible_values = serializers.SerializerMethodField("get_values") class Meta: model = Characteristic fields = ( "id", "gene_modulo", "possible_values", "highest_stat", "descriptions", ) @extend_schema_field( field={ "type": "array", "items": { "type": "integer", "format": "int32", }, "examples": [[0, 5, 10, 15, 20, 25, 30]], } ) def get_values(self, obj): mod = obj.gene_mod_5 values = [] while mod <= 31: values.append(mod) mod += 5 return values ######################### # CONTEST SERIALIZERS # ######################### class SuperContestEffectFlavorTextSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = SuperContestEffectFlavorText fields = ("flavor_text", "language") class SuperContestEffectDetailSerializer(serializers.ModelSerializer): flavor_text_entries = SuperContestEffectFlavorTextSerializer( many=True, read_only=True, source="supercontesteffectflavortext" ) moves = MoveSummarySerializer(many=True, read_only=True, source="move") class Meta: model = SuperContestEffect fields = ("id", "appeal", "flavor_text_entries", "moves") class ContestEffectEffectTextSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = ContestEffectEffectText fields = ("effect", "language") class ContestEffectFlavorTextSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = ContestEffectFlavorText fields = ("flavor_text", "language") class ContestEffectDetailSerializer(serializers.ModelSerializer): effect_entries = ContestEffectEffectTextSerializer( many=True, read_only=True, source="contesteffecteffecttext" ) flavor_text_entries = ContestEffectFlavorTextSerializer( many=True, read_only=True, source="contesteffectflavortext" ) class Meta: model = ContestEffect fields = ("id", "appeal", "jam", "effect_entries", "flavor_text_entries") class ContestTypeNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = ContestTypeName fields = ("name", "color", "language") class ContestTypeDetailSerializer(serializers.ModelSerializer): names = ContestTypeNameSerializer( many=True, read_only=True, source="contesttypename" ) berry_flavor = BerryFlavorSummarySerializer(read_only=True, source="berryflavor") class Meta: model = ContestType fields = ("id", "name", "berry_flavor", "names") class SuperContestComboSerializer(serializers.ModelSerializer): first_move = MoveSummarySerializer() second_move = MoveSummarySerializer() class Meta: model = SuperContestCombo fields = ("first_move", "second_move") class ContestComboSerializer(serializers.ModelSerializer): first_move = MoveSummarySerializer() second_move = MoveSummarySerializer() class Meta: model = ContestCombo fields = ("first_move", "second_move") ######################## # REGION SERIALIZERS # ######################## class RegionNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = RegionName fields = ("name", "language") class RegionDetailSerializer(serializers.ModelSerializer): names = RegionNameSerializer(many=True, read_only=True, source="regionname") locations = LocationSummarySerializer(many=True, read_only=True, source="location") version_groups = serializers.SerializerMethodField("get_region_version_groups") pokedexes = PokedexSummarySerializer(many=True, read_only=True, source="pokedex") main_generation = GenerationSummarySerializer(read_only=True, source="generation") class Meta: model = Region fields = ( "id", "name", "locations", "main_generation", "names", "pokedexes", "version_groups", ) @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["red-blue"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/version-group/1/"], }, }, }, } ) def get_region_version_groups(self, obj): vg_regions = VersionGroupRegion.objects.filter(region=obj) data = VersionGroupRegionSerializer( vg_regions, many=True, context=self.context ).data groups = [] for group in data: groups.append(group["version_group"]) return groups ############################ # GENERATION SERIALIZERS # ############################ class GenerationNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = GenerationName fields = ("name", "language") class GenerationDetailSerializer(serializers.ModelSerializer): main_region = RegionSummarySerializer(source="region") names = GenerationNameSerializer(many=True, read_only=True, source="generationname") abilities = AbilitySummarySerializer(many=True, read_only=True, source="ability") moves = MoveSummarySerializer(many=True, read_only=True, source="move") pokemon_species = PokemonSpeciesSummarySerializer( many=True, read_only=True, source="pokemonspecies" ) types = TypeSummarySerializer(many=True, read_only=True, source="type") version_groups = VersionGroupSummarySerializer( many=True, read_only=True, source="versiongroup" ) class Meta: model = Generation fields = ( "id", "name", "abilities", "main_region", "moves", "names", "pokemon_species", "types", "version_groups", ) ######################## # GENDER SERIALIZERS # ######################## class GenderDetailSerializer(serializers.ModelSerializer): pokemon_species_details = serializers.SerializerMethodField("get_species") required_for_evolution = serializers.SerializerMethodField("get_required") class Meta: model = Gender fields = ("id", "name", "pokemon_species_details", "required_for_evolution") @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["rate", "pokemon_species"], "properties": { "rate": {"type": "integer", "format": "int32", "examples": [1]}, "pokemon_species": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["bulbasaur"]}, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/pokemon-species/1/" ], }, }, }, }, }, } ) def get_species(self, obj): species_objects = [] if obj.name == "female": species_objects = PokemonSpecies.objects.filter(gender_rate__gt=0) elif obj.name == "male": species_objects = PokemonSpecies.objects.filter(gender_rate__range=[0, 7]) elif obj.name == "genderless": species_objects = PokemonSpecies.objects.filter(gender_rate=-1) details = [] for species in species_objects: detail = OrderedDict() detail["rate"] = species.gender_rate detail["pokemon_species"] = PokemonSpeciesSummarySerializer( species, context=self.context ).data details.append(detail) return details @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["wormadam"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/pokemon-species/413/"], }, }, }, } ) def get_required(self, obj): evo_objects = PokemonEvolution.objects.filter(gender=obj) species_list = [] for evo in evo_objects: species = PokemonSpeciesSummarySerializer( evo.evolved_species, context=self.context ).data species_list.append(species) return species_list ############################# # GROWTH RATE SERIALIZERS # ############################# class ExperienceSerializer(serializers.ModelSerializer): class Meta: model = Experience fields = ("level", "experience") class GrowthRateDescriptionSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = GrowthRateDescription fields = ("description", "language") class GrowthRateDetailSerializer(serializers.ModelSerializer): descriptions = GrowthRateDescriptionSerializer( many=True, read_only=True, source="growthratedescription" ) levels = ExperienceSerializer(many=True, read_only=True, source="experience") pokemon_species = PokemonSpeciesSummarySerializer( many=True, read_only=True, source="pokemonspecies" ) class Meta: model = GrowthRate fields = ("id", "name", "formula", "descriptions", "levels", "pokemon_species") ########################## # LANGUAGE SERIALIZERS # ########################## class LanguageNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer(source="local_language") class Meta: model = LanguageName fields = ("name", "language") class LanguageDetailSerializer(serializers.ModelSerializer): names = LanguageNameSerializer( many=True, read_only=True, source="languagename_language" ) class Meta: model = Language fields = ("id", "name", "official", "iso639", "iso3166", "names") ######################################## # LOCATION AND ENCOUNTER SERIALIZERS # ######################################## class EncounterConditionNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = EncounterConditionName fields = ("name", "language") class EncounterConditionDetailSerializer(serializers.ModelSerializer): names = EncounterConditionNameSerializer( many=True, read_only=True, source="encounterconditionname" ) values = EncounterConditionValueSummarySerializer( many=True, read_only=True, source="encounterconditionvalue" ) class Meta: model = EncounterCondition fields = ("id", "name", "values", "names") class EncounterConditionValueNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = EncounterConditionValueName fields = ("name", "language") class EncounterConditionValueDetailSerializer(serializers.ModelSerializer): condition = EncounterConditionSummarySerializer(source="encounter_condition") names = EncounterConditionValueNameSerializer( many=True, read_only=True, source="encounterconditionvaluename" ) class Meta: model = EncounterConditionValue fields = ("id", "name", "condition", "names") class EncounterMethodNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = EncounterMethodName fields = ("name", "language") class EncounterMethodDetailSerializer(serializers.ModelSerializer): names = EncounterMethodNameSerializer( many=True, read_only=True, source="encountermethodname" ) class Meta: model = EncounterMethod fields = ("id", "name", "order", "names") class EncounterSlotSerializer(serializers.ModelSerializer): encounter_method = EncounterMethodSummarySerializer() chance = serializers.IntegerField(source="rarity") class Meta: model = EncounterSlot fields = ("id", "slot", "chance", "encounter_method", "version_group") class EncounterDetailSerializer(serializers.ModelSerializer): version = VersionSummarySerializer() location_area = LocationAreaSummarySerializer() pokemon = PokemonSummarySerializer() condition_values = serializers.SerializerMethodField("get_encounter_conditions") class Meta: model = Encounter fields = ( "min_level", "max_level", "version", "encounter_slot", "pokemon", "location_area", "condition_values", ) def get_encounter_conditions(self, obj): condition_values = EncounterConditionValueMap.objects.filter(encounter=obj) data = EncounterConditionValueMapSerializer( condition_values, many=True, context=self.context ).data values = [] for map in data: values.append(map["condition_value"]) return values class LocationAreaEncounterRateSerializer(serializers.ModelSerializer): encounter_method = EncounterMethodSummarySerializer() version = VersionSummarySerializer() class Meta: model = LocationAreaEncounterRate fields = ("rate", "encounter_method", "version") class LocationAreaNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = LocationAreaName fields = ("name", "language") class LocationAreaDetailSerializer(serializers.ModelSerializer): location = LocationSummarySerializer() encounter_method_rates = serializers.SerializerMethodField("get_method_rates") pokemon_encounters = serializers.SerializerMethodField("get_encounters") names = LocationAreaNameSerializer( many=True, read_only=True, source="locationareaname" ) class Meta: model = LocationArea fields = ( "id", "name", "game_index", "encounter_method_rates", "location", "names", "pokemon_encounters", ) @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["encounter_method", "version_details"], "properties": { "encounter_method": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["old-rod"]}, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/encounter-method/2/" ], }, }, }, "version_details": { "type": "array", "items": { "type": "object", "required": ["rate", "version"], "properties": { "rate": { "type": "integer", "format": "int32", "examples": [5], }, "version": { "type": "object", "required": ["name", "url"], "properties": { "name": { "type": "string", "examples": ["platinum"], }, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/version/14/" ], }, }, }, }, }, }, }, }, } ) def get_method_rates(self, obj): # Get encounters related to this area and pull out unique encounter methods encounter_rates = LocationAreaEncounterRate.objects.filter( location_area=obj ).order_by("encounter_method_id") method_ids = encounter_rates.values("encounter_method_id").distinct() encounter_rate_list = [] for id in method_ids: encounter_rate_details = OrderedDict() # Get each Unique Item by ID encounter_method_object = EncounterMethod.objects.get( pk=id["encounter_method_id"] ) encounter_method_data = EncounterMethodSummarySerializer( encounter_method_object, context=self.context ).data encounter_rate_details["encounter_method"] = encounter_method_data # Get Versions associated with each unique item area_encounter_objects = encounter_rates.filter( encounter_method_id=id["encounter_method_id"] ) serializer = LocationAreaEncounterRateSerializer( area_encounter_objects, many=True, context=self.context ) encounter_rate_details["version_details"] = [] for area_encounter in serializer.data: version_detail = OrderedDict() version_detail["rate"] = area_encounter["rate"] version_detail["version"] = area_encounter["version"] encounter_rate_details["version_details"].append(version_detail) encounter_rate_list.append(encounter_rate_details) return encounter_rate_list @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["pokemon", "version_details"], "properties": { "pokemon": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["tentacool"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/pokemon/72/"], }, }, }, "version_details": { "type": "array", "items": { "type": "object", "required": ["version", "max_chance", "encounter_details"], "properties": { "version": { "type": "object", "required": ["name", "url"], "properties": { "name": { "type": "string", "examples": ["diamond"], }, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/version/12/" ], }, }, }, "max_chance": { "type": "integer", "format": "int32", "examples": [60], }, "encounter_details": { "type": "object", "required": [ "min_level", "max_level", "condition_value", "chance", "method", ], "properties": { "min_level": { "type": "integer", "format": "int32", "examples": [20], }, "max_level": { "type": "integer", "format": "int32", "examples": [30], }, "condition_values": { "type": "object", "required": ["name", "url"], "properties": { "name": { "type": "string", "examples": ["slot2-sapphire"], }, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/encounter-condition-value/10/" ], }, }, }, "chance": { "type": "integer", "format": "int32", "examples": [60], }, "method": { "type": "object", "required": ["name", "url"], "properties": { "name": { "type": "string", "examples": ["surf"], }, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/encounter-method/5/" ], }, }, }, }, }, }, }, }, }, }, } ) def get_encounters(self, obj): # get versions for later use version_objects = Version.objects.all() version_data = VersionSummarySerializer( version_objects, many=True, context=self.context ).data # all encounters associated with location area all_encounters = Encounter.objects.filter(location_area=obj).order_by("pokemon") encounters_list = [] # break encounters into pokemon groupings for poke in all_encounters.values("pokemon").distinct(): pokemon_object = Pokemon.objects.get(pk=poke["pokemon"]) pokemon_detail = OrderedDict() pokemon_detail["pokemon"] = PokemonSummarySerializer( pokemon_object, context=self.context ).data pokemon_detail["version_details"] = [] poke_encounters = all_encounters.filter(pokemon=poke["pokemon"]).order_by( "version" ) # each pokemon has multiple versions it could be encountered in for ver in poke_encounters.values("version").distinct(): version_detail = OrderedDict() version_detail["version"] = version_data[ver["version"] - 1] version_detail["max_chance"] = 0 version_detail["encounter_details"] = [] poke_data = EncounterDetailSerializer( poke_encounters.filter(version=ver["version"]), many=True, context=self.context, ).data # each version has multiple ways a pokemon can be encountered for encounter in poke_data: slot = EncounterSlot.objects.get(pk=encounter["encounter_slot"]) slot_data = EncounterSlotSerializer(slot, context=self.context).data del encounter["pokemon"] del encounter["encounter_slot"] del encounter["location_area"] del encounter["version"] encounter["chance"] = slot_data["chance"] version_detail["max_chance"] += slot_data["chance"] encounter["method"] = slot_data["encounter_method"] version_detail["encounter_details"].append(encounter) pokemon_detail["version_details"].append(version_detail) encounters_list.append(pokemon_detail) return encounters_list class LocationGameIndexSerializer(serializers.ModelSerializer): generation = GenerationSummarySerializer() class Meta: model = LocationGameIndex fields = ("game_index", "generation") class LocationNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = LocationName fields = ("name", "language") class LocationDetailSerializer(serializers.ModelSerializer): region = RegionSummarySerializer() names = LocationNameSerializer(many=True, read_only=True, source="locationname") game_indices = LocationGameIndexSerializer( many=True, read_only=True, source="locationgameindex" ) areas = LocationAreaSummarySerializer( many=True, read_only=True, source="locationarea" ) class Meta: model = Location fields = ("id", "name", "region", "names", "game_indices", "areas") ######################### # ABILITY SERIALIZERS # ######################### class AbilityEffectTextSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = AbilityEffectText fields = ("effect", "short_effect", "language") class AbilityFlavorTextSerializer(serializers.ModelSerializer): flavor_text = serializers.CharField() language = LanguageSummarySerializer() version_group = VersionGroupSummarySerializer() class Meta: model = AbilityFlavorText fields = ("flavor_text", "language", "version_group") class AbilityChangeEffectTextSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = AbilityChangeEffectText fields = ( "effect", "language", ) class AbilityChangeSerializer(serializers.ModelSerializer): version_group = VersionGroupSummarySerializer() effect_entries = AbilityChangeEffectTextSerializer( many=True, read_only=True, source="abilitychangeeffecttext" ) class Meta: model = AbilityChange fields = ("version_group", "effect_entries") class AbilityNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = AbilityName fields = ("name", "language") class AbilityDetailSerializer(serializers.ModelSerializer): effect_entries = AbilityEffectTextSerializer( many=True, read_only=True, source="abilityeffecttext" ) flavor_text_entries = AbilityFlavorTextSerializer( many=True, read_only=True, source="abilityflavortext" ) names = AbilityNameSerializer(many=True, read_only=True, source="abilityname") generation = GenerationSummarySerializer() effect_changes = AbilityChangeSerializer( many=True, read_only=True, source="abilitychange" ) pokemon = serializers.SerializerMethodField("get_ability_pokemon") class Meta: model = Ability fields = ( "id", "name", "is_main_series", "generation", "names", "effect_entries", "effect_changes", "flavor_text_entries", "pokemon", ) @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["is_hidden", "slot", "pokemon"], "properties": { "is_hidden": {"type": "boolean"}, "slot": {"type": "integer", "format": "int32", "examples": [3]}, "pokemon": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["gloom"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/pokemon/44/"], }, }, }, }, }, } ) def get_ability_pokemon(self, obj): pokemon_ability_objects = PokemonAbility.objects.filter(ability=obj) data = PokemonAbilitySerializer( pokemon_ability_objects, many=True, context=self.context ).data pokemon = [] for poke in data: del poke["ability"] pokemon.append(poke) return pokemon ###################### # STAT SERIALIZERS # ###################### class StatNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = StatName fields = ("name", "language") class StatDetailSerializer(serializers.ModelSerializer): names = StatNameSerializer(many=True, read_only=True, source="statname") move_damage_class = MoveDamageClassSummarySerializer() characteristics = CharacteristicSummarySerializer( many=True, read_only=True, source="characteristic" ) affecting_moves = serializers.SerializerMethodField("get_moves_that_affect") affecting_natures = serializers.SerializerMethodField("get_natures_that_affect") class Meta: model = Stat fields = ( "id", "name", "game_index", "is_battle_only", "affecting_moves", "affecting_natures", "characteristics", "move_damage_class", "names", ) @extend_schema_field( field={ "type": "object", "required": ["decrease", "increase"], "properties": { "increase": { "type": "array", "items": { "type": "object", "required": ["change", "move"], "properties": { "change": { "type": "integer", "format": "int32", "examples": [-1], }, "move": { "type": "object", "required": ["name", "url"], "properties": { "name": { "type": "string", "examples": ["swords-dance"], }, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/move/14/" ], }, }, }, }, }, }, "decrease": { "type": "array", "items": { "type": "object", "required": ["change", "move"], "properties": { "change": { "type": "integer", "format": "int32", "examples": [5], }, "move": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["growl"]}, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/move/45/" ], }, }, }, }, }, }, }, } ) def get_moves_that_affect(self, obj): stat_change_objects = MoveMetaStatChange.objects.filter(stat=obj) stat_changes = MoveMetaStatChangeSerializer( stat_change_objects, many=True, context=self.context ).data changes = OrderedDict([("increase", []), ("decrease", [])]) for change in stat_changes: del change["stat"] if change["change"] > 0: changes["increase"].append(change) else: changes["decrease"].append(change) return changes @extend_schema_field( field={ "type": "object", "required": ["increase", "decrease"], "properties": { "increase": { "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["lonely"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/nature/6/"], }, }, }, }, "decrease": { "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["bold"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/nature/2/"], }, }, }, }, }, } ) def get_natures_that_affect(self, obj): increase_objects = Nature.objects.filter(increased_stat=obj) increases = NatureSummarySerializer( increase_objects, many=True, context=self.context ).data decrease_objects = Nature.objects.filter(decreased_stat=obj) decreases = NatureSummarySerializer( decrease_objects, many=True, context=self.context ).data return OrderedDict([("increase", increases), ("decrease", decreases)]) ############################# # ITEM POCKET SERIALIZERS # ############################# class ItemPocketNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = ItemName fields = ("name", "language") class ItemPocketDetailSerializer(serializers.ModelSerializer): names = ItemPocketNameSerializer(many=True, read_only=True, source="itempocketname") categories = ItemCategorySummarySerializer( many=True, read_only=True, source="itemcategory" ) class Meta: model = ItemPocket fields = ("id", "name", "categories", "categories", "names") ############################### # ITEM CATEGORY SERIALIZERS # ############################### class ItemCategoryNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = ItemName fields = ("name", "language") class ItemCategoryDetailSerializer(serializers.ModelSerializer): names = ItemCategoryNameSerializer( many=True, read_only=True, source="itemcategoryname" ) pocket = ItemPocketSummarySerializer(source="item_pocket") items = ItemSummarySerializer(many=True, read_only=True, source="item") class Meta: model = ItemCategory fields = ("id", "name", "items", "names", "pocket") ################################ # ITEM ATTRIBUTE SERIALIZERS # ################################ class ItemAttributeNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = ItemAttributeName fields = ("name", "language") class ItemAttributeDescriptionSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = ItemAttributeDescription fields = ("description", "language") class ItemAttributeDetailSerializer(serializers.ModelSerializer): names = ItemAttributeNameSerializer( many=True, read_only=True, source="itemattributename" ) descriptions = ItemAttributeDescriptionSerializer( many=True, read_only=True, source="itemattributedescription" ) items = serializers.SerializerMethodField("get_attribute_items") class Meta: model = ItemAttribute fields = ("id", "name", "descriptions", "items", "names") @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["master-ball"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/item/1/"], }, }, }, } ) def get_attribute_items(self, obj): item_map_objects = ItemAttributeMap.objects.filter(item_attribute=obj) items = [] for map in item_map_objects: item_obj = Item.objects.get(pk=map.item.id) item = ItemSummarySerializer(item_obj, context=self.context).data items.append(item) return items ################################### # ITEM FLING EFFECT SERIALIZERS # ################################### class ItemFlingEffectEffectTextSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = ItemFlingEffectEffectText fields = ("effect", "language") class ItemFlingEffectDetailSerializer(serializers.ModelSerializer): effect_entries = ItemFlingEffectEffectTextSerializer( many=True, read_only=True, source="itemflingeffecteffecttext" ) items = ItemSummarySerializer(many=True, read_only=True, source="item") class Meta: model = ItemFlingEffect fields = ("id", "name", "effect_entries", "items") ####################### # ITEM SERIALIZERS # ####################### class ItemFlavorTextSerializer(serializers.ModelSerializer): text = serializers.CharField(source="flavor_text") language = LanguageSummarySerializer() version_group = VersionGroupSummarySerializer() class Meta: model = ItemFlavorText fields = ("text", "version_group", "language") class ItemEffectTextSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = ItemEffectText fields = ("effect", "short_effect", "language") class ItemGameIndexSerializer(serializers.ModelSerializer): generation = GenerationSummarySerializer() class Meta: model = ItemGameIndex fields = ("game_index", "generation") class ItemNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = ItemName fields = ("name", "language") class ItemSpritesSerializer(serializers.ModelSerializer): class Meta: model = ItemSprites fields = ("sprites",) class ItemDetailSerializer(serializers.ModelSerializer): names = ItemNameSerializer(many=True, read_only=True, source="itemname") game_indices = ItemGameIndexSerializer( many=True, read_only=True, source="itemgameindex" ) effect_entries = ItemEffectTextSerializer( many=True, read_only=True, source="itemeffecttext" ) flavor_text_entries = ItemFlavorTextSerializer( many=True, read_only=True, source="itemflavortext" ) category = ItemCategorySummarySerializer(source="item_category") attributes = serializers.SerializerMethodField("get_item_attributes") fling_effect = ItemFlingEffectSummarySerializer(source="item_fling_effect") held_by_pokemon = serializers.SerializerMethodField(source="get_held_by_pokemon") baby_trigger_for = serializers.SerializerMethodField(source="get_baby_trigger_for") sprites = serializers.SerializerMethodField("get_item_sprites") machines = serializers.SerializerMethodField("get_item_machines") class Meta: model = Item fields = ( "id", "name", "cost", "fling_power", "fling_effect", "attributes", "category", "effect_entries", "flavor_text_entries", "game_indices", "names", "held_by_pokemon", "sprites", "baby_trigger_for", "machines", ) @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["machine", "version_group"], "properties": { "machine": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/machine/1/"], }, "version_group": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["sword-shield"]}, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/version-group/20/" ], }, }, }, }, }, } ) def get_item_machines(self, obj): machine_objects = Machine.objects.filter(item=obj) machines = [] for machine_object in machine_objects: machine_data = MachineSummarySerializer( machine_object, context=self.context ).data version_group_data = VersionGroupSummarySerializer( machine_object.version_group, context=self.context ).data machines.append( {"machine": machine_data, "version_group": version_group_data} ) return machines @extend_schema_field( field={ "type": "object", "required": ["default"], "properties": { "default": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/media/sprites/items/master-ball.png" ], } }, } ) def get_item_sprites(self, obj): sprites_object = ItemSprites.objects.get(item_id=obj) return sprites_object.sprites @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["countable"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/item-attribute/1/"], }, }, }, } ) def get_item_attributes(self, obj): item_attribute_maps = ItemAttributeMap.objects.filter(item=obj) serializer = ItemAttributeMapSerializer( item_attribute_maps, many=True, context=self.context ) data = serializer.data attributes = [] for map in data: attribute = OrderedDict() attribute["name"] = map["attribute"]["name"] attribute["url"] = map["attribute"]["url"] attributes.append(attribute) return attributes @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["pokemon", "version-details"], "properties": { "pokemon": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["farfetchd"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/pokemon/83/"], }, }, }, "version-details": { "type": "array", "items": { "type": "object", "required": ["rarity", "version"], "properties": { "rarity": { "type": "integer", "format": "int32", "examples": [5], }, "version": { "type": "object", "required": ["name", "url"], "properties": { "name": { "type": "string", "examples": ["ruby"], }, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/version/7/" ], }, }, }, }, }, }, }, }, } ) def get_held_by_pokemon(self, obj): pokemon_items = PokemonItem.objects.filter(item=obj).order_by("pokemon_id") pokemon_ids = pokemon_items.values("pokemon_id").distinct() pokemon_list = [] for id in pokemon_ids: item_pokemon_details = OrderedDict() # Get each Unique Item by ID pokemon_object = Pokemon.objects.get(pk=id["pokemon_id"]) pokemon_data = PokemonSummarySerializer( pokemon_object, context=self.context ).data item_pokemon_details["pokemon"] = pokemon_data # Get Versions associated with each unique item pokemon_item_objects = pokemon_items.filter(pokemon_id=id["pokemon_id"]) serializer = PokemonItemSerializer( pokemon_item_objects, many=True, context=self.context ) item_pokemon_details["version_details"] = [] for pokemon in serializer.data: version_detail = OrderedDict() version_detail["rarity"] = pokemon["rarity"] version_detail["version"] = pokemon["version"] item_pokemon_details["version_details"].append(version_detail) pokemon_list.append(item_pokemon_details) return pokemon_list @extend_schema_field( field={ "type": "object", "required": ["url"], "properties": { "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/evolution-chain/51/"], } }, } ) def get_baby_trigger_for(self, obj): try: chain_object = EvolutionChain.objects.get(baby_trigger_item=obj) data = EvolutionChainSummarySerializer( chain_object, context=self.context ).data except EvolutionChain.DoesNotExist: data = None return data ######################## # NATURE SERIALIZERS # ######################## class NatureBattleStylePreferenceSerializer(serializers.ModelSerializer): move_battle_style = MoveBattleStyleSummarySerializer() class Meta: model = NatureBattleStylePreference fields = ( "low_hp_preference", "high_hp_preference", "move_battle_style", ) class NatureNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = NatureName fields = ("name", "language") class NatureDetailSerializer(serializers.ModelSerializer): names = NatureNameSerializer(many=True, read_only=True, source="naturename") decreased_stat = StatSummarySerializer() increased_stat = StatSummarySerializer() likes_flavor = BerryFlavorSummarySerializer() hates_flavor = BerryFlavorSummarySerializer() berries = BerrySummarySerializer(many=True, read_only=True, source="berry") pokeathlon_stat_changes = serializers.SerializerMethodField("get_pokeathlon_stats") move_battle_style_preferences = NatureBattleStylePreferenceSerializer( many=True, read_only=True, source="naturebattlestylepreference" ) class Meta: model = Nature fields = ( "id", "name", "decreased_stat", "increased_stat", "likes_flavor", "hates_flavor", "berries", "pokeathlon_stat_changes", "move_battle_style_preferences", "names", ) @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["max_change", "pokeathlon_stat"], "properties": { "max_change": { "type": "integer", "format": "int32", "examples": [1], }, "pokeathlon_stat": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["power"]}, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/pokeathlon-stat/2/" ], }, }, }, }, }, } ) def get_pokeathlon_stats(self, obj): pokeathlon_stat_objects = NaturePokeathlonStat.objects.filter(nature=obj) pokeathlon_stats = NaturePokeathlonStatSerializer( pokeathlon_stat_objects, many=True, context=self.context ).data for stat in pokeathlon_stats: del stat["nature"] return pokeathlon_stats ####################### # BERRY SERIALIZERS # ####################### class BerryFirmnessNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = BerryFirmnessName fields = ("name", "language") class BerryFirmnessDetailSerializer(serializers.ModelSerializer): names = BerryFirmnessNameSerializer( many=True, read_only=True, source="berryfirmnessname" ) berries = BerrySummarySerializer(many=True, read_only=True, source="berry") class Meta: model = BerryFirmness fields = ("id", "name", "berries", "names") class BerryFlavorNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = BerryFlavorName fields = ("name", "language") class BerryFlavorDetailSerializer(serializers.ModelSerializer): names = BerryFlavorNameSerializer( many=True, read_only=True, source="berryflavorname" ) contest_type = ContestTypeSummarySerializer() berries = serializers.SerializerMethodField("get_berries_with_flavor") class Meta: model = BerryFlavor fields = ("id", "name", "berries", "contest_type", "names") @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["potency", "berry"], "properties": { "potency": {"type": "integer", "examples": [10]}, "berry": { "type": "object", "require": ["name", "url"], "properties": { "name": { "type": "string", "description": "The name of the berry", "examples": ["rowap"], }, "url": { "type": "string", "format": "uri", "description": "The URL to get more information about the berry", "examples": ["https://pokeapi.co/api/v2/berry/64/"], }, }, }, }, }, } ) def get_berries_with_flavor(self, obj): flavor_map_objects = BerryFlavorMap.objects.filter( berry_flavor=obj, potency__gt=0 ).order_by("potency") flavor_maps = BerryFlavorMapSerializer( flavor_map_objects, many=True, context=self.context ).data for map in flavor_maps: del map["flavor"] return flavor_maps class BerryDetailSerializer(serializers.ModelSerializer): item = ItemSummarySerializer() natural_gift_type = TypeSummarySerializer() firmness = BerryFirmnessSummarySerializer(source="berry_firmness") flavors = serializers.SerializerMethodField("get_berry_flavors") class Meta: model = Berry fields = ( "id", "name", "growth_time", "max_harvest", "natural_gift_power", "size", "smoothness", "soil_dryness", "firmness", "flavors", "item", "natural_gift_type", ) @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["potency", "flavor"], "properties": { "potency": {"type": "integer", "examples": [10]}, "flavor": { "type": "object", "require": ["name", "url"], "properties": { "name": { "type": "string", "description": "The name of the flavor", "examples": ["spicy"], }, "url": { "type": "string", "format": "uri", "description": "The URL to get more information about the flavor", "examples": [ "https://pokeapi.co/api/v2/berry-flavor/1/" ], }, }, }, }, }, } ) def get_berry_flavors(self, obj): flavor_map_objects = BerryFlavorMap.objects.filter(berry=obj) flavor_maps = BerryFlavorMapSerializer( flavor_map_objects, many=True, context=self.context ).data flavors = [] for map in flavor_maps: del map["berry"] flavors.append(map) return flavors ########################### # EGG GROUP SERIALIZERS # ########################### class PokemonEggGroupSerializer(serializers.ModelSerializer): species = PokemonSpeciesSummarySerializer(source="pokemon_species") egg_group = EggGroupSummarySerializer() class Meta: model = PokemonEggGroup fields = ("species", "egg_group") class EggGroupNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = EggGroupName fields = ("name", "language") class EggGroupDetailSerializer(serializers.ModelSerializer): names = EggGroupNameSerializer(many=True, read_only=True, source="egggroupname") pokemon_species = serializers.SerializerMethodField("get_species") class Meta: model = EggGroup fields = ("id", "name", "names", "pokemon_species") @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["potency", "flavor"], "properties": { "name": { "type": "string", "description": "Pokemon species name.", "examples": ["bulbasaur"], }, "url": { "type": "string", "format": "uri", "description": "The URL to get more information about the species", "examples": ["https://pokeapi.co/api/v2/pokemon-species/1/"], }, }, }, } ) def get_species(self, obj): results = PokemonEggGroup.objects.filter(egg_group=obj) data = PokemonEggGroupSerializer(results, many=True, context=self.context).data associated_species = [] for species in data: associated_species.append(species["species"]) return associated_species ###################### # TYPE SERIALIZERS # ###################### # https://stackoverflow.com/a/45987450/3482533 class TypeEfficacySerializer(serializers.ModelSerializer): class Meta: model = TypeEfficacy fields = "__all__" class TypeEfficacyPastSerializer(serializers.ModelSerializer): generation = GenerationSummarySerializer() class Meta: model = TypeEfficacyPast fields = ("target_type", "damage_type", "damage_factor", "generation") class TypeGameIndexSerializer(serializers.ModelSerializer): generation = GenerationSummarySerializer() class Meta: model = TypeGameIndex fields = ("game_index", "generation") class TypeNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = TypeName fields = ("name", "language") class TypeSpriteSerializer(serializers.ModelSerializer): class Meta: model = TypeSprites fields = ("sprites",) class TypeDetailSerializer(serializers.ModelSerializer): """ Serializer for the Type resource """ generation = GenerationSummarySerializer() names = AbilityNameSerializer(many=True, read_only=True, source="typename") game_indices = TypeGameIndexSerializer( many=True, read_only=True, source="typegameindex" ) move_damage_class = MoveDamageClassSummarySerializer() damage_relations = serializers.SerializerMethodField("get_type_relationships") past_damage_relations = serializers.SerializerMethodField( "get_type_past_relationships" ) pokemon = serializers.SerializerMethodField("get_type_pokemon") moves = MoveSummarySerializer(many=True, read_only=True, source="move") sprites = serializers.SerializerMethodField("get_type_sprites") class Meta: model = Type fields = ( "id", "name", "damage_relations", "past_damage_relations", "game_indices", "generation", "move_damage_class", "names", "pokemon", "moves", "sprites", ) def get_type_sprites(self, obj): sprites_object = TypeSprites.objects.get(type_id=obj) return sprites_object.sprites # adds an entry for the given type with the given damage # factor in the given direction to the set of relations def add_type_entry(self, relations, type, damage_factor, direction="_damage_to"): if damage_factor == 200: relations["double" + direction].append( TypeSummarySerializer(type, context=self.context).data ) elif damage_factor == 50: relations["half" + direction].append( TypeSummarySerializer(type, context=self.context).data ) elif damage_factor == 0: relations["no" + direction].append( TypeSummarySerializer(type, context=self.context).data ) @extend_schema_field( field={ "type": "object", "required": [ "no_damage_to", "half_damage_to", "double_damage_to", "no_damage_from", "half_damage_from", "double_damage_from", ], "properties": { "no_damage_to": { "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["flying"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/type/3/"], }, }, }, }, "half_damage_to": { "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["bug"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/type/7/"], }, }, }, }, "double_damage_to": { "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["poison"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/type/4/"], }, }, }, }, "no_damage_from": { "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["electric"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/type/13/"], }, }, }, }, "half_damage_from": { "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["poison"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/type/4/"], }, }, }, }, "double_damage_from": { "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["water"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/type/11/"], }, }, }, }, }, } ) def get_type_relationships(self, obj): relations = OrderedDict() relations["no_damage_to"] = [] relations["half_damage_to"] = [] relations["double_damage_to"] = [] relations["no_damage_from"] = [] relations["half_damage_from"] = [] relations["double_damage_from"] = [] # Damage To results = TypeEfficacy.objects.filter(damage_type=obj) serializer = TypeEfficacySerializer(results, many=True, context=self.context) for relation in serializer.data: type = Type.objects.get(pk=relation["target_type"]) damage_factor = relation["damage_factor"] self.add_type_entry(relations, type, damage_factor, direction="_damage_to") # Damage From results = TypeEfficacy.objects.filter(target_type=obj) serializer = TypeEfficacySerializer(results, many=True, context=self.context) for relation in serializer.data: type = Type.objects.get(pk=relation["damage_type"]) damage_factor = relation["damage_factor"] self.add_type_entry( relations, type, damage_factor, direction="_damage_from" ) return relations # takes a list of past type relations by generation and # returns a list of lists where each list has the entries # for a single generation def group_relations_by_generation(self, serializer_data): data_by_gen = [] current_generation = "" generation_data = [] for relation in serializer_data: gen_name = relation["generation"]["name"] if gen_name != current_generation: # first item for this generation so create its list current_generation = gen_name generation_data = [relation] data_by_gen.append(generation_data) else: # add to this generation's list generation_data.append(relation) return data_by_gen # removes the entry for the given type in # the given direction from the set of relations def remove_type_entry(self, relations, type, direction="_damage_to"): for k in ["double", "half", "no"]: rel_list = relations[k + direction] for i, o in enumerate(rel_list): if o["name"] == type.name: del rel_list[i] return # returns past type relationships for the given type object @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["generation", "damage_relations"], "properties": { "generation": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["generation-v"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/generation/5/"], }, }, }, "damage_relations": { "type": "object", "required": [ "no_damage_to", "half_damage_to", "double_damage_to", "no_damage_from", "half_damage_from", "double_damage_from", ], "properties": { "no_damage_to": { "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": { "type": "string", "examples": ["flying"], }, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/type/3/" ], }, }, }, }, "half_damage_to": { "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["bug"]}, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/type/7/" ], }, }, }, }, "double_damage_to": { "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": { "type": "string", "examples": ["poison"], }, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/type/4/" ], }, }, }, }, "no_damage_from": { "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": { "type": "string", "examples": ["electric"], }, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/type/13/" ], }, }, }, }, "half_damage_from": { "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": { "type": "string", "examples": ["poison"], }, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/type/4/" ], }, }, }, }, "double_damage_from": { "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": { "type": "string", "examples": ["water"], }, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/type/11/" ], }, }, }, }, }, }, }, }, } ) def get_type_past_relationships(self, obj): # collect data from DB damage_type_results = list(TypeEfficacyPast.objects.filter(damage_type=obj)) target_type_results = list(TypeEfficacyPast.objects.filter(target_type=obj)) serializer = TypeEfficacyPastSerializer( damage_type_results + target_type_results, many=True, context=self.context ) # group data by generation data_by_gen = self.group_relations_by_generation(serializer.data) # process each generation's data in turn final_data = [] past_relations = {} for gen_data in data_by_gen: # create past relations object for this generation past_relations = OrderedDict() # set generation past_relations["generation"] = gen_data[0]["generation"] # use current damage relations object past_relations["damage_relations"] = self.get_type_relationships(obj) relations = past_relations["damage_relations"] current_gen = Generation.objects.get(name=gen_data[0]["generation"]["name"]) # remove types not yet introduced # e.g. Poison has no effect on Steel, but Steel was not present in generation I # so it should be absent from the list relations["no_damage_to"] = self.remove_newer_types( relations["no_damage_to"], current_gen ) relations["half_damage_to"] = self.remove_newer_types( relations["half_damage_to"], current_gen ) relations["double_damage_to"] = self.remove_newer_types( relations["double_damage_to"], current_gen ) relations["no_damage_from"] = self.remove_newer_types( relations["no_damage_from"], current_gen ) relations["half_damage_from"] = self.remove_newer_types( relations["half_damage_from"], current_gen ) relations["double_damage_from"] = self.remove_newer_types( relations["double_damage_from"], current_gen ) # populate offensive relations results = list(filter(lambda x: x["damage_type"] == obj.id, gen_data)) for relation in results: type = Type.objects.get(pk=relation["target_type"]) # remove conflicting entry if it exists self.remove_type_entry(relations, type, direction="_damage_to") # add entry damage_factor = relation["damage_factor"] self.add_type_entry( relations, type, damage_factor, direction="_damage_to" ) del relation["generation"] # populate defensive relations results = list(filter(lambda x: x["target_type"] == obj.id, gen_data)) for relation in results: type = Type.objects.get(pk=relation["damage_type"]) # remove conflicting entry if it exists self.remove_type_entry(relations, type, direction="_damage_from") # add entry damage_factor = relation["damage_factor"] self.add_type_entry( relations, type, damage_factor, direction="_damage_from" ) del relation["generation"] # add to final list final_data.append(past_relations) return final_data def remove_newer_types(self, relations, current_gen): return list(filter(lambda x: self.type_is_present(x, current_gen), relations)) def type_is_present(self, type, current_gen): type_obj = Type.objects.get(name=type["name"]) gen_introduced = Generation.objects.get(pk=type_obj.generation.id) return gen_introduced.id <= current_gen.id @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["potency", "flavor"], "properties": { "slot": {"type": "integer", "examples": [1]}, "pokemon": { "type": "object", "require": ["name", "url"], "properties": { "name": { "type": "string", "description": "The name of the pokemon", "examples": ["sandshrew"], }, "url": { "type": "string", "format": "uri", "description": "The URL to get more information about the pokemon", "examples": ["https://pokeapi.co/api/v2/pokemon/27/"], }, }, }, }, }, } ) def get_type_pokemon(self, obj): poke_type_objects = PokemonType.objects.filter(type=obj) poke_types = PokemonTypeSerializer( poke_type_objects, many=True, context=self.context ).data for poke_type in poke_types: del poke_type["type"] return poke_types ######################### # MACHINE SERIALIZERS # ######################### class MachineDetailSerializer(serializers.ModelSerializer): item = ItemSummarySerializer() version_group = VersionGroupSummarySerializer() move = MoveSummarySerializer() class Meta: model = Machine fields = ("id", "item", "version_group", "move") ################################### # MOVE BATTLE STYLE SERIALIZERS # ################################### class MoveBattleStyleNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = MoveBattleStyleName fields = ("name", "language") class MoveBattleStyleDetailSerializer(serializers.ModelSerializer): names = MoveBattleStyleNameSerializer( many=True, read_only=True, source="movebattlestylename" ) class Meta: model = MoveBattleStyle fields = ("id", "name", "names") ################################### # MOVE DAMAGE CLASS SERIALIZERS # ################################### class MoveDamageClassNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = MoveDamageClassName fields = ("name", "language") class MoveDamageClassDescriptionSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = MoveDamageClassDescription fields = ("description", "language") class MoveDamageClassDetailSerializer(serializers.ModelSerializer): names = MoveDamageClassNameSerializer( many=True, read_only=True, source="movedamageclassname" ) descriptions = MoveDamageClassDescriptionSerializer( many=True, read_only=True, source="movedamageclassdescription" ) moves = MoveSummarySerializer(many=True, read_only=True, source="move") class Meta: model = MoveDamageClass fields = ( "id", "name", "descriptions", "moves", "names", ) ########################### # MOVE META SERIALIZERS # ########################### class MoveMetaAilmentNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = MoveMetaAilmentName fields = ("name", "language") class MoveMetaAilmentDetailSerializer(serializers.ModelSerializer): names = MoveMetaAilmentNameSerializer( many=True, read_only=True, source="movemetaailmentname" ) moves = serializers.SerializerMethodField("get_ailment_moves") class Meta: model = MoveMetaAilment fields = ("id", "name", "moves", "names") @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["thunder-punch"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/move/9/"], }, }, }, } ) def get_ailment_moves(self, obj): move_meta_objects = MoveMeta.objects.filter(move_meta_ailment=obj) moves = [] for meta in move_meta_objects: move_obj = Move.objects.get(pk=meta.move.id) data = MoveSummarySerializer(move_obj, context=self.context).data moves.append(data) return moves class MoveMetaCategoryDescriptionSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = MoveMetaCategoryDescription fields = ("description", "language") class MoveMetaCategoryDetailSerializer(serializers.ModelSerializer): descriptions = MoveMetaCategoryDescriptionSerializer( many=True, read_only=True, source="movemetacategorydescription" ) moves = serializers.SerializerMethodField("get_category_moves") class Meta: model = MoveMetaCategory fields = ("id", "name", "descriptions", "moves") @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["sing"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/move/47/"], }, }, }, } ) def get_category_moves(self, obj): move_meta_objects = MoveMeta.objects.filter(move_meta_category=obj) moves = [] for meta in move_meta_objects: move_obj = Move.objects.get(pk=meta.move.id) data = MoveSummarySerializer(move_obj, context=self.context).data moves.append(data) return moves class MoveMetaSerializer(serializers.ModelSerializer): ailment = MoveMetaAilmentSummarySerializer(source="move_meta_ailment") category = MoveMetaCategorySummarySerializer(source="move_meta_category") class Meta: model = MoveMeta fields = ( "ailment", "category", "min_hits", "max_hits", "min_turns", "max_turns", "drain", "healing", "crit_rate", "ailment_chance", "flinch_chance", "stat_chance", ) ############################# # MOVE TARGET SERIALIZERS # ############################# class MoveTargetNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = MoveTargetName fields = ("name", "language") class MoveTargetDescriptionSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = MoveTargetDescription fields = ("description", "language") class MoveTargetDetailSerializer(serializers.ModelSerializer): names = MoveTargetNameSerializer(many=True, read_only=True, source="movetargetname") descriptions = MoveTargetDescriptionSerializer( many=True, read_only=True, source="movetargetdescription" ) moves = MoveSummarySerializer(many=True, read_only=True, source="move") class Meta: model = MoveTarget fields = ("id", "name", "descriptions", "moves", "names") ###################### # MOVE SERIALIZERS # ###################### class MoveNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = AbilityName fields = ("name", "language") class MoveChangeSerializer(serializers.ModelSerializer): version_group = VersionGroupSummarySerializer() type = TypeSummarySerializer() effect_entries = serializers.SerializerMethodField("get_effects") effect_chance = serializers.IntegerField(source="move_effect_chance") class Meta: model = MoveChange fields = ( "accuracy", "power", "pp", "effect_chance", "effect_entries", "type", "version_group", ) @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["effect", "short_effect", "language"], "properties": { "effect": { "type": "string", "examples": [ "Inflicts [regular damage]{mechanic:regular-damage}." ], }, "short_effect": { "type": "string", "examples": [ "Inflicts regular damage with no additional effect." ], }, "language": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["en"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/language/9/"], }, }, }, }, }, } ) def get_effects(self, obj): effect_texts = MoveEffectEffectText.objects.filter(move_effect=obj.move_effect) data = MoveEffectEffectTextSerializer( effect_texts, many=True, context=self.context ).data return data class MoveEffectEffectTextSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = MoveEffectEffectText fields = ("effect", "short_effect", "language") class MoveEffectChangeEffectTextSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = MoveEffectChangeEffectText fields = ("effect", "language") class MoveEffectChangeSerializer(serializers.ModelSerializer): version_group = VersionGroupSummarySerializer() effect_entries = MoveEffectChangeEffectTextSerializer( many=True, read_only=True, source="moveeffectchangeeffecttext" ) class Meta: model = MoveEffectChange fields = ("version_group", "effect_entries") class MoveFlavorTextSerializer(serializers.ModelSerializer): flavor_text = serializers.CharField() language = LanguageSummarySerializer() version_group = VersionGroupSummarySerializer() class Meta: model = MoveFlavorText fields = ("flavor_text", "language", "version_group") class MoveDetailSerializer(serializers.ModelSerializer): generation = GenerationSummarySerializer() type = TypeSummarySerializer() target = MoveTargetSummarySerializer(source="move_target") contest_type = ContestTypeSummarySerializer() contest_effect = ContestEffectSummarySerializer() damage_class = MoveDamageClassSummarySerializer(source="move_damage_class") meta = MoveMetaSerializer(read_only=True, source="movemeta") names = MoveNameSerializer(many=True, read_only=True, source="movename") effect_entries = serializers.SerializerMethodField("get_effect_text") effect_chance = serializers.IntegerField(source="move_effect_chance") contest_combos = serializers.SerializerMethodField("get_combos") stat_changes = serializers.SerializerMethodField("get_move_stat_change") super_contest_effect = SuperContestEffectSummarySerializer() past_values = MoveChangeSerializer(many=True, read_only=True, source="movechange") effect_changes = serializers.SerializerMethodField("get_effect_change_text") machines = serializers.SerializerMethodField("get_move_machines") flavor_text_entries = MoveFlavorTextSerializer( many=True, read_only=True, source="moveflavortext" ) learned_by_pokemon = serializers.SerializerMethodField() class Meta: model = Move fields = ( "id", "name", "accuracy", "effect_chance", "pp", "priority", "power", "contest_combos", "contest_type", "contest_effect", "damage_class", "effect_entries", "effect_changes", "generation", "meta", "names", "past_values", "stat_changes", "super_contest_effect", "target", "type", "machines", "flavor_text_entries", "learned_by_pokemon", ) @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["clefairy"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/pokemon/35/"], }, }, }, } ) def get_learned_by_pokemon(self, obj): pokemon_moves = PokemonMove.objects.filter(move_id=obj).order_by("pokemon_id") pokemon_list = [] pokemon_ids = pokemon_moves.values("pokemon_id").distinct() for id in pokemon_ids: pokemon_object = Pokemon.objects.get(pk=id["pokemon_id"]) pokemon_data = PokemonSummarySerializer( pokemon_object, context=self.context ).data pokemon_list.append(pokemon_data) return pokemon_list @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["machine", "version_group"], "properties": { "machine": { "type": "object", "required": ["url"], "properties": { "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/machine/1/"], } }, }, "version_group": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["sword-shield"]}, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/version-group/1/" ], }, }, }, }, }, } ) def get_move_machines(self, obj): machine_objects = Machine.objects.filter(move=obj) machines = [] for machine_object in machine_objects: machine_data = MachineSummarySerializer( machine_object, context=self.context ).data version_group_data = VersionGroupSummarySerializer( machine_object.version_group, context=self.context ).data machines.append( {"machine": machine_data, "version_group": version_group_data} ) return machines @extend_schema_field( field={ "type": "object", "required": ["normal", "super"], "properties": { "normal": { "type": "object", "required": ["use_before", "use_after"], "properties": { "use_before": { "type": "array", "nullable": True, "items": { "type": "object", "required": ["name", "url"], "properties": { "name": { "type": "string", "examples": ["fire-punch"], }, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/move/7/" ], }, }, }, }, "use_after": { "type": "array", "nullable": True, "items": { "type": "object", "required": ["name", "url"], "properties": { "name": { "type": "string", "examples": ["ice-punch"], }, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/move/8/" ], }, }, }, }, }, }, "super": { "type": "object", "required": ["use_before", "use_after"], "properties": { "use_before": { "type": "array", "nullable": True, "items": { "type": "object", "required": ["name", "url"], "properties": { "name": { "type": "string", "examples": ["night-slash"], }, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/move/400/" ], }, }, }, }, "use_after": { "type": "array", "nullable": True, "items": { "type": "object", "required": ["name", "url"], "properties": { "name": { "type": "string", "examples": ["focus-energy"], }, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/move/116/" ], }, }, }, }, }, }, }, } ) def get_combos(self, obj): normal_before_objects = ContestCombo.objects.filter(first_move=obj) normal_before_data = ContestComboSerializer( normal_before_objects, many=True, context=self.context ).data normal_after_objects = ContestCombo.objects.filter(second_move=obj) normal_after_data = ContestComboSerializer( normal_after_objects, many=True, context=self.context ).data super_before_objects = SuperContestCombo.objects.filter(first_move=obj) super_before_data = SuperContestComboSerializer( super_before_objects, many=True, context=self.context ).data super_after_objects = SuperContestCombo.objects.filter(second_move=obj) super_after_data = SuperContestComboSerializer( super_after_objects, many=True, context=self.context ).data details = None if ( normal_before_data or normal_after_data or super_before_data or super_after_data ): details = OrderedDict() details["normal"] = OrderedDict() details["normal"]["use_before"] = None details["normal"]["use_after"] = None details["super"] = OrderedDict() details["super"]["use_before"] = None details["super"]["use_after"] = None for combo in normal_before_data: if details["normal"]["use_before"] is None: details["normal"]["use_before"] = [] details["normal"]["use_before"].append(combo["second_move"]) for combo in normal_after_data: if details["normal"]["use_after"] is None: details["normal"]["use_after"] = [] details["normal"]["use_after"].append(combo["first_move"]) for combo in super_before_data: if details["super"]["use_before"] is None: details["super"]["use_before"] = [] details["super"]["use_before"].append(combo["second_move"]) for combo in super_after_data: if details["super"]["use_after"] is None: details["super"]["use_after"] = [] details["super"]["use_after"].append(combo["first_move"]) return details @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["effect", "short_effect", "language"], "properties": { "effect": { "type": "string", "examples": [ "Inflicts [regular damage]{mechanic:regular-damage}." ], }, "short_effect": { "type": "string", "examples": [ "Inflicts regular damage with no additional effect." ], }, "language": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["en"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/language/9/"], }, }, }, }, }, } ) def get_effect_text(self, obj): effect_texts = MoveEffectEffectText.objects.filter(move_effect=obj.move_effect) data = MoveEffectEffectTextSerializer( effect_texts, many=True, context=self.context ).data if len(data) > 0: for key, value in data[0].items(): if "$effect_chance%" in value: data[0][key] = value.replace( "$effect_chance", f"{obj.move_effect_chance}" ) return data @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["effect_entries", "version_group"], "properties": { "effect_entries": { "type": "array", "items": { "type": "object", "required": ["effect", "language"], "properties": { "effect": { "type": "string", "examples": [ "Hits Pokémon under the effects of dig and fly." ], }, "language": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["en"]}, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/language/9/" ], }, }, }, }, }, }, "version_group": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["gold-silver"]}, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/version-group/3/" ], }, }, }, }, }, } ) def get_effect_change_text(self, obj): effect_changes = MoveEffectChange.objects.filter(move_effect=obj.move_effect) data = MoveEffectChangeSerializer( effect_changes, many=True, context=self.context ).data return data @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["change", "stat"], "properties": { "change": {"type": "integer", "format": "int32", "examples": [2]}, "stat": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["attack"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/stat/1/"], }, }, }, }, }, } ) def get_move_stat_change(self, obj): stat_change_objects = MoveMetaStatChange.objects.filter(move=obj) stat_changes = MoveMetaStatChangeSerializer( stat_change_objects, many=True, context=self.context ).data for change in stat_changes: del change["move"] return stat_changes ########################## # PAL PARK SERIALIZERS # ########################## class PalParkSerializer(serializers.ModelSerializer): area = PalParkAreaSummarySerializer(read_only=True, source="pal_park_area") pokemon_species = PokemonSpeciesSummarySerializer() class Meta: model = PalPark fields = ("base_score", "rate", "area", "pokemon_species") class PalParkAreaNameSerializer(serializers.HyperlinkedModelSerializer): language = LanguageSummarySerializer() class Meta: model = PalParkAreaName fields = ("name", "language") class PalParkAreaDetailSerializer(serializers.ModelSerializer): names = PalParkAreaNameSerializer( many=True, read_only=True, source="palparkareaname" ) pokemon_encounters = serializers.SerializerMethodField("get_encounters") class Meta: model = PalParkArea fields = ("id", "name", "names", "pokemon_encounters") @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["base_score", "pokemon-species", "rate"], "properties": { "base_score": { "type": "integer", "format": "int32", "examples": [50], }, "pokemon-species": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["bulbasaur"]}, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/pokemon-species/1/" ], }, }, }, "rate": {"type": "integer", "format": "int32", "examples": [30]}, }, }, } ) def get_encounters(self, obj): pal_park_objects = PalPark.objects.filter(pal_park_area=obj) parks = PalParkSerializer( pal_park_objects, many=True, context=self.context ).data encounters = [] for encounter in parks: del encounter["area"] encounters.append(encounter) return encounters ############################### # POKEMON COLOR SERIALIZERS # ############################### class PokemonColorNameSerializer(serializers.HyperlinkedModelSerializer): language = LanguageSummarySerializer() class Meta: model = PokemonColorName fields = ("name", "language") class PokemonColorDetailSerializer(serializers.ModelSerializer): names = PokemonColorNameSerializer( many=True, read_only=True, source="pokemoncolorname" ) pokemon_species = PokemonSpeciesSummarySerializer( many=True, read_only=True, source="pokemonspecies" ) class Meta: model = PokemonColor fields = ("id", "name", "names", "pokemon_species") ############################## # POKEMON FORM SERIALIZERS # ############################## class PokemonFormSpritesSerializer(serializers.ModelSerializer): class Meta: model = PokemonFormSprites fields = ("sprites",) class PokemonFormNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = PokemonFormName fields = ("name", "pokemon_name", "language") class PokemonFormDetailSerializer(serializers.ModelSerializer): pokemon = PokemonSummarySerializer() version_group = VersionGroupSummarySerializer() sprites = serializers.SerializerMethodField("get_pokemon_form_sprites") form_names = serializers.SerializerMethodField("get_pokemon_form_names") names = serializers.SerializerMethodField("get_pokemon_form_pokemon_names") types = serializers.SerializerMethodField("get_pokemon_form_types") class Meta: model = PokemonForm fields = ( "id", "name", "order", "form_order", "is_default", "is_battle_only", "is_mega", "form_name", "pokemon", "sprites", "version_group", "form_names", "names", "types", ) @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["language", "name"], "properties": { "language": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["en"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/language/9/"], }, }, }, "name": {"type": "string", "examples": ["Plant Cloak"]}, }, }, } ) def get_pokemon_form_names(self, obj): form_results = PokemonFormName.objects.filter( pokemon_form=obj, name__regex=".+" ) form_serializer = PokemonFormNameSerializer( form_results, many=True, context=self.context ) data = form_serializer.data for name in data: del name["pokemon_name"] return data @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["language", "name"], "properties": { "language": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["en"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/language/9/"], }, }, }, "name": {"type": "string", "examples": ["Plant Cloak"]}, }, }, } ) def get_pokemon_form_pokemon_names(self, obj): form_results = PokemonFormName.objects.filter( pokemon_form=obj, pokemon_name__regex=".+" ) form_serializer = PokemonFormNameSerializer( form_results, many=True, context=self.context ) data = form_serializer.data for name in data: name["name"] = name["pokemon_name"] del name["pokemon_name"] return data @extend_schema_field( field={ "type": "object", "properties": { "default": { "type": "string", "format": "uri", "examples": [ "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/412.png" ], } }, "additionalProperties": { # Stoplight Elements doesn't render this well "type": "string", "format": "uri", "nullable": True, "examples": [ "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/shiny/412.png" ], }, "examples": [ { "back_default": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/412.png", "back_female": None, "back_shiny": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/shiny/412.png", "back_shiny_female": None, "front_default": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/412.png", "front_female": None, "front_shiny": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/shiny/412.png", "front_shiny_female": None, } ], } ) def get_pokemon_form_sprites(self, obj): sprites_object = PokemonFormSprites.objects.get(pokemon_form_id=obj) return sprites_object.sprites @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["slot", "type"], "properties": { "slot": {"type": "integer", "format": "int32", "examples": [1]}, "type": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["bug"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/type/7/"], }, }, }, }, }, } ) def get_pokemon_form_types(self, obj): form_type_objects = PokemonFormType.objects.filter(pokemon_form=obj) form_types = PokemonFormTypeSerializer( form_type_objects, many=True, context=self.context ).data for form_type in form_types: del form_type["pokemon_form"] # defer to parent Pokemon's types if no form-specific types if form_types == []: pokemon_object = Pokemon.objects.get(id=obj.pokemon_id) pokemon_type_objects = PokemonType.objects.filter(pokemon=pokemon_object) form_types = PokemonTypeSerializer( pokemon_type_objects, many=True, context=self.context ).data for form_type in form_types: del form_type["pokemon"] return form_types ################################# # POKEMON HABITAT SERIALIZERS # ################################# class PokemonHabitatNameSerializer(serializers.HyperlinkedModelSerializer): language = LanguageSummarySerializer() class Meta: model = PokemonHabitatName fields = ("name", "language") class PokemonHabitatDetailSerializer(serializers.ModelSerializer): names = PokemonHabitatNameSerializer( many=True, read_only=True, source="pokemonhabitatname" ) pokemon_species = PokemonSpeciesSummarySerializer( many=True, read_only=True, source="pokemonspecies" ) class Meta: model = PokemonHabitat fields = ("id", "name", "names", "pokemon_species") ############################## # POKEMON MOVE SERIALIZERS # ############################## class MoveLearnMethodNameSerializer(serializers.HyperlinkedModelSerializer): language = LanguageSummarySerializer() class Meta: model = MoveLearnMethodName fields = ("name", "language") class MoveLearnMethodDescriptionSerializer(serializers.HyperlinkedModelSerializer): language = LanguageSummarySerializer() class Meta: model = MoveLearnMethodDescription fields = ("description", "language") class MoveLearnMethodDetailSerializer(serializers.ModelSerializer): names = MoveLearnMethodNameSerializer( many=True, read_only=True, source="movelearnmethodname" ) descriptions = MoveLearnMethodDescriptionSerializer( many=True, read_only=True, source="movelearnmethoddescription" ) version_groups = serializers.SerializerMethodField("get_method_version_groups") class Meta: model = MoveLearnMethod fields = ("id", "name", "names", "descriptions", "version_groups") # "version_groups": [ # { # "name": "red-blue", # "url": "https://pokeapi.co/api/v2/version-group/1/" # }, @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["red-blue"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/version-group/1/"], }, }, }, } ) def get_method_version_groups(self, obj): version_group_objects = VersionGroupMoveLearnMethod.objects.filter( move_learn_method=obj ) version_group_data = VersionGroupMoveLearnMethodSerializer( version_group_objects, many=True, context=self.context ).data groups = [] for vg in version_group_data: groups.append(vg["version_group"]) return groups # https://stackoverflow.com/a/45987450/3482533 class PokemonMoveSerializer(serializers.ModelSerializer): class Meta: model = PokemonMove fields = "__all__" ############################### # POKEMON SHAPE SERIALIZERS # ############################### class PokemonShapeNameSerializer(serializers.HyperlinkedModelSerializer): language = LanguageSummarySerializer() class Meta: model = PokemonShapeName fields = ("name", "awesome_name", "language") class PokemonShapeDetailSerializer(serializers.ModelSerializer): names = serializers.SerializerMethodField("get_shape_names") awesome_names = serializers.SerializerMethodField("get_shape_awesome_names") pokemon_species = PokemonSpeciesSummarySerializer( many=True, read_only=True, source="pokemonspecies" ) class Meta: model = PokemonShape fields = ("id", "name", "awesome_names", "names", "pokemon_species") @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["url", "name"], "properties": { "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/language/9/"], }, "name": {"type": "string", "examples": ["Ball"]}, }, }, } ) def get_shape_names(self, obj): results = PokemonShapeName.objects.filter(pokemon_shape_id=obj) serializer = PokemonShapeNameSerializer( results, many=True, context=self.context ) data = serializer.data for entry in data: del entry["awesome_name"] return data # "awesome_names": [ # { # "awesome_name": "Pomacé", # "language": { # "name": "fr", # "url": "https://pokeapi.co/api/v2/language/5/" # } # }, # { # "awesome_name": "Pomaceous", # "language": { # "name": "en", # "url": "https://pokeapi.co/api/v2/language/9/" # } # } # ], @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["awesome_name", "language"], "properties": { "awesome_name": {"type": "string", "examples": ["Pomaceous"]}, "language": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["en"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/language/9/"], }, }, }, }, }, } ) def get_shape_awesome_names(self, obj): results = PokemonShapeName.objects.filter(pokemon_shape_id=obj) serializer = PokemonShapeNameSerializer( results, many=True, context=self.context ) data = serializer.data for entry in data: del entry["name"] return data ############################## # POKEMON ITEM SERIALIZERS # ############################## class PokemonItemSerializer(serializers.ModelSerializer): version = VersionSummarySerializer() item = ItemSummarySerializer() class Meta: model = PokemonItem fields = ("rarity", "item", "version") ############################## # POKEMON STAT SERIALIZERS # ############################## class PokemonStatSerializer(serializers.ModelSerializer): stat = StatSummarySerializer() class Meta: model = PokemonStat fields = ("base_stat", "effort", "stat") ######################### # POKEMON SERIALIZERS # ######################### class PokemonGameIndexSerializer(serializers.ModelSerializer): version = VersionSummarySerializer() class Meta: model = PokemonGameIndex fields = ("game_index", "version") class PokemonDetailSerializer(serializers.ModelSerializer): abilities = serializers.SerializerMethodField("get_pokemon_abilities") past_abilities = serializers.SerializerMethodField("get_past_pokemon_abilities") game_indices = PokemonGameIndexSerializer( many=True, read_only=True, source="pokemongameindex" ) moves = serializers.SerializerMethodField("get_pokemon_moves") species = PokemonSpeciesSummarySerializer(source="pokemon_species") stats = PokemonStatSerializer(many=True, read_only=True, source="pokemonstat") types = serializers.SerializerMethodField("get_pokemon_types") past_types = serializers.SerializerMethodField("get_past_pokemon_types") forms = PokemonFormSummarySerializer( many=True, read_only=True, source="pokemonform" ) held_items = serializers.SerializerMethodField("get_pokemon_held_items") location_area_encounters = serializers.SerializerMethodField("get_encounters") sprites = serializers.SerializerMethodField("get_pokemon_sprites") cries = serializers.SerializerMethodField("get_pokemon_cries") class Meta: model = Pokemon fields = ( "id", "name", "base_experience", "height", "is_default", "order", "weight", "abilities", "past_abilities", "forms", "game_indices", "held_items", "location_area_encounters", "moves", "species", "sprites", "cries", "stats", "types", "past_types", ) @extend_schema_field( field={ "type": "object", "properties": { "front_default": { "type": "string", "format": "uri", "exmaple": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/1.png", } }, "additionalProperties": { # Stoplight Elements doesn't render this well "type": "string", "format": "uri", "nullable": True, "examples": [ "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/shiny/1.png" ], }, "examples": [ { "back_default": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/1.png", "back_female": None, "back_shiny": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/shiny/1.png", "back_shiny_female": None, "front_default": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png", "front_female": None, "front_shiny": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/shiny/1.png", "front_shiny_female": None, } ], } ) def get_pokemon_sprites(self, obj): sprites_object = PokemonSprites.objects.get(pokemon_id=obj) return sprites_object.sprites @extend_schema_field( field={ "type": "object", "required": ["latest", "legacy"], "properties": { "latest": { "type": "string", "format": "uri", "examples": [ "https://raw.githubusercontent.com/PokeAPI/cries/main/cries/pokemon/latest/50.ogg" ], }, "legacy": { "type": "string", "format": "uri", "examples": [ "https://raw.githubusercontent.com/PokeAPI/cries/main/cries/pokemon/legacy/50.ogg" ], }, }, } ) def get_pokemon_cries(self, obj): cries_object = PokemonCries.objects.get(pokemon_id=obj) return cries_object.cries # { # "move": { # "name": "scratch", # "url": "https://pokeapi.co/api/v2/move/10/" # }, # "version_group_details": [ # { # "level_learned_at": 1, # "move_learn_method": { # "name": "level-up", # "url": "https://pokeapi.co/api/v2/move-learn-method/1/" # }, # "version_group": { # "name": "red-blue", # "url": "https://pokeapi.co/api/v2/version-group/1/" # } # }, # { # "level_learned_at": 1, # "move_learn_method": { # "name": "level-up", # "url": "https://pokeapi.co/api/v2/move-learn-method/1/" # }, # "version_group": { # "name": "yellow", # "url": "https://pokeapi.co/api/v2/version-group/2/" # } # }, # { # "level_learned_at": 1, # "move_learn_method": { # "name": "level-up", # "url": "https://pokeapi.co/api/v2/move-learn-method/1/" # }, # "version_group": { # "name": "gold-silver", # "url": "https://pokeapi.co/api/v2/version-group/3/" # } # }, # { # "level_learned_at": 1, # "move_learn_method": { # "name": "level-up", # "url": "https://pokeapi.co/api/v2/move-learn-method/1/" # }, # "version_group": { # "name": "crystal", # "url": "https://pokeapi.co/api/v2/version-group/4/" # } # }, # { # "level_learned_at": 1, # "move_learn_method": { # "name": "level-up", # "url": "https://pokeapi.co/api/v2/move-learn-method/1/" # }, # "version_group": { # "name": "ruby-sapphire", # "url": "https://pokeapi.co/api/v2/version-group/5/" # } # }, # { # "level_learned_at": 1, # "move_learn_method": { # "name": "level-up", # "url": "https://pokeapi.co/api/v2/move-learn-method/1/" # }, # "version_group": { # "name": "emerald", # "url": "https://pokeapi.co/api/v2/version-group/6/" # } # }, # { # "level_learned_at": 1, # "move_learn_method": { # "name": "level-up", # "url": "https://pokeapi.co/api/v2/move-learn-method/1/" # }, # "version_group": { # "name": "firered-leafgreen", # "url": "https://pokeapi.co/api/v2/version-group/7/" # } # }, # { # "level_learned_at": 1, # "move_learn_method": { # "name": "level-up", # "url": "https://pokeapi.co/api/v2/move-learn-method/1/" # }, # "version_group": { # "name": "diamond-pearl", # "url": "https://pokeapi.co/api/v2/version-group/8/" # } # }, # { # "level_learned_at": 1, # "move_learn_method": { # "name": "level-up", # "url": "https://pokeapi.co/api/v2/move-learn-method/1/" # }, # "version_group": { # "name": "platinum", # "url": "https://pokeapi.co/api/v2/version-group/9/" # } # }, # { # "level_learned_at": 1, # "move_learn_method": { # "name": "level-up", # "url": "https://pokeapi.co/api/v2/move-learn-method/1/" # }, # "version_group": { # "name": "heartgold-soulsilver", # "url": "https://pokeapi.co/api/v2/version-group/10/" # } # }, # { # "level_learned_at": 1, # "move_learn_method": { # "name": "level-up", # "url": "https://pokeapi.co/api/v2/move-learn-method/1/" # }, # "version_group": { # "name": "black-white", # "url": "https://pokeapi.co/api/v2/version-group/11/" # } # }, # { # "level_learned_at": 1, # "move_learn_method": { # "name": "level-up", # "url": "https://pokeapi.co/api/v2/move-learn-method/1/" # }, # "version_group": { # "name": "colosseum", # "url": "https://pokeapi.co/api/v2/version-group/12/" # } # }, # { # "level_learned_at": 1, # "move_learn_method": { # "name": "level-up", # "url": "https://pokeapi.co/api/v2/move-learn-method/1/" # }, # "version_group": { # "name": "xd", # "url": "https://pokeapi.co/api/v2/version-group/13/" # } # }, # { # "level_learned_at": 1, # "move_learn_method": { # "name": "level-up", # "url": "https://pokeapi.co/api/v2/move-learn-method/1/" # }, # "version_group": { # "name": "black-2-white-2", # "url": "https://pokeapi.co/api/v2/version-group/14/" # } # }, # { # "level_learned_at": 1, # "move_learn_method": { # "name": "level-up", # "url": "https://pokeapi.co/api/v2/move-learn-method/1/" # }, # "version_group": { # "name": "x-y", # "url": "https://pokeapi.co/api/v2/version-group/15/" # } # }, # { # "level_learned_at": 1, # "move_learn_method": { # "name": "level-up", # "url": "https://pokeapi.co/api/v2/move-learn-method/1/" # }, # "version_group": { # "name": "omega-ruby-alpha-sapphire", # "url": "https://pokeapi.co/api/v2/version-group/16/" # } # }, # { # "level_learned_at": 1, # "move_learn_method": { # "name": "level-up", # "url": "https://pokeapi.co/api/v2/move-learn-method/1/" # }, # "version_group": { # "name": "sun-moon", # "url": "https://pokeapi.co/api/v2/version-group/17/" # } # }, # { # "level_learned_at": 1, # "move_learn_method": { # "name": "level-up", # "url": "https://pokeapi.co/api/v2/move-learn-method/1/" # }, # "version_group": { # "name": "ultra-sun-ultra-moon", # "url": "https://pokeapi.co/api/v2/version-group/18/" # } # }, # { # "level_learned_at": 1, # "move_learn_method": { # "name": "level-up", # "url": "https://pokeapi.co/api/v2/move-learn-method/1/" # }, # "version_group": { # "name": "lets-go-pikachu-lets-go-eevee", # "url": "https://pokeapi.co/api/v2/version-group/19/" # } # }, # { # "level_learned_at": 1, # "move_learn_method": { # "name": "level-up", # "url": "https://pokeapi.co/api/v2/move-learn-method/1/" # }, # "version_group": { # "name": "sword-shield", # "url": "https://pokeapi.co/api/v2/version-group/20/" # } # }, # { # "level_learned_at": 1, # "move_learn_method": { # "name": "level-up", # "url": "https://pokeapi.co/api/v2/move-learn-method/1/" # }, # "version_group": { # "name": "brilliant-diamond-and-shining-pearl", # "url": "https://pokeapi.co/api/v2/version-group/23/" # } # }, # { # "level_learned_at": 1, # "move_learn_method": { # "name": "level-up", # "url": "https://pokeapi.co/api/v2/move-learn-method/1/" # }, # "version_group": { # "name": "scarlet-violet", # "url": "https://pokeapi.co/api/v2/version-group/25/" # } # } # ] # }, # "move": { # "name": "scratch", # "url": "https://pokeapi.co/api/v2/move/10/" # }, # "version_group_details": [ # { # "level_learned_at": 1, # "move_learn_method": { # "name": "level-up", # "url": "https://pokeapi.co/api/v2/move-learn-method/1/" # }, # "version_group": { # "name": "red-blue", # "url": "https://pokeapi.co/api/v2/version-group/1/" # } # }, @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["move", "version_group_details"], "properties": { "move": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["scratch"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/move/10/"], }, }, }, "version_group_details": { "type": "array", "items": { "type": "object", "required": [ "level_learned_at", "move_learn_method", "version_group", ], "properties": { "level_learned_at": { "type": "integer", "format": "int32", "examples": [1], }, "move_learn_method": { "type": "object", "required": ["name", "url"], "properties": { "name": { "type": "string", "examples": ["level-up"], }, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/move-learn-method/1/" ], }, }, }, "version_group": { "type": "object", "required": ["name", "url"], "properties": { "name": { "type": "string", "examples": ["red-blue"], }, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/version-group/1/" ], }, }, }, }, }, }, }, }, } ) def get_pokemon_moves(self, obj): version_objects = VersionGroup.objects.all() version_data = VersionGroupSummarySerializer( version_objects, many=True, context=self.context ).data method_objects = MoveLearnMethod.objects.all() method_data = MoveLearnMethodSummarySerializer( method_objects, many=True, context=self.context ).data # Get moves related to this pokemon and pull out unique Move IDs. # Note that it's important to order by the same column we're using to # determine if the entries are unique. Otherwise distinct() will # return apparent duplicates. pokemon_moves = PokemonMove.objects.filter(pokemon_id=obj).order_by("move_id") move_ids = pokemon_moves.values("move_id").distinct() move_list = [] for id in move_ids: pokemon_move_details = OrderedDict() # Get each Unique Move by ID move_object = Move.objects.get(pk=id["move_id"]) move_data = MoveSummarySerializer(move_object, context=self.context).data pokemon_move_details["move"] = move_data # Get Versions and Move Methods associated with each unique move pokemon_move_objects = pokemon_moves.filter(move_id=id["move_id"]) serializer = PokemonMoveSerializer( pokemon_move_objects, many=True, context=self.context ) pokemon_move_details["version_group_details"] = [] for move in serializer.data: version_detail = OrderedDict() version_detail["level_learned_at"] = move["level"] version_detail["version_group"] = version_data[ move["version_group"] - 1 ] version_detail["move_learn_method"] = method_data[ move["move_learn_method"] - 1 ] pokemon_move_details["version_group_details"].append(version_detail) move_list.append(pokemon_move_details) return move_list # { # "item": { # "name": "soft-sand", # "url": "https://pokeapi.co/api/v2/item/214/" # }, # "version_details": [ # { # "rarity": 5, # "version": { # "name": "diamond", # "url": "https://pokeapi.co/api/v2/version/12/" # } # }, @extend_schema_field( field={ "type": "object", "required": ["item", "version_details"], "properties": { "item": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["soft-sand"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/item/214/"], }, }, }, "version_details": { "type": "array", "items": { "type": "object", "required": ["rarity", "version"], "properties": { "rarity": { "type": "integer", "format": "int32", "examples": [5], }, "version": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["diamond"]}, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/version/12/" ], }, }, }, }, }, }, }, } ) def get_pokemon_held_items(self, obj): # Get items related to this pokemon and pull out unique Item IDs pokemon_items = PokemonItem.objects.filter(pokemon_id=obj).order_by("item_id") item_ids = pokemon_items.values("item_id").distinct() item_list = [] for id in item_ids: pokemon_item_details = OrderedDict() # Get each Unique Item by ID item_object = Item.objects.get(pk=id["item_id"]) item_data = ItemSummarySerializer(item_object, context=self.context).data pokemon_item_details["item"] = item_data # Get Versions associated with each unique item pokemon_item_objects = pokemon_items.filter(item_id=id["item_id"]) serializer = PokemonItemSerializer( pokemon_item_objects, many=True, context=self.context ) pokemon_item_details["version_details"] = [] for item in serializer.data: version_detail = OrderedDict() version_detail["rarity"] = item["rarity"] version_detail["version"] = item["version"] pokemon_item_details["version_details"].append(version_detail) item_list.append(pokemon_item_details) return item_list # { # "ability": { # "name": "sand-veil", # "url": "https://pokeapi.co/api/v2/ability/8/" # }, # "is_hidden": false, # "slot": 1 # }, @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["ability", "is_hidden", "slot"], "properties": { "ability": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["sand-veil"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/ability/8/"], }, }, }, "is_hidden": {"type": "boolean"}, "slot": {"type": "integer", "format": "int32", "examples": [1]}, }, }, } ) def get_pokemon_abilities(self, obj): pokemon_ability_objects = PokemonAbility.objects.filter(pokemon=obj) data = PokemonAbilitySerializer( pokemon_ability_objects, many=True, context=self.context ).data abilities = [] for ability in data: del ability["pokemon"] abilities.append(ability) return abilities # { # "abilities": [ # { # "ability": { # "name": "levitate", # "url": "https://pokeapi.co/api/v2/ability/26/" # }, # "is_hidden": false, # "slot": 1 # } # ], # "generation": { # "name": "generation-vi", # "url": "https://pokeapi.co/api/v2/generation/6/" # } # } @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["abilities", "generation"], "properties": { "abilities": { "type": "array", "items": { "type": "object", "required": ["ability", "is_hidden", "slot"], "properties": { "ability": { "type": "object", "required": ["name", "url"], "properties": { "name": { "type": "string", "examples": ["levitate"], }, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/ability/26/" ], }, }, }, "is_hidden": {"type": "boolean"}, "slot": { "type": "integer", "format": "int32", "examples": [1], }, }, }, }, "generation": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["generation-vi"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/generation/6/"], }, }, }, }, }, } ) def get_past_pokemon_abilities(self, obj): pokemon_past_ability_objects = PokemonAbilityPast.objects.filter(pokemon=obj) pokemon_past_abilities = PokemonAbilityPastSerializer( pokemon_past_ability_objects, many=True, context=self.context ).data # post-process to the form we want current_generation = "" past_obj = {} final_data = [] for pokemon_past_ability in pokemon_past_abilities: del pokemon_past_ability["pokemon"] generation = pokemon_past_ability["generation"]["name"] if generation != current_generation: current_generation = generation past_obj = {} # create past abilities object for this generation past_obj["generation"] = pokemon_past_ability["generation"] del pokemon_past_ability["generation"] # create abilities array past_obj["abilities"] = [pokemon_past_ability] # add to past abilities array final_data.append(past_obj) else: # add to existing array for this generation del pokemon_past_ability["generation"] past_obj["abilities"].append(pokemon_past_ability) return final_data # { # "slot": 1, # "type": { # "name": "ghost", # "url": "https://pokeapi.co/api/v2/type/8/" # } # }, @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["slot", "type"], "properties": { "slot": {"type": "integer", "format": "int32", "examples": [1]}, "type": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["ghost"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/type/8/"], }, }, }, }, }, } ) def get_pokemon_types(self, obj): poke_type_objects = PokemonType.objects.filter(pokemon=obj) poke_types = PokemonTypeSerializer( poke_type_objects, many=True, context=self.context ).data for poke_type in poke_types: del poke_type["pokemon"] return poke_types # "past_types": [ # { # "generation": { # "name": "generation-v", # "url": "https://pokeapi.co/api/v2/generation/5/" # }, # "types": [ # { # "slot": 1, # "type": { # "name": "normal", # "url": "https://pokeapi.co/api/v2/type/1/" # } # } # ] # } # ], @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["generation", "types"], "properties": { "generation": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["generation-v"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/generation/5/"], }, }, }, "types": { "type": "array", "items": { "type": "object", "required": ["slot", "type"], "properties": { "slot": { "type": "integer", "format": "int32", "examples": [1], }, "type": { "type": "object", "required": ["name", "url"], "properties": { "name": { "type": "string", "examples": ["normal"], }, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/type/1/" ], }, }, }, }, }, }, }, }, } ) def get_past_pokemon_types(self, obj): poke_past_type_objects = PokemonTypePast.objects.filter(pokemon=obj) poke_past_types = PokemonTypePastSerializer( poke_past_type_objects, many=True, context=self.context ).data # post-process to the form we want current_generation = "" past_obj = {} final_data = [] for poke_past_type in poke_past_types: del poke_past_type["pokemon"] generation = poke_past_type["generation"]["name"] if generation != current_generation: current_generation = generation past_obj = {} # create past types object for this generation past_obj["generation"] = poke_past_type["generation"] del poke_past_type["generation"] # create types array past_obj["types"] = [poke_past_type] # add to past types array final_data.append(past_obj) else: # add to existing array for this generation del poke_past_type["generation"] past_obj["types"].append(poke_past_type) return final_data @extend_schema_field( field={ "type": "string", "examples": ["https://pokeapi.co/api/v2/pokemon/1/encounters"], } ) def get_encounters(self, obj): return reverse("pokemon_encounters", kwargs={"pokemon_id": obj.pk}) ################################# # POKEMON SPECIES SERIALIZERS # ################################# class EvolutionTriggerNameSerializer(serializers.HyperlinkedModelSerializer): language = LanguageSummarySerializer() class Meta: model = EvolutionTriggerName fields = ("name", "language") class EvolutionTriggerDetailSerializer(serializers.HyperlinkedModelSerializer): names = EvolutionTriggerNameSerializer( many=True, read_only=True, source="evolutiontriggername" ) pokemon_species = serializers.SerializerMethodField("get_species") class Meta: model = EvolutionTrigger fields = ("id", "name", "names", "pokemon_species") @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["ivysaur"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/pokemon-species/2/"], }, }, }, } ) def get_species(self, obj): evo_objects = PokemonEvolution.objects.filter(evolution_trigger=obj) species_list = [] species_names = set() for evo in evo_objects: species = PokemonSpeciesSummarySerializer( evo.evolved_species, context=self.context ).data if species["name"] not in species_names: species_list.append(species) species_names.add(species["name"]) return species_list class PokemonSpeciesDescriptionSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = PokemonSpeciesDescription fields = ("description", "language") class PokemonSpeciesFlavorTextSerializer(serializers.ModelSerializer): flavor_text = serializers.CharField() language = LanguageSummarySerializer() version = VersionSummarySerializer() class Meta: model = PokemonSpeciesFlavorText fields = ("flavor_text", "language", "version") class PokemonSpeciesNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = PokemonSpeciesName fields = ("name", "genus", "language") class PokemonSpeciesEvolutionSerializer(serializers.ModelSerializer): """ This is here purely to help build pokemon evolution chains """ class Meta: model = PokemonSpecies fields = ("name", "id", "evolves_from_species", "is_baby") class PokemonSpeciesDetailSerializer(serializers.ModelSerializer): names = serializers.SerializerMethodField("get_pokemon_names") form_descriptions = PokemonSpeciesDescriptionSerializer( many=True, read_only=True, source="pokemonspeciesdescription" ) pokedex_numbers = PokemonDexEntrySerializer( many=True, read_only=True, source="pokemondexnumber" ) egg_groups = serializers.SerializerMethodField("get_pokemon_egg_groups") flavor_text_entries = PokemonSpeciesFlavorTextSerializer( many=True, read_only=True, source="pokemonspeciesflavortext" ) genera = serializers.SerializerMethodField("get_pokemon_genera") generation = GenerationSummarySerializer() growth_rate = GrowthRateSummarySerializer() color = PokemonColorSummarySerializer(source="pokemon_color") habitat = PokemonHabitatSummarySerializer(source="pokemon_habitat") shape = PokemonShapeSummarySerializer(source="pokemon_shape") evolves_from_species = PokemonSpeciesSummarySerializer() varieties = serializers.SerializerMethodField("get_pokemon_varieties") evolution_chain = EvolutionChainSummarySerializer() pal_park_encounters = serializers.SerializerMethodField("get_encounters") class Meta: model = PokemonSpecies fields = ( "id", "name", "order", "gender_rate", "capture_rate", "base_happiness", "is_baby", "is_legendary", "is_mythical", "hatch_counter", "has_gender_differences", "forms_switchable", "growth_rate", "pokedex_numbers", "egg_groups", "color", "shape", "evolves_from_species", "evolution_chain", "habitat", "generation", "names", "pal_park_encounters", "form_descriptions", "flavor_text_entries", "genera", "varieties", ) @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["language", "name"], "properties": { "language": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["en"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/language/9/"], }, }, }, "name": {"type": "string", "examples": ["bulbasaur"]}, }, }, } ) def get_pokemon_names(self, obj): species_results = PokemonSpeciesName.objects.filter(pokemon_species=obj) species_serializer = PokemonSpeciesNameSerializer( species_results, many=True, context=self.context ) data = species_serializer.data for name in data: del name["genus"] return data # { # "genus": "Seed Pokémon", # "language": { # "name": "en", # "url": "https://pokeapi.co/api/v2/language/9/" # } # }, @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["genus", "language"], "properties": { "genus": {"type": "string", "examples": ["Seed Pokémon"]}, "language": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["en"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/language/9/"], }, }, }, }, }, } ) def get_pokemon_genera(self, obj): results = PokemonSpeciesName.objects.filter(pokemon_species=obj) serializer = PokemonSpeciesNameSerializer( results, many=True, context=self.context ) data = serializer.data genera = [] for entry in data: if entry["genus"]: del entry["name"] genera.append(entry) return genera @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["monster"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/egg-group/1/"], }, }, }, } ) def get_pokemon_egg_groups(self, obj): results = PokemonEggGroup.objects.filter(pokemon_species=obj) data = PokemonEggGroupSerializer(results, many=True, context=self.context).data groups = [] for group in data: groups.append(group["egg_group"]) return groups @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["is_default", "pokemon"], "properties": { "is_default": {"type": "boolean"}, "pokemon": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["bulbasaur"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/pokemon/1/"], }, }, }, }, }, } ) def get_pokemon_varieties(self, obj): results = Pokemon.objects.filter(pokemon_species=obj) summary_data = PokemonSummarySerializer( results, many=True, context=self.context ).data detail_data = PokemonDetailSerializer( results, many=True, context=self.context ).data varieties = [] for index, pokemon in enumerate(detail_data): entry = OrderedDict() entry["is_default"] = pokemon["is_default"] entry["pokemon"] = summary_data[index] varieties.append(entry) return varieties @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["area", "base_score", "rate"], "properties": { "area": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["field"]}, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/pal-park-area/2/" ], }, }, }, "base_score": { "type": "integer", "format": "int32", "examples": [50], }, "rate": {"type": "integer", "format": "int32", "examples": [30]}, }, }, } ) def get_encounters(self, obj): pal_park_objects = PalPark.objects.filter(pokemon_species=obj) parks = PalParkSerializer( pal_park_objects, many=True, context=self.context ).data encounters = [] for encounter in parks: del encounter["pokemon_species"] encounters.append(encounter) return encounters class PokemonEvolutionSerializer(serializers.ModelSerializer): item = ItemSummarySerializer(source="evolution_item") held_item = ItemSummarySerializer() known_move = MoveSummarySerializer() known_move_type = TypeSummarySerializer() party_species = PokemonSpeciesSummarySerializer() party_type = TypeSummarySerializer() trade_species = PokemonSpeciesSummarySerializer() location = LocationSummarySerializer() trigger = EvolutionTriggerSummarySerializer(source="evolution_trigger") class Meta: model = PokemonEvolution fields = ( "item", "trigger", "gender", "held_item", "known_move", "known_move_type", "location", "min_level", "min_happiness", "min_beauty", "min_affection", "needs_overworld_rain", "party_species", "party_type", "relative_physical_stats", "time_of_day", "trade_species", "turn_upside_down", ) class EvolutionChainDetailSerializer(serializers.ModelSerializer): baby_trigger_item = ItemSummarySerializer() chain = serializers.SerializerMethodField("build_chain") class Meta: model = EvolutionChain fields = ("id", "baby_trigger_item", "chain") # TODO: Revisit Schema @extend_schema_field( field={ "type": "object", "required": ["evolution_details", "evolves_to", "is_baby", "species"], "properties": { "evolution_details": {"type": "array", "items": {}, "examples": []}, "evolves_to": { "type": "array", "items": { "type": "object", "required": [ "evolution_details", "evolves_to", "is_baby", "species", ], "properties": { "evolution_details": { "type": "array", "items": { "type": "object", "required": [ "gender", "held_item", "item", "known_move", "known_move_type", "location", "min_affection", "min_beauty", "min_happiness", "min_level", "needs_overworld_rain", "party_species", "party_type", "relative_physical_stats", "time_of_day", "trade_species", "trigger", "turn_upside_down", ], "properties": { "gender": { "type": "", "nullable": True, "type": "object", "required": ["name", "url"], "properties": { "name": { "type": "string", "examples": [1], }, "url": { "type": "string", "format": "uri", "examples": [2], }, }, }, "held_item": { "type": "object", "nullable": True, "required": ["name", "url"], "properties": { "name": { "type": "string", "examples": [1], }, "url": { "type": "string", "format": "uri", "examples": [2], }, }, }, "item": { "type": "object", "nullable": True, "required": ["name", "url"], "properties": { "name": { "type": "string", "examples": [1], }, "url": { "type": "string", "format": "uri", "examples": [2], }, }, }, "known_move": { "type": "", "nullable": True, }, "known_move_type": { "type": "", "nullable": True, }, "location": { "type": "object", "nullable": True, "required": ["name", "url"], "properties": { "name": { "type": "string", }, "url": { "type": "string", "format": "uri", }, }, }, "min_affection": { "type": "integer", "format": "int32", "nullable": True, }, "min_beauty": { "type": "integer", "format": "int32", "nullable": True, }, "min_happiness": { "type": "integer", "format": "int32", "nullable": True, }, "min_level": { "type": "integer", "format": "int32", "nullable": True, }, "needs_overworld_rain": { "type": "boolean", "nullable": True, }, "party_species": { "type": "string", "nullable": True, }, "party_type": { "type": "string", "nullable": True, }, "relative_physical_stats": { "type": "string", "nullable": True, }, "time_of_day": {"type": "string"}, "trade_species": { "type": "string", "nullable": True, }, "trigger": { "type": "object", "required": ["name", "url"], "properties": { "name": { "type": "string", }, "url": { "type": "string", "format": "uri", }, }, }, "turn_upside_down": {"type": "boolean"}, }, }, }, "is_baby": {"type": "boolean"}, "species": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["happiny"]}, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/pokemon-species/440/" ], }, }, }, }, }, }, "is_baby": {"type": "boolean"}, "species": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["happiny"]}, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/pokemon-species/440/" ], }, }, }, }, } ) def build_chain(self, obj): chain_id = obj.id pokemon_objects = PokemonSpecies.objects.filter( evolution_chain_id=chain_id ).order_by("order") summary_data = PokemonSpeciesSummarySerializer( pokemon_objects, many=True, context=self.context ).data ref_data = PokemonSpeciesEvolutionSerializer( pokemon_objects, many=True, context=self.context ).data # convert evolution data list to tree evolution_tree = self.build_evolution_tree(ref_data) # serialize chain recursively from tree chain = self.build_chain_link_entry(evolution_tree, summary_data) return chain # converts a list of Pokemon species evolution data into a tree representing the evolution chain def build_evolution_tree(self, species_evolution_data): evolution_tree = OrderedDict() evolution_tree["species"] = species_evolution_data[0] evolution_tree["children"] = [] for species in species_evolution_data[1:]: chain_link = OrderedDict() chain_link["species"] = species chain_link["children"] = [] evolves_from_species_id = chain_link["species"]["evolves_from_species"] # find parent link by DFS parent_link = evolution_tree search_stack = [parent_link] while len(search_stack) > 0: l = search_stack.pop() if l["species"]["id"] == evolves_from_species_id: parent_link = l break # "left" to "right" requires reversing the list of children search_stack += reversed(l["children"]) parent_link["children"].append(chain_link) return evolution_tree # serializes an evolution chain link recursively # chain_link is a tree representing an evolution chain def build_chain_link_entry(self, chain_link, summary_data): entry = OrderedDict() evolution_data = None species = chain_link["species"] if species["evolves_from_species"]: evolution_object = PokemonEvolution.objects.filter( evolved_species=species["id"] ) evolution_data = PokemonEvolutionSerializer( evolution_object, many=True, context=self.context ).data entry["is_baby"] = species["is_baby"] species_summary = next(x for x in summary_data if x["name"] == species["name"]) entry["species"] = species_summary entry["evolution_details"] = evolution_data or [] evolves_to = [ self.build_chain_link_entry(c, summary_data) for c in chain_link["children"] ] entry["evolves_to"] = evolves_to return entry class PokemonDexNumberSerializer(serializers.ModelSerializer): entry_number = serializers.IntegerField(source="pokedex_number") pokemon_species = PokemonSpeciesSummarySerializer() class Meta: model = PokemonDexNumber fields = ("pokedex", "entry_number", "pokemon_species") ############################ # POKEATHLON SERIALIZERS # ############################ class PokeathlonStatNameSerializer(serializers.HyperlinkedModelSerializer): language = LanguageSummarySerializer() class Meta: model = PokeathlonStatName fields = ("name", "language") class PokeathlonStatDetailSerializer(serializers.HyperlinkedModelSerializer): names = PokeathlonStatNameSerializer( many=True, read_only=True, source="pokeathlonstatname" ) affecting_natures = serializers.SerializerMethodField("get_natures_that_affect") class Meta: model = PokeathlonStat fields = ("id", "name", "affecting_natures", "names") @extend_schema_field( field={ "type": "object", "required": ["decrease", "increase"], "properties": { "decrease": { "type": "array", "items": { "type": "object", "required": ["max_change", "nature"], "properties": { "max_change": { "type": "integer", "format": "int32", "maximum": -1, "examples": [-1], }, "nature": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["hardy"]}, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/nature/1/" ], }, }, }, }, }, }, "increase": { "type": "array", "items": { "type": "object", "required": ["max_change", "nature"], "properties": { "max_change": { "type": "integer", "format": "int32", "minimum": 1, "examples": [2], }, "nature": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["hardy"]}, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/nature/1/" ], }, }, }, }, }, }, }, } ) def get_natures_that_affect(self, obj): stat_change_objects = NaturePokeathlonStat.objects.filter(pokeathlon_stat=obj) stat_changes = NaturePokeathlonStatSerializer( stat_change_objects, many=True, context=self.context ).data changes = OrderedDict([("increase", []), ("decrease", [])]) for change in stat_changes: del change["pokeathlon_stat"] if change["max_change"] > 0: changes["increase"].append(change) else: changes["decrease"].append(change) return changes ######################### # POKEDEX SERIALIZERS # ######################### class PokedexNameSerializer(serializers.HyperlinkedModelSerializer): language = LanguageSummarySerializer() class Meta: model = PokedexName fields = ("name", "language") class PokedexDescriptionSerializer(serializers.HyperlinkedModelSerializer): language = LanguageSummarySerializer() class Meta: model = PokedexDescription fields = ("description", "language") class PokedexDetailSerializer(serializers.ModelSerializer): region = RegionSummarySerializer() names = PokedexNameSerializer(many=True, read_only=True, source="pokedexname") descriptions = PokedexDescriptionSerializer( many=True, read_only=True, source="pokedexdescription" ) pokemon_entries = serializers.SerializerMethodField("get_pokedex_entries") version_groups = serializers.SerializerMethodField("get_pokedex_version_groups") class Meta: model = Pokedex fields = ( "id", "name", "is_main_series", "descriptions", "names", "pokemon_entries", "region", "version_groups", ) @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["entry_number", "pokemon_species"], "properties": { "entry_number": { "type": "integer", "format": "int32", "examples": [1], }, "pokemon_species": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["bulbasaur"]}, "url": { "type": "string", "format": "uri", "examples": [ "https://pokeapi.co/api/v2/pokemon-species/1/" ], }, }, }, }, }, } ) def get_pokedex_entries(self, obj): results = PokemonDexNumber.objects.filter(pokedex=obj).order_by( "pokedex_number" ) serializer = PokemonDexNumberSerializer( results, many=True, context=self.context ) data = serializer.data for entry in data: del entry["pokedex"] return data @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["the-teal-mask"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/version-group/26/"], }, }, }, } ) def get_pokedex_version_groups(self, obj): dex_group_objects = PokedexVersionGroup.objects.filter(pokedex=obj) dex_groups = PokedexVersionGroupSerializer( dex_group_objects, many=True, context=self.context ).data results = [] for dex_group in dex_groups: results.append(dex_group["version_group"]) return results ######################### # VERSION SERIALIZERS # ######################### class VersionNameSerializer(serializers.ModelSerializer): language = LanguageSummarySerializer() class Meta: model = VersionName fields = ("name", "language") class VersionDetailSerializer(serializers.ModelSerializer): """ Should have a link to Version Group info but the Circular dependency and compilation order fight eachother and I'm not sure how to add anything other than a hyperlink """ names = VersionNameSerializer(many=True, read_only=True, source="versionname") version_group = VersionGroupSummarySerializer() class Meta: model = Version fields = ("id", "name", "names", "version_group") class VersionGroupDetailSerializer(serializers.ModelSerializer): generation = GenerationSummarySerializer() versions = VersionSummarySerializer(many=True, read_only=True, source="version") regions = serializers.SerializerMethodField("get_version_group_regions") move_learn_methods = serializers.SerializerMethodField("get_learn_methods") pokedexes = serializers.SerializerMethodField("get_version_groups_pokedexes") class Meta: model = VersionGroup fields = ( "id", "name", "order", "generation", "move_learn_methods", "pokedexes", "regions", "versions", ) @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["kanto"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/region/1/"], }, }, }, } ) def get_version_group_regions(self, obj): vg_regions = VersionGroupRegion.objects.filter(version_group=obj) data = VersionGroupRegionSerializer( vg_regions, many=True, context=self.context ).data regions = [] for region in data: regions.append(region["region"]) return regions # "name": "level-up", # "url": "https://pokeapi.co/api/v2/move-learn-method/1/" @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["level-up"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/move-learn-method/1/"], }, }, }, } ) def get_learn_methods(self, obj): learn_method_objects = VersionGroupMoveLearnMethod.objects.filter( version_group=obj ) learn_method_data = VersionGroupMoveLearnMethodSerializer( learn_method_objects, many=True, context=self.context ).data methods = [] for method in learn_method_data: methods.append(method["move_learn_method"]) return methods @extend_schema_field( field={ "type": "array", "items": { "type": "object", "required": ["name", "url"], "properties": { "name": {"type": "string", "examples": ["kanto"]}, "url": { "type": "string", "format": "uri", "examples": ["https://pokeapi.co/api/v2/pokedex/2/"], }, }, }, } ) def get_version_groups_pokedexes(self, obj): dex_group_objects = PokedexVersionGroup.objects.filter(version_group=obj) dex_groups = PokedexVersionGroupSerializer( dex_group_objects, many=True, context=self.context ).data results = [] for dex_group in dex_groups: results.append(dex_group["pokedex"]) return results