djangofantalega: model Player e model Evaluation
7 – Models: Player ed Evaluation
Creare i modelli Player ed Evaluation.
Per Evaluation si intendono i voti che settimanalmente vengono
pubblicati e con i quali si effettuano i conteggi delle squadre.
La fantalega in oggetto si basa sulla creazione di squadre tramite Asta
(Auction) pertanto un giocatore, potrà appartenere solo ad una squadra.
Per questo la relazione Team-Player sarà di tipo one-to-many.
Lo stesso Player avrà una relazione one-to-many con Evaluation.
Aggiungere nel file fantalega/models.py i models Player e Evaluation:
... from .models import Player, Evaluation ... class Player(models.Model): code = models.IntegerField() name = models.CharField(max_length=32) real_team = models.CharField(max_length=3) cost = models.IntegerField() auction_value = models.IntegerField() role = models.CharField(max_length=16) team = models.ForeignKey(Team, null=True) season = models.ForeignKey(Season, related_name='players') def __unicode__(self): return self.name @staticmethod def get_by_code(code, season): return Player.objects.filter(code=int(code), season=season).first() @staticmethod def code_to_role(code): if int(code) < 200: return 'goalkeeper' elif 200 < int(code) < 500: return 'defender' elif 500 < int(code) < 800: return 'midfielder' elif int(code) > 800: return 'forward' else: return 'unknown' class Evaluation(models.Model): season = models.ForeignKey(Season, related_name='evaluations') player = models.ForeignKey(Player, related_name='player_votes') day = models.IntegerField() net_value = models.FloatField() fanta_value = models.FloatField() cost = models.IntegerField() def __unicode__(self): return "[%s] %s" % (self.day, self.player.name) @staticmethod def get_evaluations(day, code, season): """get_evaluations(self, day, code, season) -> fanta_value, net_value code: Player.code day: lineup.day + league.offset season: season object """ player = Player.objects.filter(code=int(code), season=season).first() evaluation = Evaluation.objects.filter(day=day, player=player).first() if evaluation and player: return code, evaluation.fanta_value, evaluation.net_value else: return code, None, None @staticmethod def upload(path, day, season): # with open(path) as data: # for shell string-file-path upload with path as data: # for InMemoryUploadedFile object upload for record in data: # nnn|PLAYER_NAME|REAL_TEAM|x|y|n code, name, real_team, fv, v, cost = record.strip().split("|") player = Player.get_by_code(code, season) role = Player.code_to_role(code.strip()) if not player: player = Player(name=name, code=code, role=role, real_team=real_team, cost=cost, auction_value=0, season=season) print "[INFO] Creating %s %s" % (code, name) else: player.cost = cost player.real_team = real_team print "[INFO] Upgrading %s %s" % (code, name) player.save() # storing evaluation evaluation = Evaluation.objects.filter(day=day, season=season, player=player).first() if evaluation: evaluation.net_value = v evaluation.fanta_value = fv evaluation.cost = cost evaluation.save() print "[INFO] Upgrading values day: %s player %s [%s]" % ( day, player.name, season.name) else: Evaluation.objects.create(day=day, player=player, cost=cost, net_value=v, fanta_value=fv, season=season) print "[INFO] Creating values day: %s player %s [%s]" % ( day, player.name, season.name) print "[INFO] Evaluation uploading done!"
Tenendo traccia anche di stagioni precedenti, Evaluation avrà una relazione
many-to-one con Season. Stesso discorso per Player. Ogni stagione (Season)
avrà i suoi giocatori (Player) di riferimento quindi la relazione
Season-Player sarà di tipo one-to-many.
Aggiornare il database inserendo la nuova tabella.
(venv) >python manage.py makemigrations Migrations for 'fantalega': fantalega\migrations\0005_auto_20161110_1407.py: - Create model Evaluation - Create model Player - Add field player to evaluation - Add field season to evaluation
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.0005_auto_20161110_1407... OK
Sistemare l’interfaccia di admin per i model Player ed Evaluation:
file fantalega/admin.py:
# noinspection PyUnresolvedReferences ... from .models import Player, Evaluation # Register your models here. ... class PlayersInline(admin.TabularInline): model = Player extra = 0 classes = ('collapse',) ... class EvaluationAdmin(admin.ModelAdmin): list_display = ('day', 'player', 'fanta_value', 'net_value', 'cost') list_filter = ('day', 'player', 'season') list_per_page = 50 class PlayerAdmin(admin.ModelAdmin): ordering = ('code', ) list_display = ('code', 'name', 'real_team', 'cost') list_filter = ('season', 'role', 'team') list_per_page = 20 ... admin.site.register(Player, PlayerAdmin) admin.site.register(Evaluation, EvaluationAdmin)
La classe PlayersInline la facciamo apparire nell’interfaccia di
admin di Team, poichè è fondamentale poter vedere da quali giocatori
è composta la rosa della squadra, quindi, sempre in admin:
... class PlayersInline(admin.TabularInline): model = Player extra = 0 classes = ('collapse',) class TeamAdmin(admin.ModelAdmin): inlines = [LeaguesInline, PlayersInline] # TabularInLine added list_display = ('name', 'budget', 'max_trades') ordering = ('-budget', )
Ora aggiungere gli urls inerenti Player ed Evaluation nel file fantalega\urls.py:
... # players urls url(r'^players/$', views.players, name='players'), url(r'^players/(?P<player_id>[0-9]+)/$', views.player_details, name='player_details'), # votes urls url(r'^leagues/(?P<league_id>[0-9]+)/votes/(?P<day>[0-9]+)/$', views.vote, name='vote'), url(r'^leagues/(?P<league_id>[0-9]+)/upload$', views.upload_votes, name='upload_votes'), ]
Aggiungere nel file fantalega\views.py le nuove viste:
... from .models import Player, Evaluation ... @login_required def players(request): sorted_players = Player.objects.order_by('code') context = {'players': sorted_players} return render(request, 'fantalega/players.html', context) @login_required def player_details(request, player_id): player = Player.objects.get(id=int(player_id)) votes = player.player_votes.all() context = {'player': player, 'votes': votes} return render(request, 'fantalega/player.html', context) @login_required def vote(request, league_id, day): league = get_object_or_404(League, pk=int(league_id)) if request.GET.get('back_to_teams'): return redirect('league_details', league.id) votes = Evaluation.objects.filter(season=league.season, day=day).all() context = {'votes': votes, 'day': day, 'league': league} return render(request, 'fantalega/vote.html', context) @login_required def upload_votes(request, league_id): league = get_object_or_404(League, pk=int(league_id)) seasons = enumerate([season.name for season in Season.objects.all()]) if request.GET.get('back_to_teams'): return redirect('league_details', league.id) if request.method == "POST": form = UploadVotesForm(request.POST, request.FILES, initial={'seasons': seasons}) if form.is_valid(): day = form.cleaned_data['day'] dict_season = dict(form.fields['season'].choices) season = dict_season[int(form.cleaned_data['season'])] obj_season = get_object_or_404(Season, name=season) file_in = request.FILES['file_in'] Evaluation.upload(path=file_in, day=day, season=obj_season) messages.success(request, 'votes uploaded!') return redirect('league_details', league.id) else: form = UploadVotesForm(initial={'seasons': seasons}) return render(request, 'fantalega/upload_votes.html', {'form': form, 'league': league})
il form che permetterà l’upload dei voti e dei giocatori (fantalega/forms.py) sarà:
... class UploadVotesForm(forms.Form): def __init__(self, *args, **kwargs): self.dict_values = kwargs.pop('initial') super(UploadVotesForm, self).__init__(*args, **kwargs) self.fields['day'] = forms.IntegerField() self.fields['season'] = forms.ChoiceField(label=u'season', choices=self.dict_values['seasons'], widget=forms.Select(),) self.fields['file_in'] = forms.FileField()
e andrà importato nel file fantalega/views.py:
from .forms import UploadVotesForm ...
Ora le template legate alle views suddette.
templates/players.html
{% extends 'fantalega/base.html' %} {% block content %} <font color="green"><b>List of all players</b></font><br><br> {% if players %} <table class="table table-striped" width="100%"> <tr> <th>code</th> <th>name</th> <th>team</th> <th>fanta team</th> <th>season</th> </tr> <tr> {% for player in players %} <td>{{ player.code }}</td> <td><a href="{% url 'player_details' player.id %}"> {{ player.name }}</a></td> <td>{{ player.real_team }}</td> <td>{{ player.team.name }}</td> <td>{{ player.season }}</td> </tr> {% endfor %} </table> {% else %} <font color="red"><b>No players found.</b></font> {% endif %} {% endblock %}
templates/player.html
{% extends 'fantalega/base.html' %} {% load app_filters %} {% block content %} <h1><font color="green">{{ player.name }}</font></h1> <table class="table table-striped" width="100%"> <tr> <th>code</th> <th>real team</th> <th>role</th> <th>cost</th> <th>auction value</th> <th>season</th> </tr> <tr> <td>{{ player.code }}</td> <td>{{ player.real_team }}</td> <td>{{ player.role }}</td> <td>{{ player.cost }}</td> <td>{{ player.auction_value }}</td> <td>{{ player.season }}</td> </tr> </table> <br> <b><font color="orange">votes</font></b> <br> <table class="table table-striped" width="100%"> <tr> <th>day</th> <th>fanta value</th> <th>value</th> <th>cost</th> </tr> {% for vote in votes %} <tr> <td>{{ vote.day }}</td> <td>{{ vote.fanta_value }}</td> <td>{{ vote.net_value }}</td> <td>{{ vote.cost }}</td> </tr> {% endfor %} </table> <br> <b><font color="orange">presenze</font></b>: {{player|get_played:player.code}} <br> <b><font color="orange">fv avg</font></b>: {{player|get_avg:player.code}} {% endblock %}
templates/vote.html
{% extends 'fantalega/base.html' %} {% block content %} <font color="green"><b>{{ league.name }}</b></font>: list of evaluations for day <font color="purple"><b>{{ day }}</b></font><br><br> <form action="#" method="get"> <input type="submit" class="btn" value="back to {{ league.name }} teams" name="back_to_teams"> </form> <br> <table class="table table-striped" width="100%"> <tr> <th>code</th> <th>name</th> <th>team</th> <th>fanta value</th> <th>value</th> <th>cost</th> </tr> <tr> {% for vote in votes %} <td>{{ vote.player.code }}</td> <td><a href="{% url 'player_details' vote.player.id %}"> {{ vote.player.name }}</a></td> <td>{{ vote.player.real_team }}</td> <td>{{ vote.fanta_value }}</td> <td>{{ vote.net_value }} </td> <td>{{ vote.cost }}</td></tr> {% endfor %} </table> {% endblock %}
templates/upload_votes.html
{% extends 'fantalega/base.html' %} {% load bootstrap3 %} {% block content %} <h1>Upload votes for <font color="green">{{ league.name }}</font></h1><br> <form action="#" method="get"> <input type="submit" class="btn" value="back to {{ league.name }} teams" name="back_to_teams"> </form> <form enctype="multipart/form-data" method="POST" class="form"> {% csrf_token %} {% bootstrap_form form %} {% buttons %} <button type="submit" class="btn btn-primary"> {% bootstrap_icon "upload" %} Upload</button> {% endbuttons %} </form> {% endblock %}
Avviare il server e recarsi nella pagina relativa ai giocatori:
http://127.0.0.1:8000/fantalega/players/
Come si nota non ci sono ancora giocatori, pertanto vanno caricati.
Abilitare il pulsante ‘upload votes’ nella view league_details:
fantalega/views.py
@login_required def league_details(request, league_id): league = get_object_or_404(League, pk=int(league_id)) league_teams = league.team_set.all() if request.GET.get('calendar'): return redirect('calendar', league.id) if request.GET.get('matches'): return redirect('matches', league.id) if request.GET.get('upload votes'): return redirect('upload_votes', league.id) context = {'league': league, 'teams': league_teams, 'user': request.user} return render(request, 'fantalega/league.html', context)
I file dei voti sono i soliti MCCxx.txt e si dovranno trovare
nella directory fantalega/static
Nella template player.html si fa uso di alcuni custom filter, pertanto
aggiungerli al file fantalega/templatetags/app_filters.py
... from fantalega.models import Player, Evaluation ... @register.filter(name='get_played') def get_played(player, code): obj_player = Player.objects.filter(name=player, code=code).first() played = [e for e in Evaluation.objects.filter(player=obj_player).all() if e.fanta_value > 0.0 ] return len(played) @register.filter(name='get_avg') def get_avg(player, code): obj_player = Player.objects.filter(name=player, code=code).first() fanta_values = [e.fanta_value for e in Evaluation.objects.filter(player=obj_player).all() if e.fanta_value > 0.0 ] try: return sum(fanta_values)/len(fanta_values) except ZeroDivisionError: return 0.0
Siccome la pagina dei giocatori deve essere facilmente consultabile da ogni dove,
sarebbe bene aggiungerla nella template base.html (come navbar) in modo che venga
ereditata da tutte.
fantalega/templates/fantalega/base.html
... <div class="navbar-header"> <a class="navbar-brand" href="{% url 'seasons' %}">Seasons</a></div> <div class="navbar-header"> <a class="navbar-brand" href="{% url 'leagues' %}">Leagues</a></div> <div class="navbar-header"> <a class="navbar-brand" href="{% url 'players' %}">Players</a></div> ...
Il server è già avviato, recarsi all’interno della lega e
premere sul pulsante ‘upload votes’. Una volta terminato
l’upload dei dati, recarsi nella pagina http://127.0.0.1:8000/fantalega/players/
ed appariranno tutti i giocatori.
Su ognuno sarà possibile cliccare entrando nella pagina relativa al singolo
giocatore con tutti i dettagli.
Le Squadre e i giocatori ci sono, il prossimo step è quello di definire l’asta (Auction)
Salvare ora gli avanzamenti su github:
git add --all
git commit -m "Player and Evaluation 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
articoli successivi
8 – Asta
9 – Models: Lineup
10 – Models: Trade
11 – Asta di riparazione
12 – Classifica
Commenti recenti