djangofantalega: model Team
5 – Models: Team
Creare il terzo Model dell’ applicazione: Team
Una Lega (League) avrà più squadre (Team), ma una squadra potrà
prendere parte a più leghe (es. Lega e Champions), pertanto
trattasi di relazione many-to-many tra League e Team.
La relazione ManytoMany è rappresentata da una AssociationTable
LeaguesTeams.
Aggiungere nel file fantalega/models.py il model Team:
... from django.contrib.auth.models import User ... class Team(models.Model): name = models.CharField(max_length=32) budget = models.IntegerField() max_trades = models.IntegerField() user = models.OneToOneField(User, null=True, related_name='team') leagues = models.ManyToManyField(League, through='LeaguesTeams') def __unicode__(self): return self.name # M2M secondary Association object class LeaguesTeams(models.Model): league = models.ForeignKey(League, on_delete=models.CASCADE) team = models.ForeignKey(Team, on_delete=models.CASCADE) class Meta: verbose_name_plural = 'League-Team Associations'
Nota:
la relazione m2m si appoggerà ad una Association Table
dove sarà possibile in futuro, aggiungere comodi attributi.
Molto importante è anche la relazione One-to-One con User.
Un utente registrato avrà a disposizione SOLO una squadra.
Aggiornare il database inserendo la nuova tabella:
(venv) >python manage.py makemigrations Migrations for 'fantalega': fantalega\migrations\0003_auto_20161109_1123.py: - Create model LeaguesTeams - Create model Team - Add field team to leaguesteams
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.0003_auto_20161109_1123... OK
Ora inserire qualche dato nel database con questo criterio:
prima creiamo gli users, al quale successivamente daremo i privilegi
di modifica della squadra e niente più.
(venv) >python manage.py shell >>> from django.contrib.auth.models import User, Permission >>> permission = Permission.objects.filter(name__icontains='change team').first() >>> permission <Permission: fantalega | team | Can change team> >>> for name in ('pippo', 'pluto', 'paperino', 'topolino', 'minnie', 'etabeta', 'clarabella'): ... u = User.objects.create_user(username=name, password=name) ... u.user_permissions.add(permission) ... u.save() >>> for user in User.objects.all(): ... print "{}, staff: {}, active: {}".format(user.username, user.is_staff, user.is_active) ... bancaldo, staff: True, active: True pippo, staff: False, active: True pluto, staff: False, active: True paperino, staff: False, active: True topolino, staff: False, active: True minnie, staff: False, active: True etabeta, staff: False, active: True clarabella, staff: False, active: True >>> permission = Permission.objects.filter(name__icontains='can change team').first() >>> permission.user_set.all() <QuerySet [<User: pippo>, <User: pluto>, <User: paperino>, <User: topolino>, <User: minnie>, <User: etabeta>, <User: clarabella>]> >>> bancaldo = User.objects.get(username__iexact='bancaldo') >>> bancaldo <User: bancaldo> >>> bancaldo.is_staff True >>> bancaldo.has_perm(permission) True >>> pippo = User.objects.get(username__iexact='pippo') >>> pippo.user_permissions.all() <QuerySet [<Permission: fantalega | team | Can change team>]> >>> pippo.has_perm("fantalega.change_team") True
Come si nota, ‘bancaldo’ (superuser) non appare nella lista degli users che hanno il permesso
‘Can change team’. In effetti bancaldo non ha nessun specifico permesso abilitato, poichè il parametro
is_staff settato a True durante la creazione dello superuser, li ha abilitati tutti di default.
Queste cose sono tutte consultabili da Admin, alla voce Utenti.
Creare le squadre:
(venv) >python manage.py shell >>> from django.contrib.auth.models import User, Permission >>> from fantalega.models import League, Team >>> league = League.objects.filter(name__icontains='lega').first() >>> cup = League.objects.filter(name__icontains='champ').first() >>> for user in User.objects.all(): ... t = Team.objects.create(name='%s_team' % user.username, budget=league.budget, max_trades=league.max_trades, ... user=user) ... LeaguesTeams.objects.create(team=t, league=league) ... LeaguesTeams.objects.create(team=t, league=cup) ... >>> league.team_set.all() <QuerySet [<Team: bancaldo_team>, <Team: pippo_team>, <Team: pluto_team>, ... >>> cup.team_set.all() <QuerySet [<Team: bancaldo_team>, <Team: pippo_team>, <Team: pluto_team>, ... >>> t.leagues.all() <QuerySet [<League: lega 2016-2017>, <League: Champions 2016-2017>]>
Sistemare l’interfaccia di admin per il model Team:
file fantalega/admin.py:
# noinspection PyUnresolvedReferences from django.contrib import admin from .models import Season, League, LeaguesTeams, Team # Register your models here. class LeaguesInline(admin.TabularInline): model = Team.leagues.through extra = 0 classes = ('collapse',) verbose_name = 'associated league' verbose_name_plural = 'associated leagues' class TeamsInline(admin.TabularInline): model = Team.leagues.through extra = 0 classes = ('collapse',) verbose_name = 'associated teams' verbose_name_plural = 'associated teams' class LeagueAdmin(admin.ModelAdmin): inlines = [TeamsInline, ] fieldsets = [(None, {'fields': ['name', 'budget', 'max_trades', 'rounds', 'offset']}), ('season', {'fields': ['season']}), ('number of Players', {'fields': ['max_goalkeepers', 'max_defenders', 'max_midfielders', 'max_forwards']}), ] class TeamAdmin(admin.ModelAdmin): inlines = [LeaguesInline] list_display = ('name', 'budget', 'max_trades') ordering = ('-budget', ) class LeaguesTeamsAdmin(admin.ModelAdmin): list_display = ('league', 'team') list_filter = ('league', 'team') list_per_page = 20 admin.site.register(Season) admin.site.register(League, LeagueAdmin) admin.site.register(LeaguesTeams, LeaguesTeamsAdmin) admin.site.register(Team, TeamAdmin)
Qui viene introdotta la classe admin.TabularInline, che permette
di visualizzare in maniera tabulare determinati valori.
la tupla ‘classes’ permette di aggiungere il collapse di una
determinata sezione. Model è il modello di riferimento.
L’aspetto sarà il seguente:
Ora aggiungere gli urls inerenti Team nel file fantalega\urls.py:
... # team urls url(r'^leagues/(?P<league_id>[0-9]+)/teams/(?P<team_id>[0-9]+)/$', views.team_details, name='team_details'), ]
Aggiungere nel file fantalega\views.py le nuove viste ‘teams’ e ‘team_details’:
... from .models import Season, League, Team # Team added ... @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)) context = {'team': team, 'user': request.user, 'league': league} if request.GET.get('back_to_teams'): return redirect('league_details', league.id) return render(request, 'fantalega/team.html', context)
L’if presente nel model permette di essere redirezionati verso
l’url con nome ‘league_details’, quando nella template team.html
il pulsante con valore ‘back_to_teams’, viene premuto.
Ora che esistono anche le squadre (Team), facciamo in modo che siano
presenti anche nella template relativa alla stagione (League), aggiungendo
la lista delle squadre, al dizionario ‘context’ della vista ‘league_details’:
... from .models import Season, League, Team # Team added ... @login_required def league_details(request, league_id): league = get_object_or_404(League, pk=int(league_id)) league_teams = league.team_set.all() # list of teams context = {'league': league, 'teams': league_teams} return render(request, 'fantalega/league.html', context) ...
La template sarà quindi:
fantalega/team.html
{% extends 'fantalega/base.html' %} {% load bootstrap3 %} {% load app_filters %} {% block content %} <form action="#" method="get"> <input type="submit" class="btn" value="back to {{ league.name }} teams" name="back_to_teams"> </form> <table class="table table-striped" width="40%"> <tr> <th>budget</th> <th>trade remaining</th> </tr> <tr> <td>{{ team.budget }}</td> <td>{{ team.max_trades }}</td> </tr> </table> <div id="container" style="width:100%;"> <div id="left" style="float:left; width:50%;"> <b><font color="orange">Players:</font></b><br> <table class="table table-striped" width="40%"> <tr> <th>code</th> <th>player name</th> <th>real team</th> <th>cost</th> </tr> {% for player in team.player_set.all %} <tr> <td>{{ player.code }}</td> <td><a href="{% url 'player_details' player.id %}"> {{ player.name }}</a></td> <td>{{ player.real_team }}</td> <td>{{ player.cost }}</td> </tr> {% endfor %} </table> <form action="#" method="get"> <input type="submit" class="btn" value="sell players for repair session" name="sale"> </form> </div> <div id="right" style="float:right; width:50%;"> <b><font color="orange">Trade operations:</font></b><br> <table class="table table-striped" width="40%"> <tr> <th>IN/OUT</th> <th>player name</th> </tr> {% for trade in team.trade_set.all %} <tr> <td>{{ trade.direction }}</td> <td><a href="{% url 'player_details' trade.player.id %}"> {{ trade.player.name }}</a></td> </tr> {% endfor %} </table> {% if user.is_authenticated and user.team == team %} <form action="#" method="get"> <input type="submit" class="btn" value="new trade" name="new trade"> </form> <b><font color="orange">Team lineups:</font></b><br> {% for lineup in lineups %} <ul> <li><a href="{% url 'lineup_details' league.id team.id lineup.day %}">lineup day: {{ lineup.day }}</a>: {{ lineup.pts|pts_filter }}</li> </ul> {% endfor %} <form action="#" method="get"> <input type="submit" class="btn" value="new lineup" name="new lineup"> </form> {% endif %} </div> </div> {% endblock %}
In questa template si fa uso di un custom_filter. Nella fattispecie, quando saranno
disponibili le formazioni (Lineup), a seconda del punteggio effettuato dalla
formazione, il valore stesso sarà colorato diversamente.
Per creare un custom_filter, creare nella directory fantalega,
una sottodirectory templatetags, con all’interno un file vuoto __init__.py e
un file app_filters.py.
Il contenuto sarà:
# noinspection PyUnresolvedReferences from django import template from django.utils.safestring import mark_safe register = template.Library() @register.assignment_tag def get_bootstrap_alert_msg_css_name(tags): return 'danger' if tags == 'error' else tags @register.filter(name='pts_filter') def pts_filter(value): if value: if float(value) <= 60: color = 'e60000' elif 60 < float(value) <= 72: color = 'cc66ff' else: color = '009933' new_string = '<b><font color="#%s">%s</font></b>' % (color, value) return mark_safe(new_string) else: return value
Nella template i filters vanno caricati all’inizio con la voce:
{% load app_filters %}
mentre il filtro verrà chiamato con la sintassi ‘valore|filtro:
{{ lineup.pts|pts_filter }}
il valore lineups.pts viene passato come argomento alla pts_filter()
che ritorna lo stesso valore, corredato da una colorazione specifica.
E’ assolutamente necessario ritornare il valore con mark_safe.
Andando alla pagina http://127.0.0.1:8000/fantalega/leagues/ sarà possibile
cliccare sulla lega desiderata, entrare nel dettaglio della lega stessa e, se
create, entrare nel dettaglio di una delle squadre elencate.
Salvare gli avanzamenti su github:
git add --all
git commit -m "Team 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
articoli successivi
6 – Models: Match
7 – Models: Player
8 – Asta
9 – Models: Lineup
10 – Models: Trade
11 – Asta di riparazione
12 – Classifica
Commenti recenti