Skip to content

Commit de4dc8d

Browse files
committed
reverted aggregation/annotation on Team objects for season record due to poor performance
1 parent 27598cc commit de4dc8d

File tree

4 files changed

+63
-90
lines changed

4 files changed

+63
-90
lines changed

src/picker/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = "3.0.0"
1+
__version__ = "3.0.1"
22
VERSION = tuple(int(i) for i in __version__.split("."))
33

44
default_app_config = "picker.apps.PickerConfig"

src/picker/models/sports.py

Lines changed: 60 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -93,21 +93,38 @@ def to_dict(self):
9393
},
9494
}
9595

96+
@cached_property
97+
def team_list(self):
98+
return list(
99+
Team.objects
100+
.filter(league=self)
101+
.select_related("league", "conference", "division")
102+
)
103+
96104
@cached_property
97105
def team_dict(self):
98106
names = {}
99-
for team in self.teams.all():
100-
names[team.abbr] = team
107+
aliases = {}
108+
for tm_id, name in Alias.objects.filter(team__league=self).values_list("team_id", "name"):
109+
aliases.setdefault(tm_id, []).append(name)
110+
111+
for team in self.team_list:
112+
names[team.abbr.lower()] = team
113+
names[team.abbr.upper()] = team
101114
names[team.id] = team
102115
if team.nickname:
103116
full_name = "{} {}".format(team.name, team.nickname)
104117
names[full_name] = team
105118

106-
for alias in Alias.objects.filter(team=team).values_list("name", flat=True):
107-
names[alias] = team
119+
if team.id in aliases:
120+
for name in aliases[team.id]:
121+
names[name] = team
108122

109123
return names
110124

125+
def team(self, key):
126+
return self.team_dict[key]
127+
111128
@property
112129
def latest_gameset(self):
113130
rel = timezone.now()
@@ -202,68 +219,7 @@ def __str__(self):
202219
def valid_team_abbr(value):
203220
if value.startswith("__"):
204221
raise ValidationError('Team abbr cannot start with "__"')
205-
206-
207-
class TeamManager(models.Manager):
208-
def _season_record_annotations(self, season=None):
209-
season = season or models.F("league__current_season")
210-
Status = Game.Status
211-
return {
212-
"season_home_wins": models.Count(
213-
"home_games__id",
214-
distinct=True,
215-
filter=models.Q(
216-
home_games__status=Status.HOME_WIN, home_games__gameset__season=season
217-
),
218-
),
219-
"season_home_losses": models.Count(
220-
"home_games",
221-
distinct=True,
222-
filter=models.Q(
223-
home_games__status=Status.AWAY_WIN, home_games__gameset__season=season
224-
),
225-
),
226-
"season_home_ties": models.Count(
227-
"home_games__id",
228-
distinct=True,
229-
filter=models.Q(home_games__status=Status.TIE, home_games__gameset__season=season),
230-
),
231-
"season_away_wins": models.Count(
232-
"away_games__id",
233-
distinct=True,
234-
filter=models.Q(
235-
away_games__status=Status.AWAY_WIN, away_games__gameset__season=season
236-
),
237-
),
238-
"season_away_losses": models.Count(
239-
"away_games__id",
240-
distinct=True,
241-
filter=models.Q(
242-
away_games__status=Status.HOME_WIN, away_games__gameset__season=season
243-
),
244-
),
245-
"season_away_ties": models.Count(
246-
"away_games__id",
247-
distinct=True,
248-
filter=models.Q(away_games__status=Status.TIE, away_games__gameset__season=season),
249-
),
250-
"season_wins": models.F("season_home_wins") + models.F("season_away_wins"),
251-
"season_losses": models.F("season_home_losses") + models.F("season_away_losses"),
252-
"season_ties": models.F("season_away_ties") + models.F("season_home_ties"),
253-
}
254-
255-
def get_queryset(self):
256-
return super().get_queryset().annotate(**self._season_record_annotations())
257-
258-
def season_record(self, season, team):
259-
data = (
260-
super()
261-
.get_queryset()
262-
.filter(id=team.id)
263-
.aggregate(**self._season_record_annotations(season))
264-
)
265-
return SimpleNamespace(team=team, season=season, **data)
266-
222+
267223

