Home > Django > djangofantalega: model Lineup

djangofantalega: model Lineup

14 Novembre 2016

9 – Models: Lineup

Creare il Model Lineup.
Lineup (formazione) è in relazione many-to-one con Team,
ma è anche in relazione con Player.
Una formazione (Lineup) contiene molti giocatori (Player), ma un
giocatore, può far parte di più formazioni;
la relazione Player-Lineup è quindi di tipo many-to-many.

add_lineup

Come già fatto in precedenza, si utilizzerà una association-table per la relazione ManytoMany
in modo da poter sfruttare l’attributo ‘position’, poichè la posizione di un giocatore
in panchina, è determinante quando si usa il cambio modulo.

Aggiungere quindi nel file fantalega/models.py i models necessari:

...
class Lineup (models.Model):
    league = models.ForeignKey(League, related_name='league_lineups')
    team = models.ForeignKey(Team, related_name='team_lineups')
    players = models.ManyToManyField(Player, through='LineupsPlayers',
                                     related_name='player_lineups')
    timestamp = models.DateTimeField()
    day = models.IntegerField()
    pts = models.FloatField(null=True)
    won = models.IntegerField(null=True)
    matched = models.IntegerField(null=True)
    lost = models.IntegerField(null=True)
    goals_made = models.IntegerField(null=True)
    goals_conceded = models.IntegerField(null=True)

    def get_players_by_position(self):
        lineup_players = LineupsPlayers.query.filter(lineup=self.id).order_by(
            LineupsPlayers.position).all()
        if lineup_players:
            return [rec.player for rec in lineup_players]

    def __unicode__(self):
        return "[%s] %s" % (self.day, self.team.name)


# M2M secondary Association object
class LineupsPlayers(models.Model):
    player = models.ForeignKey(Player, on_delete=models.CASCADE)
    lineup = models.ForeignKey(Lineup, on_delete=models.CASCADE)
    position = models.IntegerField()

    class Meta:
        verbose_name_plural = 'Lineup-Player Associations'

    @staticmethod
    def get_sorted_lineup(lineup):
        return LineupsPlayers.objects.filter(
            lineup=lineup).order_by('position').all()

Aggiornare il database inserendo le nuove tabelle.

(venv) >python manage.py makemigrations
Migrations for 'fantalega':
  fantalega\migrations\0006_auto_20161111_1103.py:
    - Create model Lineup
    - Create model LineupsPlayers
    - Add field players to lineup
    - Add field team to lineup

confermare con:

(venv) C:\tmp\djangosite>python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, fantalega, log, sessions
Running migrations:
  Applying fantalega.0006_auto_20161111_1103... OK

Sistemare l’interfaccia di admin per i nuovi modelli:
file fantalega/admin.py:

# noinspection PyUnresolvedReferences
...
from .models import Lineup, LineupsPlayers


# Register your models here.
class LineupPlayersInline(admin.TabularInline):
    model = Lineup.players.through
    extra = 0
    classes = ('collapse',)
	

class LineupAdmin(admin.ModelAdmin):
    inlines = [LineupPlayersInline, ]
    ordering = ('day', )
    list_display = ('day', 'team', 'pts')
    list_filter = ('day', 'team')
    list_per_page = 20

	
class LineupsPlayersAdmin(admin.ModelAdmin):
    ordering = ('position', )
    list_display = ('position', 'colored_player', 'get_team_name', )
    list_filter = ('lineup__day', 'lineup__team__name')
    list_per_page = 21

    @staticmethod
    def get_team_name(obj):
        return obj.lineup.team.name

    @staticmethod
    def colored_player(obj):
        colour = '013ADF' if obj.position <= 11 else 'FF0080'
        return format_html('<span style="color: #{};">{}</span>',
                           colour, obj.player.name)


...
admin.site.register(Lineup, LineupAdmin)
admin.site.register(LineupsPlayers, LineupsPlayersAdmin)

Ora aggiungere gli urls inerenti Lineup nel file fantalega\urls.py:

...
    # lineup urls
    url(r'^leagues/(?P<league_id>[0-9]+)/teams/'
        r'(?P<team_id>[0-9]+)/lineup/upload$', views.upload_lineup,
        name='upload_lineup'),
    url(r'^leagues/(?P<league_id>[0-9]+)/teams/(?P<team_id>[0-9]+)'
        r'/lineup/(?P<day>[0-9]+)/$',
        views.lineup_details, name='lineup_details'),
    url(r'^leagues/(?P<league_id>[0-9]+)/teams/(?P<team_id>[0-9]+)'
        r'/lineup/(?P<day>[0-9]+)/edit$',
        views.lineup_edit, name='lineup_edit'),
]

