From 26ce073c298418511c502769c65a2db1cc9f95f5 Mon Sep 17 00:00:00 2001 From: santichausis Date: Fri, 17 Jul 2026 12:57:03 -0300 Subject: [PATCH] Fix location area encounters lookup assuming contiguous version ids Same issue as #1567 / PR #1603 (previously fixed in get_pokemon_moves): LocationAreaDetailSerializer.get_encounters looked up Version summaries by list position (id - 1), assuming ids form a contiguous 1-indexed sequence. Any gap in the Version table (e.g. a deleted row) causes the wrong version to be returned, or an IndexError. This is the same root cause reported in #1313 and previously attempted in PR #1314 (closed, unmerged). --- pokemon_v2/serializers.py | 16 +++++++++++----- pokemon_v2/tests.py | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/pokemon_v2/serializers.py b/pokemon_v2/serializers.py index 9c8f4d286..cf0ac95c6 100644 --- a/pokemon_v2/serializers.py +++ b/pokemon_v2/serializers.py @@ -1193,10 +1193,16 @@ def get_method_rates(self, obj): ) 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 + version_objects = Version.objects.all().order_by("id") + version_data = { + version_object.id: data + for version_object, data in zip( + version_objects, + 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") @@ -1219,7 +1225,7 @@ def get_encounters(self, obj): # 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["version"] = version_data[ver["version"]] version_detail["max_chance"] = 0 version_detail["encounter_details"] = [] diff --git a/pokemon_v2/tests.py b/pokemon_v2/tests.py index 2260e6df4..23c2ae95b 100644 --- a/pokemon_v2/tests.py +++ b/pokemon_v2/tests.py @@ -3298,6 +3298,42 @@ def test_location_area_api(self): ), ) + def test_location_area_encounters_with_non_contiguous_version_ids(self): + # Regression test: get_encounters used to look up Version + # summaries by list position (id - 1), assuming ids were a + # contiguous 1-indexed sequence. Deleting a row (or otherwise + # creating a gap) breaks that assumption and returns the wrong + # version, or raises an IndexError. + location_area = self.setup_location_area_data(name="lctn area for id gap test") + + # Create and delete a version so that the id actually used + # below is not contiguous starting from 1. + doomed_version = self.setup_version_data(name="doomed ver") + doomed_version.delete() + + version = self.setup_version_data(name="ver after gap") + pokemon = self.setup_pokemon_data(name="pkmn for id gap test") + encounter_slot = self.setup_encounter_slot_data(rarity=30) + encounter = self.setup_encounter_data( + location_area=location_area, + encounter_slot=encounter_slot, + pokemon=pokemon, + version=version, + ) + + response = self.client.get( + "{}/location-area/{}/".format(API_V2, location_area.pk) + ) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + + version_detail = response.data["pokemon_encounters"][0]["version_details"][0] + self.assertEqual(version_detail["version"]["name"], version.name) + self.assertEqual( + version_detail["version"]["url"], + "{}{}/version/{}/".format(TEST_HOST, API_V2, encounter.version.pk), + ) + # Contest Tests def test_contest_type_api(self): contest_type = self.setup_contest_type_data(name="base cntst tp")