export_ranking now exports KyuDanRankings and SeasonRankings.

This commit is contained in:
2017-11-03 07:15:28 +01:00
parent f3d44b743b
commit d5b67ffe0c
4 changed files with 226 additions and 21 deletions

View File

@@ -1,36 +1,148 @@
"""Export Mahjong Rankings as excel files.""" """Export Mahjong Rankings as excel files."""
from datetime import date
from operator import itemgetter from operator import itemgetter
import openpyxl
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from openpyxl import Workbook from openpyxl.styles import Border
from mahjong_ranking.models import SeasonRanking from mahjong_ranking.models import SeasonRanking, KyuDanRanking
THIN_BORDER = openpyxl.styles.Side(style='thin', color="d3d7cf")
HEADING_STYLE = openpyxl.styles.NamedStyle(name="heading")
HEADING_STYLE.font = openpyxl.styles.Font(name='Philosopher', size=11,
bold=True, color='ffffff')
HEADING_STYLE.fill = openpyxl.styles.PatternFill(fill_type='solid',
start_color='a40000',
end_color='a40000')
DEFAULT_STYLE = openpyxl.styles.NamedStyle(name='content')
DEFAULT_STYLE.font = openpyxl.styles.Font(name='Philosopher', size=10,
bold=False, color='000000')
DEFAULT_STYLE.border = openpyxl.styles.Border(bottom=THIN_BORDER,
top=THIN_BORDER)
INT_STYLE = openpyxl.styles.NamedStyle(name='int')
INT_STYLE.font = DEFAULT_STYLE.font
INT_STYLE.border = DEFAULT_STYLE.border
INT_STYLE.number_format = '#,##0'
FLOAT_STYLE = openpyxl.styles.NamedStyle(name='float')
FLOAT_STYLE.font = DEFAULT_STYLE.font
FLOAT_STYLE.border = DEFAULT_STYLE.border
FLOAT_STYLE.number_format = '#,##0.00'
def geneate_seasonexcel(json_data): def geneate_excel():
"""Generate an excel .xlsx spreadsheet from json data of the kyu/dan """Generate an excel .xlsx spreadsheet from json data of the kyu/dan
rankings. rankings.
:param json_data: The ladder ranking as JSON export.""" :param json_data: The ladder ranking as JSON export."""
workbook = Workbook() workbook = openpyxl.Workbook()
worksheet = workbook.active workbook.add_named_style(HEADING_STYLE)
workbook.add_named_style(DEFAULT_STYLE)
workbook.add_named_style(INT_STYLE)
workbook.add_named_style(FLOAT_STYLE)
for sheet in workbook.worksheets:
print(sheet)
workbook.remove(sheet)
return workbook
worksheet.append([
'Rang', 'Spitzname',
'⌀ Platz', '⌀ Punkte',
'Hanchans', 'Gut', 'Gewonnen'
])
json_data = sorted(json_data, key=itemgetter('placement')) def generate_sheet(workbook, title, columns_settings, json_data):
for row in json_data: row = 1
worksheet.append([ ws = workbook.create_sheet()
row['placement'], row['username'], ws.title = title
row['avg_placement'], row['avg_score'],
row['hanchan_count'], # setup print orientation
row['good_hanchans'], row['won_hanchans'] ws.page_setup.orientation = ws.ORIENTATION_PORTRAIT
]) ws.page_setup.paperSize = ws.PAPERSIZE_A4
workbook.save("sample.xlsx") ws.page_setup.fitToWidth = True
ws.print_options.horizontalCentered = True
# setup page header
ws.oddHeader.left.text = title
ws.oddHeader.left.size = 14
ws.oddHeader.left.font = "Amerika Sans"
ws.oddHeader.left.color = "000000"
ws.oddHeader.right.text = str(date.today())
ws.oddHeader.right.size = 14
ws.oddHeader.right.font = "Amerika Sans"
ws.oddHeader.right.color = "000000"
# write table header
for column, data in enumerate(columns_settings, 1):
cell = ws.cell(column=column, row=row, value=data['title'])
cell.style = 'heading'
# write the table content
for line in json_data:
row += 1
for column, settings in enumerate(columns_settings, 1):
cell = ws.cell(column=column, row=row, value=line[settings['attr']])
cell.style = settings['style']
# set column widths
for settings in columns_settings:
ws.column_dimensions[settings['col']].width = settings['width']
def export_season_rankings(workbook):
json_data = sorted(SeasonRanking.objects.json_data(),
key=itemgetter('placement'))
title = "Mahjong Ladder - {}".format(date.today().year)
columns_settings = (
{'col': 'A', 'title': 'Rang', 'attr': 'placement', 'style': 'int',
'width': 8},
{'col': 'B', 'title': 'Spitzname', 'attr': 'username',
'style': 'content',
'width': 25},
{'col': 'C', 'title': '⌀ Platz', 'attr': 'avg_placement',
'style': 'int', 'width': 8},
{'col': 'D', 'title': '⌀ Punkte', 'attr': 'avg_score',
'style': 'float', 'width': 12},
{'col': 'E', 'title': 'Hanchans', 'attr': 'hanchan_count',
'style': 'int', 'width': 10},
{'col': 'F', 'title': 'Gut', 'attr': 'good_hanchans',
'style': 'int', 'width': 5},
{'col': 'G', 'title': 'Gewonnen', 'attr': 'won_hanchans',
'style': 'int', 'width': 10},
)
generate_sheet(
workbook=workbook,
title=title,
columns_settings=columns_settings,
json_data=json_data)
def export_kyu_dan_rankings(workbook):
json_data = KyuDanRanking.objects.json_data()
title = "Kyū & Dan Rankings"
columns_settings = (
{'col': 'A', 'title': 'Spitzname', 'attr': 'username',
'style': 'content', 'width': 14},
{'col': 'B', 'title': 'Voller Name', 'attr': 'full_name',
'style': 'content', 'width': 20},
{'col': 'C', 'title': 'Rang', 'attr': 'rank',
'style': 'content', 'width': 8},
{'col': 'D', 'title': 'Punkte', 'attr': 'points',
'style': 'int', 'width': 8},
{'col': 'E', 'title': 'Hanchans', 'attr': 'hanchan_count',
'style': 'int', 'width': 10},
{'col': 'F', 'title': 'Gut', 'attr': 'good_hanchans',
'style': 'int', 'width': 5},
{'col': 'G', 'title': 'Gewonnen', 'attr': 'won_hanchans',
'style': 'int', 'width': 10},
)
generate_sheet(
workbook=workbook,
title=title,
columns_settings=columns_settings,
json_data=json_data)
class Command(BaseCommand): class Command(BaseCommand):
@@ -39,4 +151,8 @@ class Command(BaseCommand):
def handle(self, *args, **options): def handle(self, *args, **options):
"""Exports the current ladder ranking in a spreadsheet. """Exports the current ladder ranking in a spreadsheet.
This is useful as a backup in form of a hardcopy.""" This is useful as a backup in form of a hardcopy."""
geneate_seasonexcel(SeasonRanking.objects.json_data()) workbook = geneate_excel()
export_season_rankings(workbook)
export_kyu_dan_rankings(workbook)
workbook.save('sample.x')
workbook.save('mahjong_rankings_{}.xlsx'.format(str(date.today())))

