Home > Django > djangofantalega: model Team

djangofantalega: model Team

14 Novembre 2016

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.

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.

users
singolo_utente

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:

admin_team

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.

team_details

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

Categorie:Django Tag:
I commenti sono chiusi.