Aggiungere nel file fantalega\views.py le nuove viste ‘upload_lineup’,
‘lineup_details’ e ‘lineup_edit’:

...
from .models import Lineup, LineupsPlayers
from django.utils import timezone  # this is important!
...
@login_required
def upload_lineup(request, league_id, team_id, day=None):
    league = get_object_or_404(League, pk=int(league_id))
    modules = [(1, '343'), (2, '352'), (3, '442'), (4, '433'), (5, '451'),
               (6, '532'), (7, '541')]
    team = get_object_or_404(Team, pk=int(team_id))
    if request.GET.get('back_to_team_details'):
        return redirect('team_details', league.id, team.id)
    team_players = [(p.code, "%s [%s]" % (p.name, p.role))
                    for p in team.player_set.all()]
    if request.method == "POST":
        form = UploadLineupForm(request.POST,
                                initial={'players': team_players, 'team': team,
                                         'modules': modules, 'day': day,
                                         'league': league})
        if form.is_valid():
            day = form.cleaned_data['day']
            lineup = Lineup.objects.filter(team=team, day=day,
                                           league=league).first()
            if lineup:
                messages.error(request, 'Lineup already exists!')
                return redirect('team_details', league_id, team_id)

            holders = [Player.get_by_code(int(code), season=league.season)
                       for code in form.cleaned_data['holders']]
            substitutes = [Player.get_by_code(int(code), season=league.season)
                           for code in [form.cleaned_data['substitute_%s' % n]
                           for n in range(1, 11)]]
            error = form.check_holders()
            if error:
                messages.error(request, error)
            else:
                dead_line = Match.objects.filter(
                    league=league, day=day).first().dead_line
                now = timezone.now()
                if now > dead_line:
                    messages.error(request, "You are out of time!")
                    messages.info(request, "Getting the previous Lineup")
                    lineup = Lineup.objects.filter(
                        team=team, day=(day - 1), league=league).first()
                    holders = [p for p in lineup.players.all()[:11]]
                    substitutes = [p for p in lineup.players.all()[11:]]
                lineup = Lineup.objects.create(team=team, day=day,
                                               league=league, timestamp=now)
                for pos, player in enumerate((holders + substitutes), 1):
                    LineupsPlayers.objects.create(position=pos, lineup=lineup,
                                                  player=player)
                messages.success(request, 'Lineup uploaded!')
                return redirect('team_details', league_id, team_id)
    else:
        form = UploadLineupForm(initial={'players': team_players, 'team': team,
                                         'modules': modules, 'day': day,
                                         'league': league})
    return render(request, 'fantalega/upload_lineup.html',
                  {'form': form, 'players': team_players, 'team': team,
                   'league': league})


@login_required
def lineup_edit(request, league_id, team_id, day):
    league = get_object_or_404(League, pk=int(league_id))
    modules = [(1, '343'), (2, '352'), (3, '442'), (4, '433'), (5, '451'),
               (6, '532'), (7, '541')]
    team = get_object_or_404(Team, pk=int(team_id))
    if request.GET.get('back_to_team_details'):
        return redirect('team_details', league.id, team.id)
    lineup = Lineup.objects.filter(team=team, league=league, day=day).first()
    team_players = [(p.code, "%s [%s]" % (p.name, p.role))
                    for p in team.player_set.all()]
    if request.method == "POST":
        form = UploadLineupForm(request.POST,
                                initial={'players': team_players, 'team': team,
                                         'modules': modules, 'day': day,
                                         'league': league})
        if form.is_valid():
            day = form.cleaned_data['day']
