diff --git a/leaderboard/contributors/models.py b/leaderboard/contributors/models.py index 57e1a04..f84ceff 100644 --- a/leaderboard/contributors/models.py +++ b/leaderboard/contributors/models.py @@ -1,3 +1,4 @@ +from collections import defaultdict import operator from bulk_update.helper import bulk_update @@ -67,28 +68,48 @@ def _compute_ranks(cls, contributions): (rank.contributor_id, rank.country_id): rank for rank in ContributorRank.objects.all() } - countries = Country.objects.all() + + contributor_prior_countries = defaultdict(set) + for contributor_id, country_id in contributor_ranks.keys(): + if country_id is not None: + contributor_prior_countries[contributor_id].add(country_id) + + countries = (Country.objects.order_by('-area') + .only('id', 'geometry').all()) + prepared_countries = dict([(country.id, country.geometry.prepared) + for country in countries]) for contribution in contributions: # Each contribution counts towards the rank in the country in which # it was made, as well as the global rank for that contributor. - contribution_country = None + contribution_country_id = None - # Attempt to find a country which contains the observation point - for country in countries: - if country.geometry.contains(contribution.point): - contribution_country = country + # Check if the contribution is in one of the countries the + # contributor has contributed to before. + for country_id in contributor_prior_countries.get( + contribution.contributor_id, ()): + + prepared = prepared_countries.get(country_id) + if prepared and prepared.contains(contribution.point): + contribution_country_id = country_id break + # Attempt to find a country which contains the observation point + if contribution_country_id is None: + for country_id, prepared in prepared_countries.items(): + if prepared.contains(contribution.point): + contribution_country_id = country_id + break + # If no point was found, find the nearest country - if contribution_country is None: - contribution_country = sorted([ + if contribution_country_id is None: + contribution_country_id = sorted([ (country.geometry.distance(contribution.point), country) for country in countries - ])[0][1] + ])[0][1].id - for country_id in (contribution_country.id, None): + for country_id in (contribution_country_id, None): rank_key = (contribution.contributor_id, country_id) contributor_rank = contributor_ranks.get(rank_key, None)