268224
class Team(models.Model):
269225
"""
@@ -290,8 +246,6 @@ class Team(models.Model):
290246
logo = models.ImageField(upload_to=LOGOS_DIR, blank=True, null=True)
291247
notes = models.TextField(blank=True, default="")
292248

293-
objects = TeamManager()
294-
295249
class Meta:
296250
ordering = ("name",)
297251
base_manager_name = "objects"
@@ -315,10 +269,20 @@ def to_dict(self):
315269
}
316270

317271
def season_record(self, season=None):
318-
o = self
319-
if season or not hasattr(self, "season_wins"):
320-
o = Team.objects.season_record(season, self)
321-
return (o.season_wins, o.season_losses, o.season_ties)
272+
season = season or self.league.current_season
273+
Q, Count, Status = models.Q, models.Count, Game.Status
274+
values = Game.objects.filter(gameset__season=season).aggregate(
275+
wins=Count(
276+
"pk",
277+
filter=Q(status=Status.AWAY_WIN, away=self) | Q(status=Status.HOME_WIN, home=self),
278+
),
279+
losses=Count(
280+
"pk",
281+
filter=Q(status=Status.AWAY_WIN, home=self) | Q(status=Status.HOME_WIN, away=self),
282+
),
283+
ties=Count("pk", filter=Q(status=Status.TIE, away=self) | Q(status=Status.TIE, home=self)),
284+
)
285+
return (values["wins"], values["losses"], values["ties"])
322286

323287
def season_points(self, season=None):
324288
w, l, t = self.season_record(season)
@@ -352,10 +316,29 @@ def byes(self, season=None):
352316
return self.bye_set.filter(season=season or self.league.current_season)
353317

354318
def complete_record(self):
319+
home_games = [0, 0, 0]
320+
away_games = [0, 0, 0]
321+
322+
for games, accum, status in (
323+
(self.away_games, away_games, Game.Status.AWAY_WIN),
324+
(self.home_games, home_games, Game.Status.HOME_WIN),
325+
):
326+
for res in games.exclude(status=Game.Status.UNPLAYED).values_list("status", flat=True):
327+
if res == status:
328+
accum[0] += 1
329+
elif res == Game.Status.TIE:
330+
accum[2] += 1
331+
else:
332+
accum[1] += 1
333+
355334
return [
356-
[self.season_home_wins, self.season_home_losses, self.season_home_ties],
357-
[self.season_away_wins, self.season_away_losses, self.season_away_ties],
358-
[self.season_wins, self.season_losses, self.season_ties],
335+
home_games,
336+
away_games,
337+
[
338+
away_games[0] + home_games[0],
339+
away_games[1] + home_games[1],
340+
away_games[2] + home_games[2],
341+
],
359342
]
360343

361344

@@ -441,11 +424,11 @@ def previous_gameset(self):
441424
def dates(self):
442425
return sorted(set(d.date() for d in self.games.values_list("start_time", flat=True)))
443426

444-
@property
427+
@cached_property
445428
def last_game(self):
446429
return self.games.last()
447430

448-
@property
431+
@cached_property
449432
def first_game(self):
450433
return self.games.first()
451434

src/picker/views/sports.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@ class Teams(SimplePickerViewBase):
1717
template_name = "@teams/listing.html"
1818

1919
def get_context_data(self, **kwargs):
20-
return super().get_context_data(
21-
teams=self.league.teams.select_related("conference", "division"), **kwargs
22-
)
20+
return super().get_context_data(teams=self.league.team_list, **kwargs)
2321

2422

2523
class Schedule(SimplePickerViewBase):

tests/test_models.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,6 @@ def test_random_points(self, league):
196196

197197
@pytest.mark.django_db
198198
class TestTeam:
199-
def test_season_stats_from_game(self, gameset):
200-
assert hasattr(gameset.games.all()[0].home, "season_wins")
201-
202199
def test_team_season_record(self, teams):
203200
t = teams[0]
204201
r = t.season_record(1975)
@@ -213,12 +210,7 @@ def test_team(self, league, gamesets):
213210
assert len(team.color_options) == 2
214211
assert team.byes().count() == 0
215212
assert team.complete_record() == [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
216-
217-
sr = Team.objects.season_record(league.current_season, team)
218-
assert sr.team == team
219-
for k in ["season_wins", "season_losses", "season_ties"]:
220-
assert hasattr(sr, k)
221-
assert isinstance(getattr(sr, k), int)
213+
assert team.record == (0, 0, 0)
222214

223215

224216
@pytest.mark.django_db

0 commit comments

Comments
 (0)