Squashed commit of the following:

commit bb5081a78b
Author: Xeniac <xeniac@posteo.at>
Date:   Thu Nov 23 22:02:40 2017 +0100

    Added a setting where the exported excel files should be stored.
    Added a option to send the exported excel as mail attachment.

commit 854fd38740
Author: Xeniac <xeniac@posteo.at>
Date:   Thu Nov 23 22:01:38 2017 +0100

    Fixed: enumerate the Seasonrankings starting with 1
    Fixed: Logging error when a value changed from/to None

commit 6de1ecb102
Author: Christian Berg <xeniac@posteo.at>
Date:   Thu Nov 23 14:15:36 2017 +0100

    add a latest method to query the latest x events

commit bf12060c3b
Author: Christian Berg <xeniac@posteo.at>
Date:   Thu Nov 23 14:15:12 2017 +0100

    add a latest method to query the latest x events

commit 5ad628f33a
Author: Christian Berg <xeniac@posteo.at>
Date:   Mon Nov 20 07:47:47 2017 +0100

    Changed PlayerDanScore to only list non-legacy hanchans

commit 36272c60d6
Author: Christian Berg <xeniac@posteo.at>
Date:   Mon Nov 20 07:42:44 2017 +0100

    fixed import of MIN_HANCHANS_FOR_LADDER that moved to settings

commit c428f6ed1f
Author: Christian Berg <xeniac@posteo.at>
Date:   Mon Nov 20 07:41:04 2017 +0100

    Updated docstrings for new since and until kwargs

commit 9276e97c36
Author: Christian Berg <xeniac@posteo.at>
Date:   Mon Nov 20 07:33:54 2017 +0100

    added a since parameter to the hanchan queries to return only hanchans since the give date and time

commit fd244f10e8
Author: Christian Berg <xeniac@posteo.at>
Date:   Sun Nov 19 16:55:10 2017 +0100

    new command: resetdanranking YYYY-MM-DD, sets every dan player to 1st dan with zero dan_points at the given date.

commit 0a45cf1fd8
Author: Christian Berg <xeniac@posteo.at>
Date:   Sun Nov 19 16:14:59 2017 +0100

    added new fields to KyuDanRanking that allow to pick up the calculation from the last state of the KyuDanRanking.
    last_hanchan_date: it contains the start of the latest hanchan content for this players ranking.
    wins_in_row: to save the currents wins in a row

    Added option to calcuclate rankings until a given datetime.
This commit is contained in:
2017-11-23 22:26:22 +01:00
parent a3c02ae73a
commit 97749bfd2e
18 changed files with 530 additions and 180 deletions

View File