#            module_id = form.cleaned_data['module']
#            module = dict(form.fields['module'].choices)[int(module_id)]
            holders = [Player.get_by_code(int(code), season=league.season)
                       for code in form.cleaned_data['holders']]
            substitutes = [Player.get_by_code(int(code), season=league.season)
                           for code in [form.cleaned_data['substitute_%s' % n]
                           for n in range(1, 11)]]
            error = form.check_holders()
            if error:
                messages.error(request, error)
            else:
                now = timezone.now()
                dead_line = Match.objects.filter(
                    league=league, day=day).first().dead_line
                if now > dead_line:
                    messages.error(request, "You are out of time!")
                    messages.info(request, "No change saved")
                else:
                    messages.success(request, "Lineup correct!")
                    lineup.timestamp = now
                    lineup.save()
                    for pos, player in enumerate((holders + substitutes), 1):
                        lu = LineupsPlayers.objects.filter(
                            lineup=lineup, position=int(pos)).first()
                        lu.player = player
                        lu.save()
                        print "[INFO] Lineup %s (%s) -> Player %s " \
                              "pos %s upgraded!" % (team.name, day,
                                                    player.name, pos)
                    messages.success(request, 'Lineup upgraded!')
                return redirect('team_details', league_id, team_id)
    else:
        form = UploadLineupForm(initial={'players': team_players, 'team': team,
                                         'modules': modules, 'day': day,
                                         'league': league})
        for n, player in enumerate(lineup.players.all()[11:], 1):
            form.fields['substitute_%s' % n].initial = player.code
        form.fields['holders'].initial = [p.code for p in
                                          lineup.players.all()[:11]]
    return render(request, 'fantalega/upload_lineup.html',
                  {'form': form, 'players': team_players, 'team': team,
                   'league': league})

@login_required
def lineup_details(request, league_id, team_id, day):
    league = get_object_or_404(League, pk=int(league_id))
    total = 0.0
    mod = 0.0
    team = get_object_or_404(Team, pk=int(team_id))
    if request.GET.get('back_to_team_details'):
        return redirect('team_details', league.id, team.id)
    offset = team.leagues.all()[0].offset
    fantaday = int(day) + int(offset)
    lineup = team.team_lineups.filter(day=int(day)).first()
    lineup_players = LineupsPlayers.get_sorted_lineup(lineup)
    holders = [l_p.player for l_p in lineup_players[:11]]
    substitutes = [s_p.player for s_p in lineup_players[11:]]
    d_votes = {code: (fv, v) for code, fv, v in
               [Evaluation.get_evaluations(day=(int(day) + offset),
                                           code=p.code, season=league.season)
                for p in holders]}
    if request.GET.get('modify lineup'):
        return redirect('lineup_edit', league.id, team.id, day)
    if request.GET.get('calculate'):
        try:
            handler = LineupHandler(lineup, int(day), league)
            total = handler.get_pts()
            mod = handler.mod
        except AttributeError:
            messages.error(request, 'No pts available: '
                                    'lineups or evaluations are missing, '
                                    'check in calendar...')
            total = ''

    context = {'team': team, 'holders': holders, 'substitutes': substitutes,
               'lineup': lineup, 'day': day, 'd_votes': d_votes, 'mod': mod,
               'fantaday': fantaday, 'total': total, 'league': league}
    return render(request, 'fantalega/lineup.html', context)

Sia la vista ‘upload_lineup’ che lineup_edit, fanno utilizzo dello stesso form:

fantalega/forms.py

...
from .models import Player
...
class UploadLineupForm(forms.Form):
    def __init__(self, *args, **kwargs):
        self.dict_values = kwargs.pop('initial')
        super(UploadLineupForm, self).__init__(*args, **kwargs)
        self.fields['module'] = forms.ChoiceField(
            label=u'module', choices=self.dict_values['modules'],
            widget=forms.Select())
        self.fields['day'] = forms.IntegerField(initial=self.dict_values['day'])
        self.fields['holders'] = forms.MultipleChoiceField(
            choices=self.dict_values['players'],
            widget=forms.CheckboxSelectMultiple())
        for n in range(1, 11):
            self.fields['substitute_%s' % n] = forms.ChoiceField(
                label=u'substitute %s' % n, choices=self.dict_values['players'],
                widget=forms.Select(), required=False)

    def check_holders(self):
            error = ''
            data = self.cleaned_data['holders']
            substitutes = [self.cleaned_data.get('substitute_%s' % n)
                           for n in range(1, 11)]
            if len(data) != 11:
                return "holder players number is wrong!"
            module = dict(self.fields['module'].choices)[
                int(self.cleaned_data['module'])]
            mod_defs, mod_mids, mod_forws = module
            goalkeepers = len()
            defenders = len()
            midfielders = len()
            forwarders = len()
            if goalkeepers > 1:
                return "To many goalkeepers!"
            if defenders != int(mod_defs):
                return "number of defenders doesn't match module!"
            if midfielders != int(mod_mids):
                return "number of midfielders doesn't match module!"
            if forwarders != int(mod_forws):
                return "number of forwarders doesn't match module!"
            for code in substitutes:
                player = Player.get_by_code(int(code),
                                            self.dict_values['league'].season)
                if code in data:
                    return "substitute %s is in holders!" % player.name
                if substitutes.count(code) > 1:
                    return "Duplicate substitute %s in list!" % player.name
            return error