View File

@@ -157,3 +157,37 @@ class SeasonRankingManager(models.Manager):
'won_hanchans': user['won_hanchans'] 'won_hanchans': user['won_hanchans']
}) })
return json_data return json_data
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.
:param season: Season that should be exported, current season if empty
:return: a list() of dict() objects suiteable for JSON export.
"""
json_data = list()
values = self.all()
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')
for user in values:
if user['dan']:
rank = '{}. Dan'.format(user['dan'])
points = user['dan_points']
else:
rank = '{}. Kyū'.format(user['kyu'])
points = user['kyu_points']
json_data.append({
'user_id': user['user_id'],
'username': user['user__username'],
'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']
})
return json_data

View File

@@ -346,9 +346,11 @@ class KyuDanRanking(models.Model):
legacy_dan_points = models.PositiveIntegerField(default=0) legacy_dan_points = models.PositiveIntegerField(default=0)
legacy_kyu_points = models.PositiveIntegerField(default=0) legacy_kyu_points = models.PositiveIntegerField(default=0)
wins_in_a_row = 0 wins_in_a_row = 0
objects = managers.KyuDanRankingManager()
class Meta(object): class Meta(object):
ordering = ('-dan', '-dan_points', '-kyu_points',) ordering = ('-dan_points', 'dan', '-kyu_points')
verbose_name = _(u'Kyū/Dan Ranking') verbose_name = _(u'Kyū/Dan Ranking')
verbose_name_plural = _(u'Kyū/Dan Rankings') verbose_name_plural = _(u'Kyū/Dan Rankings')

View File

@@ -0,0 +1,53 @@
"""To geneate a Sitemap with all events."""
from datetime import date
from django.contrib.sitemaps import Sitemap
from django.urls import reverse
from events.models import Event
from kasu.sitemaps import GenericSitemap
from .models import SeasonRanking
class EventRankingSitemap(GenericSitemap):
@staticmethod
def items():
"""add all upcoming and archived events to the sitemap."""
return Event.objects.all().exclude(eventranking=None)
@staticmethod
def location(event):
return reverse('event-ranking', kwargs={'event': event.id})
class EventHanchanSitemap(GenericSitemap):
@staticmethod
def items():
"""add all upcoming and archived events to the sitemap."""
return Event.objects.all().exclude(eventranking=None)
@staticmethod
def location(event):
return reverse('event-hanchan-list', kwargs={'event': event.id})
class MajongSeasonSitemap(Sitemap):
priority = 0.5
@staticmethod
def items():
seasons = SeasonRanking.objects.all().distinct('season').order_by(
'season')
seasons = seasons.values_list('season', flat=True)
return seasons
@staticmethod
def location(season):
return reverse('mahjong-ladder', kwargs={'season': season})
@staticmethod
def changefreq(season):
if season == date.today().year:
return 'weekly'
else:
return 'never'