pokeapi/pokemon_v2/serializers.py
gabe e885e3fa62
feat: add new sprites field to type
via adding `TypeSprites` to db containing type name icons from all games
(excluding tera types, for now)
2024-07-28 22:28:09 -04:00

6141 lines
211 KiB
Python

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