Nota:
I campi (field) substitute, essendo 10, sono stati creati dinamicamente con un ciclo for.

che inseriremo negli import delle views
fantalega/views.py

...
from .forms import UploadLineupForm
...

Le templates coinvolte nell'operazione di salvataggio delle formazioni saranno:

fantalega/upload_lineup.html

{% extends 'fantalega/base.html' %}
{% load bootstrap3 %}

{% block content %}
    <b>Upload lineup for <font color="green">{{ team.name }}</font></b>
    <br><br>
    <form action="#" method="get">
    <input type="submit" class="btn"
           value="back to {{ team.name }} team" name="back_to_team_details">
    </form>

    <form method="POST" class="form">
		{% csrf_token %}
        <div id="container" style="width:100%;">
            <div id="left" style="float:left; width:50%;">
              {% bootstrap_field form.module %}
              {% bootstrap_field form.holders %}
            </div>
            <div id="right" style="float:right; width:50%;">
              {% bootstrap_field form.day %}
              {% bootstrap_field form.substitute_1 %}
              {% bootstrap_field form.substitute_2 %}
              {% bootstrap_field form.substitute_3 %}
              {% bootstrap_field form.substitute_4 %}
              {% bootstrap_field form.substitute_5 %}
              {% bootstrap_field form.substitute_6 %}
              {% bootstrap_field form.substitute_7 %}
              {% bootstrap_field form.substitute_8 %}
              {% bootstrap_field form.substitute_9 %}
              {% bootstrap_field form.substitute_10 %}
            </div>
        </div>

        <div>
            {% buttons %}
                <button type="submit" class="btn btn-primary">
                    {% bootstrap_icon "save" %} upload</button>
			{% endbuttons %}
        </div>
    </form>
{% endblock %}

Nota:
siccome il form per l'upload e la modifica della formazione è lo stesso,
unica sarà anche la template. Per visualizzare i dettagli della formazione invece:

fantalega/lineup.html

{% extends 'fantalega/base.html' %}
{% load app_filters %}

{% block content %}
	<h1>Lineup <font color="green">{{ team.name }}</font>
        day: <font color="red">{{ day }}</font><br></h1>
        <div id="container" style="width:100%;">
            <div id="left" style="float:left; width:30%;">
                <b><font color="orange">holders:</font></b><br>

                <table class="table table-striped">
                  <tr>
                      <th>code</th>
                      <th>player name</th>
                      <th>real team</th>
                      <th>role</th>
                      <th>fv</th>
                      <th>v</th>
                  </tr>
                      {% for player in holders %}
                  <tr>
                          <td>{{ player.code }}</td>
                          <td><a href="{% url 'player_details' player.id %}">
                              {{ player.name }}</a></td>
                          <td>{{ player.real_team }}</td>
                          <td>{{ player.role }}</td>
                          <td>{{ player|get_fvote:fantaday }}</td>
                          <td>{{ player|get_vote:fantaday }}</td>
                  </tr>
                      {% endfor %}
                </table>
                <form action="#" method="get">
                 <input type="submit" class="btn" value="modify lineup"
                        name="modify lineup">
                </form>
                <form action="#" method="get">
                 <input type="submit" class="btn" value="calculate"
                        name="calculate">
                </form>

                <b><font color="orange">pts:</font></b>
                    {{ total|pts_filter }}
                <br>
                <b><font color="orange">defense mod:</font></b>
                    {{ mod }}
                <br>
                <br>
                <form action="#" method="get">
                <input type="submit" class="btn"
                       value="back to {{ team.name }} team"
                       name="back_to_team_details">
                </form>
            </div>
            <div id="right" style="float:right; width:30%;">
                <b><font color="orange">substitutes:</font></b><br>

                <table class="table table-striped">
                  <tr>
                      <th>code</th>
                      <th>player name</th>
                      <th>real team</th>
                      <th>role</th>
                      <th>fv</th>
                      <th>v</th>
                  </tr>
                      {% for player in substitutes %}
                  <tr>
                          <td>{{ player.code }}</td>
                          <td><a href="{% url 'player_details' player.id %}">
                              {{ player.name }}</a></td>
                          <td>{{ player.real_team }}</td>
                          <td>{{ player.role }}</td>
                          <td>{{ player|get_fvote:fantaday }}</td>
                          <td>{{ player|get_vote:fantaday }}</td>
                  </tr>
                      {% endfor %}
                </table>
            </div>


        </div>

