Beispiel #1
0
    def get_queryset(self):
        season = SeasonChooser(self.request).current
        qs = filter_season(Game.objects, season, should_include_live=True)

        query = self.request.GET.get("query", "")
        parts = re.split(r"[\s,]", query)
        for part in parts:
            part = part.strip()
            if part != "":
                if part[0] == "#":
                    # Filter by hashtag in description
                    qs = qs.filter(description__icontains=part)
                else:
                    # Filter by username
                    qs = qs.filter(players__username__icontains=part)

        qs = qs.distinct()

        if self.order.current_column == "end_datetime":
            # First show live games (but not dnf games),
            # then show all other games sorted by
            # end_datetime if it is not null,
            # otherwise use start_datetime instead
            qs = qs.order_by(
                Case(
                    When(end_datetime__isnull=True, dnf=False, then=Value(0)),
                    default=Value(1),
                    output_field=IntegerField(),
                ),
                Case(
                    When(end_datetime__isnull=True, then="start_datetime"),
                    default="end_datetime",
                    output_field=DateTimeField(),
                ).desc(),
                "id",
            )
            if self.order.reverse:
                qs = qs.reverse()
        elif self.order.current_column == "duration":
            qs = Game.add_durations(qs)

            # Always show games with unknown duration last
            if self.order.reverse:
                qs = qs.order_by(F("duration").desc(nulls_last=True), "id")
            else:
                qs = qs.order_by(F("duration").asc(nulls_last=True), "id")

        return qs
Beispiel #2
0
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        season = SeasonChooser(self.request).current

        chooser = PlayerCountChooser(self.request)
        context["player_count_chooser"] = chooser
        player_count = chooser.current

        games = filter_season_and_player_count(Game.objects, season, player_count)

        total_sips = (
            Card.objects.filter(game__id__in=games).aggregate(total_sips=Sum("value"))[
                "total_sips"
            ]
            or 0
        )

        games_with_durations = Game.add_durations(games)

        total_duration = games_with_durations.aggregate(total_duration=Sum("duration"))[
            "total_duration"
        ] or datetime.timedelta(0)

        context["game_stats"] = {
            "total_games": games.count(),
            "total_dnf": games.filter(dnf=True).count(),
            "total_sips": total_sips,
            "total_beers": total_sips / 14,
            "total_duration": str(round_timedelta(total_duration)),
        }

        games_played = Counter()
        for g in games.all():
            if g.end_datetime:
                games_played[g.end_datetime.date()] += 1

        context["heatmap_data"] = games_heatmap_data(games, season)

        stat_types = {
            "sips_data": (
                GamePlayerStat.get_sips_distribution(season, player_count),
                self.sips_count_distribution,
            ),
            "chugs_data": (
                GamePlayerStat.get_chugs_distribution(season, player_count),
                self.chug_count_distribution,
            ),
        }

        for name, (stats, prob_f) in stat_types.items():
            xs = []
            ys = []
            probs = []
            dist_str = None
            if stats.exists():
                d = {s["value"]: s["value__count"] for s in stats}
                if prob_f:
                    if player_count == None:
                        dist, dist_str = self.combined_distribution(season, prob_f)
                    else:
                        dist, dist_str = prob_f(player_count)

                for x in range(stats.first()["value"], stats.last()["value"] + 1):
                    xs.append(x)
                    ys.append(d.get(x, 0))

                    if dist:
                        probs.append(dist(x))

            context[name] = {
                "xs": xs,
                "ys": ys,
                "total_ys": sum(ys),
                "probs": probs,
                "probs_exact": True,
                "dist_str": dist_str,
            }

        BUCKETS = 60
        chugs = filter_season_and_player_count(
            Chug.objects, season, player_count, key="card__game"
        )
        duration_data = [
            {
                "name": "duration_data",
                "max_duration": 4,
                "max_duration_unit": "hours",
                "durations": lambda max_duration: (
                    g["duration"]
                    for g in games_with_durations.filter(
                        dnf=False, duration__lte=max_duration
                    ).values("duration")
                ),
                "format": str,
            },
            {
                "name": "chug_duration_data",
                "max_duration": 15,
                "max_duration_unit": "seconds",
                "durations": lambda max_duration: (
                    datetime.timedelta(milliseconds=c["duration_ms"])
                    for c in chugs.filter(
                        duration_ms__lte=get_milliseconds(max_duration)
                    ).values("duration_ms")
                ),
                "format": lambda td: f"{td.total_seconds():.2f}",
            },
        ]

        for d in duration_data:
            max_duration = datetime.timedelta(
                **{d["max_duration_unit"]: d["max_duration"]}
            )
            bucket_span = max_duration / BUCKETS
            occurrences = Counter()
            for duration in d["durations"](max_duration):
                x = int(duration / bucket_span)
                occurrences[x] += 1

            context[d["name"]] = {
                "total_ys": sum(occurrences.values()),
                "bucket_span_seconds": bucket_span.total_seconds(),
                "max_duration": f"{d['max_duration']} {d['max_duration_unit']}",
                "xs": [d["format"]((i + 1) * bucket_span) for i in range(BUCKETS)],
                "ys": [occurrences[i] for i in range(BUCKETS)],
            }

        context["chug_table_header"] = ["Players\xa0\\\xa0Chugs", *range(6 + 1)]
        context["chug_table"] = []
        for pcount in range(2, 6 + 1):
            row = [pcount]
            context["chug_table"].append(row)
            dist, _ = self.chug_count_distribution(pcount)
            for chugs in range(6 + 1):
                row.append(dist(chugs) * 100 if chugs <= pcount else None)

        context["location_data"] = []
        for g in games.filter(
            location_latitude__isnull=False, location_accuracy__lte=100 * 1000
        ):
            game_url = reverse("game_detail", args=[g.id])
            context["location_data"].append(
                {
                    "latitude": g.location_latitude,
                    "longitude": g.location_longitude,
                    "popup": f"<a href='{game_url}'>{g.date}<br>{g.players_str()}</a>",
                }
            )

        return context