def get_recent_matches(summoner_id, region): """ Retrieves game data for last 10 games played by a summoner, given a summoner ID and region. This potentially executes several queries: -first, we get match history. -game stats -IDs of participants -then we make a list of summoner IDs that we don't have in the DB -this gets broken up into MAX_IDS chunks and each chunk is a queried as a single call for basic summoner data Since match history returns the last 10 games, and each game can have 9 other players (assuming non-hexakill mode) - that's 90 potentially unknown summoner IDs + 1 for the summoner in question, giving us 91 summoner IDs that we need to query. 91 / 40 = 2.275 rounded up is 3 queries at most for summoner ID data. 3 + 1 (for the initial match history call) = 4 calls at most. """ #print 'get_recent_matches()', summoner_id, region recent = riot_api.get_recent_games(summoner_id, region) # First make a set of the associated summoner IDs (a set cannot have duplicate entries). unique_players = set() for g in recent['games']: if 'fellowPlayers' in g: for p in g['fellowPlayers']: unique_players.add(p['summonerId']) # Now we take note of any summoner IDs we already have cached (so we can remove them). to_remove = set() for p in unique_players: try: Summoner.objects.filter(region=region).get(summoner_id=p) to_remove.add(p) except ObjectDoesNotExist: pass # Remove the already cached summoner IDs from the working set. for p in to_remove: unique_players.remove(p) player_list = list(unique_players) # make a list of the set, so we can call chunks() on it # Don't forget, we have to check for the summoner ID whose history we're examining as well! try: Summoner.objects.filter(region=region).get(summoner_id=summoner_id) except ObjectDoesNotExist: # if it isn't cached, and it isn't in the list yet, add it if summoner_id not in player_list: player_list.append(summoner_id) query_list = list(chunks(player_list, MAX_IDS)) # query_list now holds a list of lists of at most MAX_ID elements # Now ask the API for info on summoners, at most MAX_ID at a time. #print 'Now asking for participants...' summoner_dto = [] for i in query_list: summoner_dto.append(riot_api.get_summoners(ids=i, region=region)) #print 'Done getting participants!' # TODO: This part is sometimes getting duplicate summoners! (fixed?) # Now put those summoner DTOs in the cache. for chunk in summoner_dto: for player in chunk: # for v in chunk[player]: # print v, len(v) #print u'ADDING summoner {}'.format(chunk[player]['name']) summoner = Summoner(summoner_id=chunk[player]['id'], name=chunk[player]['name'], std_name=chunk[player]['name'].replace(' ', '').lower(), profile_icon_id=chunk[player]['profileIconId'], revision_date=chunk[player]['revisionDate'], summoner_level=chunk[player]['summonerLevel'], region=region) # Sometimes requests will go out synchronously for the same summoner. # This means the cache is not hit and a double query for a single summoner occurs. # Duplicate summoners are prevented via the unique_together constraint on summoner_id and region, # which will throw IntegrityError and prevent the dupe from being made. try: #print summoner.name, len(summoner.name) summoner.save() except IntegrityError: pass # Requires summoners (as well as all related field values) to be cached before-hand (summoner caching done above). for match in recent['games']: # first fill in the simple stuff game = Game(summoner_id=Summoner.objects.filter(region=region).get(summoner_id=summoner_id), champion_id=Champion.objects.get(champion_id=match['championId']), create_date=match['createDate'], game_id=match['gameId'], game_mode=match['gameMode'], game_type=match['gameType'], invalid=match['invalid'], ip_earned=match['ipEarned'], level=match['level'], map_id=match['mapId'], spell_1=SummonerSpell.objects.get(spell_id=match['spell1']), spell_2=SummonerSpell.objects.get(spell_id=match['spell2']), sub_type=match['subType'], team_id=match['teamId'], region=region, champion_key=Champion.objects.get(champion_id=match['championId']).key) stats = RawStat() # Here we add stats that were returned (only stats that aren't None or 0 will be returned by API) for i in match['stats']: setattr(stats, inflection.underscore(i), match['stats'][i]) stats.save() # associate the RawStat object with this game game.stats = stats game_saved = False # Ensures no dupes of Game (or any related objects). try: game.save() game_saved = True except IntegrityError: pass # if game saved, we're good and just need to add the participating players if game_saved: # associate each Player object with this game if 'fellowPlayers' in match: for p in match['fellowPlayers']: player = Player(champion=Champion.objects.get(champion_id=p['championId']), summoner=Summoner.objects.filter(region=region).get(summoner_id=p['summonerId']), team_id=p['teamId'], participant_of=game) player.save() else: # if it didn't save, we can get rid of the stats object too. stats.delete()
def get_recent_matches(summoner_id, region): """ Retrieves game data for last 10 games played by a summoner, given a summoner ID and region. This potentially executes several queries: -first, we get match history. -game stats -IDs of participants -then we make a list of summoner IDs that we don't have in the DB -this gets broken up into MAX_IDS chunks and each chunk is a queried as a single call for basic summoner data Since match history returns the last 10 games, and each game can have 9 other players (assuming non-hexakill mode) - that's 90 potentially unknown summoner IDs + 1 for the summoner in question, giving us 91 summoner IDs that we need to query. 91 / 40 = 2.275 rounded up is 3 queries at most for summoner ID data. 3 + 1 (for the initial match history call) = 4 calls at most. """ #print 'get_recent_matches()', summoner_id, region recent = riot_api.get_recent_games(summoner_id, region) # First make a set of the associated summoner IDs (a set cannot have duplicate entries). unique_players = set() for g in recent['games']: if 'fellowPlayers' in g: for p in g['fellowPlayers']: unique_players.add(p['summonerId']) # Now we take note of any summoner IDs we already have cached (so we can remove them). to_remove = set() for p in unique_players: try: Summoner.objects.filter(region=region).get(summoner_id=p) to_remove.add(p) except ObjectDoesNotExist: pass # Remove the already cached summoner IDs from the working set. for p in to_remove: unique_players.remove(p) player_list = list( unique_players ) # make a list of the set, so we can call chunks() on it # Don't forget, we have to check for the summoner ID whose history we're examining as well! try: Summoner.objects.filter(region=region).get(summoner_id=summoner_id) except ObjectDoesNotExist: # if it isn't cached, and it isn't in the list yet, add it if summoner_id not in player_list: player_list.append(summoner_id) query_list = list( chunks(player_list, MAX_IDS) ) # query_list now holds a list of lists of at most MAX_ID elements # Now ask the API for info on summoners, at most MAX_ID at a time. #print 'Now asking for participants...' summoner_dto = [] for i in query_list: summoner_dto.append(riot_api.get_summoners(ids=i, region=region)) #print 'Done getting participants!' # TODO: This part is sometimes getting duplicate summoners! (fixed?) # Now put those summoner DTOs in the cache. for chunk in summoner_dto: for player in chunk: # for v in chunk[player]: # print v, len(v) #print u'ADDING summoner {}'.format(chunk[player]['name']) summoner = Summoner(summoner_id=chunk[player]['id'], name=chunk[player]['name'], std_name=chunk[player]['name'].replace( ' ', '').lower(), profile_icon_id=chunk[player]['profileIconId'], revision_date=chunk[player]['revisionDate'], summoner_level=chunk[player]['summonerLevel'], region=region) # Sometimes requests will go out synchronously for the same summoner. # This means the cache is not hit and a double query for a single summoner occurs. # Duplicate summoners are prevented via the unique_together constraint on summoner_id and region, # which will throw IntegrityError and prevent the dupe from being made. try: #print summoner.name, len(summoner.name) summoner.save() except IntegrityError: pass # Requires summoners (as well as all related field values) to be cached before-hand (summoner caching done above). for match in recent['games']: # first fill in the simple stuff game = Game( summoner_id=Summoner.objects.filter(region=region).get( summoner_id=summoner_id), champion_id=Champion.objects.get(champion_id=match['championId']), create_date=match['createDate'], game_id=match['gameId'], game_mode=match['gameMode'], game_type=match['gameType'], invalid=match['invalid'], ip_earned=match['ipEarned'], level=match['level'], map_id=match['mapId'], spell_1=SummonerSpell.objects.get(spell_id=match['spell1']), spell_2=SummonerSpell.objects.get(spell_id=match['spell2']), sub_type=match['subType'], team_id=match['teamId'], region=region, champion_key=Champion.objects.get( champion_id=match['championId']).key) stats = RawStat() # Here we add stats that were returned (only stats that aren't None or 0 will be returned by API) for i in match['stats']: setattr(stats, inflection.underscore(i), match['stats'][i]) stats.save() # associate the RawStat object with this game game.stats = stats game_saved = False # Ensures no dupes of Game (or any related objects). try: game.save() game_saved = True except IntegrityError: pass # if game saved, we're good and just need to add the participating players if game_saved: # associate each Player object with this game if 'fellowPlayers' in match: for p in match['fellowPlayers']: player = Player( champion=Champion.objects.get( champion_id=p['championId']), summoner=Summoner.objects.filter(region=region).get( summoner_id=p['summonerId']), team_id=p['teamId'], participant_of=game) player.save() else: # if it didn't save, we can get rid of the stats object too. stats.delete()