{% endblock %}

Per inserire una formazione, ogni User dovrà recarsi all'interno
della lega e cliccare sulla propria squadra.
Nella pagina relativa ai dettagli di squadra c'è un pulsante 'new lineup', che
va come sempre, abilitato nella view di competenza: 'team_details'.
Se vogliamo che le formazioni già inserite vengano visualizzate,
dobbiamo passare alla template, tramite il dizionario 'context', la lista
delle formazioni.

...
@login_required
def team_details(request, league_id, team_id):
    league = get_object_or_404(League, pk=int(league_id))
    team = get_object_or_404(Team, pk=int(team_id))
    lineups = Lineup.objects.filter(team=team, league=league).order_by('day')
    context = {'team': team, 'user': request.user, 'league': league,
	           'lineups': lineups}
    if request.GET.get('back_to_teams'):
        return redirect('league_details', league.id)
    if request.GET.get('new lineup'):
        return redirect('upload_lineup', league.id, team.id)
    return render(request, 'fantalega/team.html', context)

...

Ora cliccando sul bottone 'New Lineup', si verrà redirezionati al form
di inserimento. Scegliere il modulo, i titolari le riserve e salvare.
I dati inseriti verranno controllati:
- correttezza del modulo

module_error

- giocatori non duplicati

player_error

- deadline rispettata

E' possibile cliccare sulla singola formazione elencata per entrare nel
dettagli della stessa. Utilizzando un custom_filter, aggiungerlo al
file fantalega/templatetags/app_filters.py

...
@register.filter(name='get_vote')
def get_vote(player, day):
    evaluation = player.player_votes.filter(day=int(day)).first()
    if evaluation:
        return '%s' % float(evaluation.net_value)
    else:
        return '0.0'

All'interno della pagina formazione, ci sono due pulsanti oltre quello
di ritorno ai dettagli squadra: 'modify lineup' e 'calculate'.
Con il primo è possibile modificare la formazione, con il secondo,
si richiama uno script che esegue i calcoli.

Attenzione!!
Ricordarsi che la giornata da calcolare tiene presente dell'offset di lega.
Se si vogliono calcolare i punteggi della giornata di fantalega 1 ma l'offset di
lega è 2, vuol dire che nella realtà si è alla giornata 3, quindi è necessario
prima importare la valutazioni della giornata reale 3, poi effettuare i calcoli.

Siccome i voti già inseriti dovrebbero apparire nella template dei dettagli
di lega, aggiungiamo al dizionario passato alla template, anche le giornate
inserite:

def league_details(request, league_id):
    league = get_object_or_404(League, pk=int(league_id))
    league_teams = league.team_set.all()
    days = [d['day'] for d in
            Evaluation.objects.filter(
                season=league.season).order_by('day').values('day').distinct()]
    ...
    context = {'league': league, 'teams': league_teams,
               'days': days, 'user': request.user}
    ...

Il tasto 'calculate' è legato alla view 'lineup_details':

...
    if request.GET.get('calculate'):
        try:
            handler = LineupHandler(lineup, int(day), league)
            total = handler.get_pts()
            mod = handler.mod
        except AttributeError:
            messages.error(request, 'No pts available: '
                                    'lineups or evaluations are missing, '
                                    'check in calendar...')
            total = ''
...

LineupHandler viene importato nel file views.py

...
from fantalega.scripts.calc import LineupHandler, get_final, lineups_data
...

il file fantalega/scripts/calc.py conterrà quindi:

from fantalega.models import Evaluation


class BadInputError(Exception):
    pass


def convert_pts_to_goals(pts):
    """
    convert_pts_to_goals(pts) -> int

    Calculate number of goals by total pts, e.g.:
    convert_pts_to_goals(60) -> 0
    convert_pts_to_goals(66) -> 1
    convert_pts_to_goals(72) -> 2
    """
    if isinstance(pts, float):
        if pts < 60.0:
            return 0
        return (float(pts) - 60) // 6
    else:
        raise BadInputError("Need a Float as input, %s in input" % pts)