@@ -1,7 +1,8 @@
"""ObjectManagers for the Django Models used in the Mahjong-Ranking."""
from datetime import date
from . import LOGGER
from django.db import models
from django.conf import settings
class HanchanManager(models.Manager):
@@ -12,23 +13,31 @@ class HanchanManager(models.Manager):
"""
use_for_related_fields = True
def confirmed_hanchans(self, user=None, **filter_args):
def confirmed(self, user=None, since=None, until=None, **filter_args):
""" Return all valid and confirmed Hanchans.
:param user: Only return Hanchans where this user participated.
:param user: Only return Hanchans where this user participated.
:param since: only return Hanchans played since the given datetime
:param until: only return Hanchans played until the given datetime
:param filter_args: To add specific arguments to the Django filter.
:return: QuerySet Object
"""
if user:
return self.user_hanchans(user, confirmed=True, **filter_args)
else:
return self.filter(confirmed=True, **filter_args)
return self.user_hanchans(user, confirmed=True, until=until,
**filter_args)
hanchans = self.filter(confirmed=True, **filter_args)
if since:
hanchans = hanchans.filter(start__gt=since)
if until:
hanchans = hanchans.filter(start__lte=until)
return hanchans
def dan_hanchans(self, user, **filter_args):
def dan_hanchans(self, user, since = None, **filter_args):
""" Return all Hanchans where a specific user has participated and had
gain dan points and make his gamestats availabale.
:param user: Only return Hanchans where this user participated.
:param since: only return Hanchans played since the given datetime
:param filter_args: To add specific arguments to the Django filter.
:return: QuerySet Object
"""
@@ -38,15 +47,18 @@ class HanchanManager(models.Manager):
models.Q(player3=user, player3_dan_points__isnull=False) |
models.Q(player4=user, player4_dan_points__isnull=False)
).filter(confirmed=True, **filter_args)
if since:
queryset = queryset.filter(start__gt=since)
queryset = queryset.select_related().order_by('-start')
[ hanchan.get_playerdata(user) for hanchan in queryset ]
[hanchan.get_playerdata(user) for hanchan in queryset]
return queryset
def kyu_hanchans(self, user, **filter_args):
def kyu_hanchans(self, user, since = None, **filter_args):
""" Return all Hanchans where a specific user has participated and had
gain kyū points and make his gamestats availabale.
:param user: Only return Hanchans where this user participated.
:param since: only return Hanchans played since the given datetime
:param filter_args: To add specific arguments to the Django filter.
:return: QuerySet Object
"""
@@ -56,25 +68,30 @@ class HanchanManager(models.Manager):
models.Q(player3=user, player3_kyu_points__isnull=False) |
models.Q(player4=user, player4_kyu_points__isnull=False)
).filter(confirmed=True, **filter_args)
if since:
queryset = queryset.filter(start__gt=since)
queryset = queryset.select_related().order_by('-start')
[ hanchan.get_playerdata(user) for hanchan in queryset ]
[hanchan.get_playerdata(user) for hanchan in queryset]
return queryset
def season_hanchans(self, user=None, season=None):
def season_hanchans(self, user=None, season=None, until=None):
"""Return all Hanchans that belong to a given or the current season.
:param user: Only return Hanchans where this user participated.
:param season: the year of the wanted season, current year if None.
:return: QuerySet Object
"""
season = season or date.today().year
return self.confirmed_hanchans(user=user, season=season)
try:
season = season or until.year
except AttributeError:
season = date.today().year
return self.confirmed(user=user, season=season, until=until)
def user_hanchans(self, user, since=None, **filter_args):
def user_hanchans(self, user, since=None, until=None, **filter_args):
"""Return all Hanchans where a specific user has participated.
:param user: Return Hanchans where this user participated.
:param since: optional a date value since when you want to hanchans
:param since: only return Hanchans played since the given datetime
:param filter_args: To add specific arguments to the Django filter.
:return: a QuerySet Object
"""
@@ -82,15 +99,16 @@ class HanchanManager(models.Manager):
models.Q(player1=user) | models.Q(player2=user) |
models.Q(player3=user) | models.Q(player4=user)
)
queryset = queryset.filter(**filter_args)
if since:
queryset = queryset.filter(start__gte=since, **filter_args)
else:
queryset = queryset.filter(**filter_args)
queryset = queryset.filter(start__gte=since)
if until:
queryset = queryset.filter(start__lte=until)
queryset = queryset.select_related().order_by('-start')
[ hanchan.get_playerdata(user) for hanchan in queryset ]
[hanchan.get_playerdata(user) for hanchan in queryset]
return queryset
def unconfirmed_hanchans(self, user=None, **filter_args):
def unconfirmed(self, user=None, **filter_args):
""" Return all Hanchans that have been set to unconfirmed.
:param user: Only return Hanchans where this user participated.
@@ -158,8 +176,27 @@ class SeasonRankingManager(models.Manager):
})
return json_data
class KyuDanRankingManager(models.Manager):
def update(self, season=None, until=None, force_recalc=False):
try:
season = season or until.year
except AttributeError:
season = date.today().year
if until or force_recalc:
for ranking in self.filter(season=season):
ranking.recalculate(until=until)
for placement, ranking in enumerate(self.season_rankings(season), start=1):
ranking.placement = placement
ranking.save(force_update=True, update_fields=['placement'])
def season_rankings(self, season=None):
season = season or date.today().year
rankings = self.filter(
season=season,
hanchan_count__gt=settings.MIN_HANCHANS_FOR_LADDER)
return rankings.order_by('avg_placement', '-avg_score')
class KyuDanRankingManager(models.Manager):
def json_data(self):
""" Get all Rankings for a given Season and return them as a list of
dict objects, suitable for JSON exports and other processings.
@@ -172,9 +209,12 @@ class KyuDanRankingManager(models.Manager):
values = values.values('user_id', 'user__username',
'user__first_name', 'user__last_name',
'dan', 'dan_points', 'kyu', 'kyu_points',
'hanchan_count', 'won_hanchans', 'good_hanchans')
'hanchan_count', 'won_hanchans', 'good_hanchans',
'last_hanchan_date')
for user in values:
if user['dan']:
if user['hanchan_count'] == 0:
continue
elif user['dan']:
rank = '{}. Dan'.format(user['dan'])
points = user['dan_points']
else:
@@ -183,11 +223,31 @@ class KyuDanRankingManager(models.Manager):
json_data.append({
'user_id': user['user_id'],
'username': user['user__username'],
'full_name': " ".join([user['user__last_name'], user['user__first_name']]),
'full_name': " ".join(
[user['user__last_name'], user['user__first_name']]),
'rank': rank,
'points': points,
'hanchan_count': user['hanchan_count'],
'good_hanchans': user['good_hanchans'],
'won_hanchans': user['won_hanchans']
'won_hanchans': user['won_hanchans'],
'last_hanchan_date': user['last_hanchan_date']
})
return json_data
def update(self, since=None, until=None, force_recalc=False):
old_attr = {'dan': None, 'dan_points': None,
'kyu': None, 'kyu_points': None, 'won_hanchans': None,
'good_hanchans': None, 'hanchan_count': None}
for ranking in self.all():
old_attr = {attr: getattr(ranking, attr) for attr in
old_attr.keys()}
ranking.calculate(since=since, until=until,
force_recalc=force_recalc)
for attr, old_value in old_attr.items():
if getattr(ranking, attr) != old_value:
LOGGER.warning(
"%(user)s recalc shows differences in %(attr)s! old: %(old)d, new: %(new)d",
{'user': ranking.user, 'attr': attr,
'old': old_value or 0, 'new': getattr(ranking, attr) or 0}
)