Another Step in the Quest to clean up the code base.
This commit is contained in:
@@ -0,0 +1 @@
|
||||
"""A simple ladder ranking system for the game mai-star."""
|
||||
@@ -1,17 +1,17 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
"""
|
||||
Created on 19.09.2011
|
||||
|
||||
@author: christian
|
||||
"""
|
||||
|
||||
""" Admin Interface to manipulate the maistar ranking """
|
||||
from django.contrib import admin
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from . import forms, models
|
||||
|
||||
|
||||
def recalculate(modeladmin, request, queryset): # @UnusedVariable
|
||||
def recalculate(modeladmin, request, queryset):
|
||||
""" Force an recalculation of the seleceted Ranking objects.
|
||||
|
||||
:param modeladmin: The current ModelAdmin.
|
||||
:param request: An HttpRequest representing the current request.
|
||||
:param queryset: A QuerySet containing the objects selected by the user.
|
||||
"""
|
||||
if isinstance(modeladmin, RankingAdmin):
|
||||
seasons = set()
|
||||
for ranking in queryset:
|
||||
@@ -25,6 +25,7 @@ recalculate.short_description = _("Recalculate")
|
||||
|
||||
|
||||
class RankingAdmin(admin.ModelAdmin):
|
||||
"""Admin interface for Mai-Star season ladder ranking entries."""
|
||||
actions = [recalculate]
|
||||
list_display = (
|
||||
'season', 'placement', 'user', 'avg_placement', 'avg_score',
|
||||
@@ -35,6 +36,7 @@ class RankingAdmin(admin.ModelAdmin):
|
||||
|
||||
|
||||
class GameAdmin(admin.ModelAdmin):
|
||||
"""Admin interface to manage Mai-Star game scores."""
|
||||
actions = [recalculate]
|
||||
# date_hierarchy = 'event__start'
|
||||
fields = (
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
__author__ = 'christian'
|
||||
"""Django Forms to add and edit Mai-Star games."""
|
||||
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext as _
|
||||
@@ -8,10 +7,12 @@ from . import models
|
||||
|
||||
|
||||
class GameForm(forms.ModelForm):
|
||||
"""To add/edit a Mai-Star game for the ladder ranking."""
|
||||
error_css_class = 'error'
|
||||
required_css_class = 'required'
|
||||
|
||||
class Meta(object):
|
||||
"""hide the metadata in the form."""
|
||||
fields = [
|
||||
'player1', 'player1_score',
|
||||
'player2', 'player2_score',
|
||||
@@ -24,14 +25,15 @@ class GameForm(forms.ModelForm):
|
||||
model = models.Game
|
||||
|
||||
def clean(self):
|
||||
"""Check that every player occours only once per game."""
|
||||
cleaned_data = super(GameForm, self).clean()
|
||||
players_in_game = set()
|
||||
for player_nr in (
|
||||
'player1', 'player2', 'player3', 'player4', 'player5', 'player6'):
|
||||
current_player = cleaned_data.get(player_nr)
|
||||
for player_no in range(1, 6):
|
||||
player = 'player{nr}'.format(nr=player_no)
|
||||
current_player = cleaned_data.get('player')
|
||||
if current_player and current_player in players_in_game:
|
||||
msg = _("%s may only participate once." % current_player)
|
||||
self._errors[player_nr] = self.error_class([msg])
|
||||
del cleaned_data[player_nr]
|
||||
self._errors[player] = self.error_class([msg])
|
||||
del cleaned_data[player]
|
||||
players_in_game.add(current_player)
|
||||
return cleaned_data
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: kasu.mahjong_ranking\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-05-10 23:16+0200\n"
|
||||
"POT-Creation-Date: 2017-06-19 22:46+0200\n"
|
||||
"PO-Revision-Date: 2016-09-28 00:24+0200\n"
|
||||
"Last-Translator: Christian Berg <xeniac.at@gmail.com>\n"
|
||||
"Language-Team: Kasu <verein@kasu.at>\n"
|
||||
@@ -19,7 +19,7 @@ msgstr ""
|
||||
"X-Generator: Poedit 1.8.9\n"
|
||||
"X-Translated-Using: django-rosetta 0.7.2\n"
|
||||
|
||||
#: maistar_ranking/admin.py:24
|
||||
#: maistar_ranking/admin.py:19
|
||||
msgid "Recalculate"
|
||||
msgstr "Neuberechnen"
|
||||
|
||||
@@ -85,7 +85,7 @@ msgstr "Mai-Star Spiel mit {0} vom {1:%Y-%m-%d}"
|
||||
#: maistar_ranking/templates/maistar_ranking/game_form.html:5
|
||||
#: maistar_ranking/templates/maistar_ranking/game_form.html:16
|
||||
#: maistar_ranking/templates/maistar_ranking/game_list.html:27
|
||||
#: maistar_ranking/templates/maistar_ranking/player_game_list.html:45
|
||||
#: maistar_ranking/templates/maistar_ranking/player_game_list.html:44
|
||||
msgid "Edit Game"
|
||||
msgstr "Spiel bearbeiten"
|
||||
|
||||
@@ -121,12 +121,12 @@ msgid "Place"
|
||||
msgstr "Platz"
|
||||
|
||||
#: maistar_ranking/templates/maistar_ranking/game_list.html:19
|
||||
#: maistar_ranking/templates/maistar_ranking/player_game_list.html:37
|
||||
#: maistar_ranking/templates/maistar_ranking/player_game_list.html:36
|
||||
msgid "Points"
|
||||
msgstr "Punkte"
|
||||
|
||||
#: maistar_ranking/templates/maistar_ranking/game_list.html:24
|
||||
#: maistar_ranking/templates/maistar_ranking/player_game_list.html:42
|
||||
#: maistar_ranking/templates/maistar_ranking/player_game_list.html:41
|
||||
msgid "Delete Game"
|
||||
msgstr "Spiel löschen"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
"""ORM Models for the Mai-Star ranking"""
|
||||
|
||||
import logging
|
||||
|
||||
@@ -7,15 +7,13 @@ from django.db import models
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from events.models import Event
|
||||
from membership.models import Membership
|
||||
from . import settings, managers
|
||||
|
||||
|
||||
class Game(models.Model):
|
||||
"""
|
||||
Ein kompettes Spiel Mai-Star bestehend aus 6 Spielern
|
||||
"""
|
||||
"""to record a complete game with 6 different players."""
|
||||
|
||||
_player_list = list()
|
||||
event = models.ForeignKey(Event, related_name='maistargame_set')
|
||||
comment = models.TextField(_('Comment'), blank=True)
|
||||
player1 = models.ForeignKey(
|
||||
@@ -71,34 +69,29 @@ class Game(models.Model):
|
||||
)
|
||||
|
||||
def get_absolute_url(self):
|
||||
"""
|
||||
URL zur Hanchanliste des Events wo diese Hanchan gelistet wurde.
|
||||
"""
|
||||
"""URL to the event subpage that lists the Mai-Star games."""
|
||||
url = reverse('maistar-game-list',
|
||||
kwargs={'event': self.event.pk})
|
||||
return u'%(url)s#%(pk)d' % {'url': url, 'pk': self.pk}
|
||||
|
||||
@property
|
||||
def player_list(self):
|
||||
try:
|
||||
return self._player_list
|
||||
except AttributeError:
|
||||
self._player_list = list()
|
||||
for nr in range(1, 7):
|
||||
self._player_list.append({
|
||||
'user': getattr(self, 'player%d' % nr),
|
||||
'score': getattr(self, 'player%d_score' % nr),
|
||||
'placement': getattr(self, 'player%d_placement' % nr),
|
||||
})
|
||||
"""return a dict() with all 6 player names, scores and placements.
|
||||
It will be cached and reused for more perfomance."""
|
||||
if self._player_list:
|
||||
return self._player_list
|
||||
for player_no in range(1, 7):
|
||||
self._player_list.append(dict(
|
||||
user=getattr(self, 'player%d' % player_no),
|
||||
score=getattr(self, 'player%d_score' % player_no),
|
||||
placement=getattr(self, 'player%d_placement' % player_no)
|
||||
))
|
||||
return self._player_list
|
||||
|
||||
def save(self, force_insert=False, force_update=False, using=None,
|
||||
update_fields=None):
|
||||
u"""
|
||||
Bestimmt die Platzierung eines jeden Spielers noch vor dem speichern.
|
||||
Außerdem wird eine Kommasperierte Liste der Spiele mitgespeichert.
|
||||
"""
|
||||
logging.debug("Berechne die Platzierungen neu...")
|
||||
def save(self, **kwargs):
|
||||
"""recalculate the rankings before saving.
|
||||
Also self.player_names will be filled with an comma sperated list of
|
||||
all 6 player names."""
|
||||
game_date = self.event.start.date()
|
||||
player_tuples = [
|
||||
(self.player1.id, self.player1.username, self.player1_score),
|
||||
@@ -138,12 +131,11 @@ class Game(models.Model):
|
||||
self.season = season_start.year
|
||||
else:
|
||||
self.season = season_start.year - 1
|
||||
super(Game, self).save(force_insert=force_insert,
|
||||
force_update=force_update, using=using,
|
||||
update_fields=update_fields)
|
||||
super(Game, self).save(**kwargs)
|
||||
|
||||
|
||||
class Ranking(models.Model):
|
||||
"""the player scores in the ladder for one season. """
|
||||
user = models.ForeignKey(settings.AUTH_USER_MODEL)
|
||||
season = models.PositiveSmallIntegerField(_("Season"))
|
||||
placement = models.PositiveIntegerField(blank=True, null=True)
|
||||
@@ -155,22 +147,24 @@ class Ranking(models.Model):
|
||||
objects = managers.LadderManager()
|
||||
|
||||
class Meta(object):
|
||||
"""Display rankings by placement, best players first."""
|
||||
ordering = ('-season', 'placement', 'avg_placement', '-avg_score',)
|
||||
|
||||
def __str__(self):
|
||||
return "Mai-Star Ranking: %s, Season: %d" % (self.user, self.season)
|
||||
return "Mai-Star Ranking: {user!s}, Season: {season!d}".format(
|
||||
user=self.user,
|
||||
season=int(self.season)
|
||||
)
|
||||
|
||||
def get_absolute_url(self):
|
||||
"""URL to the subpage of the user profile, listing all Games."""
|
||||
return reverse('maistar-player-games', kwargs={
|
||||
'username': self.user.username,
|
||||
'season': self.season
|
||||
})
|
||||
|
||||
def recalculate(self):
|
||||
logging.info(
|
||||
u'Recalculate Mai-Star Ranking for Player %s in Season %s',
|
||||
self.user, self.season
|
||||
)
|
||||
"""Recalculate the Mai-Star Ranking for this Player in this Season."""
|
||||
self.placement = None
|
||||
self.avg_placement = None
|
||||
self.avg_score = None
|
||||
@@ -199,6 +193,8 @@ class Ranking(models.Model):
|
||||
|
||||
|
||||
def update_maistar_ranking(sender, instance, **kwargs):
|
||||
"""A Django signal hook to trigger a recalculation of the rankings as soon
|
||||
as a Mai-Star game has been added, deleted, or modified."""
|
||||
for player in instance.player_list:
|
||||
ranking, created = Ranking.objects.get_or_create(
|
||||
user=player['user'],
|
||||
|
||||
@@ -1,30 +1,24 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
"""
|
||||
Created on 03.10.2011
|
||||
""" Definition of the URL paths to access the views of the Maistar ranking. """
|
||||
|
||||
@author: christian
|
||||
"""
|
||||
from django.conf.urls import url
|
||||
from django.views.generic import RedirectView
|
||||
from .views import DeleteGame, ListGames, ListPlayerGames, \
|
||||
ListRankings, GameForm
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
url('^$', ListRankings.as_view()),
|
||||
url('^$', views.ListRankings.as_view()),
|
||||
url(r'^event/(?P<event>[\d]+)/maistar/$',
|
||||
ListGames.as_view(), name="maistar-game-list"),
|
||||
views.ListGames.as_view(), name="maistar-game-list"),
|
||||
url(r'^event/(?P<event>[\d]+)/maistar/add/$',
|
||||
GameForm.as_view(), name="maistar-add-game"),
|
||||
views.GameForm.as_view(), name="maistar-add-game"),
|
||||
url(r'^maistar/(?P<game>[\d]+)/edit/$',
|
||||
GameForm.as_view(), name="maistar-edit-game"),
|
||||
views.GameForm.as_view(), name="maistar-edit-game"),
|
||||
url(r'^maistar/(?P<game>[\d]+)/delete/$',
|
||||
DeleteGame.as_view(), name="maistar-delete-game"),
|
||||
url(r'^maistar/$', ListRankings.as_view(), name="maistar-ranking"),
|
||||
views.DeleteGame.as_view(), name="maistar-delete-game"),
|
||||
url(r'^maistar/$',
|
||||
views.ListRankings.as_view(), name="maistar-ranking"),
|
||||
url(r'^maistar/(?P<season>[\d]+)/$',
|
||||
ListRankings.as_view(), name="maistar-ranking"),
|
||||
views.ListRankings.as_view(), name="maistar-ranking"),
|
||||
url(r'^player/(?P<username>[\-\.\d\w]+)/maistar/$',
|
||||
ListPlayerGames.as_view(), name="maistar-player-games"),
|
||||
views.ListPlayerGames.as_view(), name="maistar-player-games"),
|
||||
url(r'^player/(?P<username>[\-\.\d\w]+)/maistar/(?P<season>[\d]+)/$',
|
||||
ListPlayerGames.as_view(), name="maistar-player-games"),
|
||||
views.ListPlayerGames.as_view(), name="maistar-player-games"),
|
||||
]
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
"""Views to display the Mai-Star Ladder an Mai-Star game scores."""
|
||||
|
||||
from datetime import date
|
||||
|
||||
from django.contrib import auth
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views import generic
|
||||
|
||||
from events.models import Event
|
||||
from events.views import EventDetailMixin
|
||||
from membership.models import Membership
|
||||
from utils.mixins import LoginRequiredMixin
|
||||
from utils.mixins import PermissionRequiredMixin
|
||||
from events.mixins import EventDetailMixin
|
||||
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||||
from mahjong_ranking.views import PlayerScore
|
||||
from . import forms, models
|
||||
|
||||
@@ -120,5 +117,5 @@ class ListRankings(generic.ListView):
|
||||
context['season_list'] = models.Ranking.objects.get_seasons()
|
||||
context['latest_games'] = models.Game.objects.filter(confirmed=True)[
|
||||
:3]
|
||||
context['latest_events'] = Event.objects.latest_events(num=3)
|
||||
context['latest_events'] = Event.objects.upcoming(limit=3)
|
||||
return context
|
||||
|
||||
Reference in New Issue
Block a user