def get_final(pts_a, pts_b):
    """
    get_final(pts_a, pts_b) -> tuple

    Convert pts to goals between 2 teams, e.g.:
    get_final(66, 62) -> (1, 0)
    """
    if isinstance(pts_a, float) and isinstance(pts_b, float):
        goal_a = convert_pts_to_goals(pts_a)
        goal_b = convert_pts_to_goals(pts_b)
        if goal_a == goal_b:
            if pts_a - pts_b >= 4:  # +4 in the same level results in +1 goal
                goal_a += 1
            elif pts_b - pts_a >= 4:  # +4 in the same level for team_b
                goal_b += 1
        if pts_a < 60:  # og for team_a
            goal_b += 1
        if pts_b < 60:  # og for team_b
            goal_a += 1
        if pts_a - pts_b > 9.5:  # +10 in the same level results in +1 goal
            goal_a += 1
        elif pts_b - pts_a > 9.5:  # +10 for team_b
            goal_b += 1
        return int(goal_a), int(goal_b)
    else:
        raise BadInputError("Need a Float as input, %s and %s in input" %\
                            (pts_a, pts_b))


def lineups_data(goals_a, goals_b):
    """
    lineups_data(goals_a, goals_b) -> dict

    Convert to goals team data as: won, lost, matched, goals_made etc, i.e.:
    lineups_data(3, 2) -> {'hw': 1, 'vw': 0, 'hl': 0, ...}
    hw: home_won               vw: visit_won
    hm: home_matched           vm: visit_matched
    hl: home_lost              ...and so on
    hgm: home goals made
    hgc: home goals conceded

    :param goals_a: int goals of team A
    :param goals_b: int goals of team B
    """
    data = {'hw': 0, 'hm': 0, 'hl': 0, 'hgm': goals_a, 'hgc': goals_b,
            'vw': 0, 'vm': 0, 'vl': 0, 'vgm': goals_b, 'vgc': goals_a}
    if goals_a > goals_b:
        data['hw'] = 1
        data['hl'] = 0
        data['hm'] = 0
        data['vw'] = 0
        data['vl'] = 1
        data['vm'] = 0
    elif goals_a < goals_b:
        data['hw'] = 0
        data['hl'] = 1
        data['hm'] = 0
        data['vw'] = 1
        data['vl'] = 0
        data['vm'] = 0
    else:
        data['hw'] = 0
        data['hl'] = 0
        data['hm'] = 1
        data['vw'] = 0
        data['vl'] = 0
        data['vm'] = 1
    return data


class LineupHandler(object):
    def __init__(self, lineup, day, league):
        self.league = league
        self.day = day + league.offset
        self.mod = 0.0
        self.lineup = lineup
        self.holders = [p for p in self.lineup.players.all()[:11]]
        self.substitutes = [p for p in self.lineup.players.all()[11:]]
        self.not_evaluated = []
        self.available_by_role = []
        self.added_player = []
        self.new_list = []
        self.substitutions = 0
        self.candidate = None
        self.available = [p for p in self.substitutes if
                          Evaluation.objects.filter(player=p, day=self.day,
                                                    season=league.season
                                                    ).first().fanta_value > 0.0
                          and p.role != 'goalkeeper']

    def get_goalkeeper_substitute(self):
        gks = [p for p in self.substitutes if Evaluation.objects.filter(
               player=p, day=self.day, season=self.league.season
               ).first().fanta_value > 0.0
               and p.role == 'goalkeeper']
        if gks:
            return gks[0]
        else:
            return None

    def get_evaluation(self, player):
        evaluation = Evaluation.objects.filter(player=player,
                                               season=self.league.season,
                                               day=self.day).first()
        return evaluation.fanta_value

    def need_substitutions(self):
        evaluated = [p for p in self.holders if self.get_evaluation(p) > 0.0]
        return len(evaluated) != 11

    def get_same_role_substitute(self, player):
        self.available_by_role = [p for p in self.substitutes
                                  if p.role == player.role and
                                  Evaluation.objects.filter(
                                      season=self.league.season,
                                      player=p, day=self.day
                                  ).first().fanta_value > 0.0]
        self.candidate = self.available_by_role[0]
        return self.candidate

    def get_substitute(self, player):
        if player.role == 'goalkeeper':
            self.candidate = self.get_goalkeeper_substitute()
        else:
            # print self.available
            if self.available:
                return self.available[0]

    def is_same_role_available(self, player):
        self.available_by_role = [p for p in self.substitutes if
                                  p.role == player.role and
                                  Evaluation.objects.filter(
                                      season=self.league.season,
                                      player=p, day=self.day
                                  ).first().fanta_value > 0.0]
        return len(self.available_by_role) > 0

    def is_substitute_available(self):
        self.available = [p for p in self.substitutes if
                          Evaluation.objects.filter(
                              season=self.league.season,
                              player=p, day=self.day
                          ).first().fanta_value > 0.0 and
                          p.role != 'goalkeeper']
        return len(self.available) > 0

    def get_pts(self):
        if not self.need_substitutions():
            return self.def_mod(self.holders)
        else:
            self.not_evaluated = \
                [p for p in self.holders if Evaluation.objects.filter(
                    player=p, day=self.day, season=self.league.season
                ).first().fanta_value == 0.0]
        for player in self.not_evaluated:
            if self.is_same_role_available(player):
                self.candidate = self.get_same_role_substitute(player)
                self.substitutes.pop(self.substitutes.index(self.candidate))
            elif self.is_substitute_available():
                self.candidate = self.get_substitute(player)
                # check module
                if self.is_module_accepted(player):
                    self.substitutes.pop(self.substitutes.index(self.candidate))
                else:
                    print "\n[WARNING] module doesn't exist!"
                    self.candidate = None
            else:
                self.candidate = None

            if self.candidate and self.substitutions < 3:
                self.added_player.append(self.candidate)
                self.substitutions += 1

        self.new_list = [p for p in self.holders if Evaluation.objects.filter(
            player=p, day=self.day, season=self.league.season
            ).first().fanta_value > 0.0] +\
            self.added_player
        return self.def_mod(self.new_list)

    def is_module_accepted(self, player):
        d, m, f = 0, 0, 0
        lineup = self.holders[:]
        lineup.pop(lineup.index(player))
        lineup.append(self.candidate)
        for role in [p.role for p in lineup]:
            if role == 'defender':
                d += 1
            elif role == 'midfielder':
                m += 1
            elif role == 'forward':
                f += 1
            else:
                pass
        module = '%s%s%s' % (d, m, f)
        print "\n[INFO] module changes in %s" % module
        return module in ('343', '352', '442', '433', '451', '532', '541')

    def def_mod(self, player_list):
        total = sum([Evaluation.objects.filter(
            player=p, day=self.day, season=self.league.season
            ).first().fanta_value for p in player_list])
        defenders = [p for p in player_list if p.role == 'defender']
        goalkeepers = [p for p in player_list if p.role == 'goalkeeper']
        gk = goalkeepers[0] if goalkeepers else None
        vgk = Evaluation.objects.filter(player=gk, day=self.day,
                                        season=self.league.season
                                        ).first().net_value
        def_votes = [Evaluation.objects.filter(season=self.league.season,
            player=d, day=self.day).first().net_value for d in defenders]
        if len(defenders) >= 4 and gk:
            if vgk == 0.0:
                vgk = 6.0
            for v in def_votes:
                if v == 0.0:
                    def_votes[def_votes.index(v)] = 6.0
            values = sorted(def_votes, reverse=True)[:3] + [vgk]
            avg_def = sum(values)/4.0
            if avg_def == 6:
                self.mod = 1
            elif 6 < avg_def <= 6.25:
                self.mod = 2
            elif 6.25 < avg_def <= 6.5:
                self.mod = 3
            elif 6.5 < avg_def <= 6.75:
                self.mod = 4
            elif 6.75 < avg_def <= 7:
                self.mod = 5
            elif avg_def > 7:
                self.mod = 6
            return total + self.mod
        else:
            return total

Salvare ora gli avanzamenti su github:

git add --all
git commit -m "Lineup added"
git push -u origin master

articoli precedenti
0 - indice
1 - Virtualenv e Git
2 - Models: Season
3 - Admin: Login e Logout
4 - Models: League
5 - Models: Team
6 - Models: Match
7 - Models: Player
8 - Asta

articoli successivi
10 - Models: Trade
11 - Asta di riparazione
12 - Classifica

Categorie:Django Tag:
I commenti sono chiusi.