# Documentazione Django 5.2.8

# Scrivere la tua prima applicazione in Django, parte 2

Questo tutorial inizia dove è finito Tutorial 1. Avvieremo il database, creeremo il tuo primo modello e faremo una veloce introduzione al sito admin di Django, che viene generato automaticamente.

Dove trovare aiuto:

Se hai difficoltà a completare questo tutorial, per favore vai alla sezione Getting Help delle FAQ.

## Configurazione del database

Ora, apri `mysite/settings.py`. Si tratta di un modulo Python normale con le variabili a livello di modulo che rappresentano le impostazioni di Django.

Per impostazione predefinita, la configurazione `DATABASES` utilizza SQLite. Se sei nuovo nel mondo dei database o sei semplicemente interessato a provare Django, questa è l’opzione più semplice. SQLite è incluso in Python, quindi non dovrai installare nient’altro per supportare il tuo database. Tuttavia, quando avvierai il tuo primo progetto reale, potresti voler utilizzare un database più scalabile come PostgreSQL, per evitare problemi futuri legati al cambio di database.

Se desideri usare un altro database, guarda :ref:` dettagli per personalizzare e far funzionare il tuo database <database-installation>`.

Mentre stai modificando `mysite/settings.py`, imposta `TIME_ZONE` sul tuo fuso orario.

Notate anche il `INSTALLED_APPS` setting in cima al file. Questo contiene i nomi di tutte le applicazioni che sono attivate in questa instanza di Django. L’app può essere utilizzata in più progetti, inoltre puoi creare un python package e distribuirlo per essere utilizzato in altri progetti.

Per impostazione predefinita `INSTALLED_APPS` contiene le seguenti app, tutte fornite con Django:

- `django.contrib.admin` – Il admin site. Lo userai a breve.

- `django.contrib.auth` – Un sistema di autenticazione.

- `django.contrib.contenttypes` – Un framework per i tipi di contenuto.

- `django.contrib.sessions` – Un framework di sessione.

- `django.contrib.messages` – Un framework di messaggistica.

- `django.contrib.staticfiles` – Un framework per la gestione dei file statici.

Queste applicazioni sono incluse di default come convenienza per l’uso comune.

Alcune di queste applicazioni utilizzano almeno una tabella nel database, quindi dobbiamo creare le tabelle nel database prima di poterle utilizzare. Per farlo, esegui il seguente comando:

/ 

    $ python manage.py migrate

    ...\> py manage.py migrate

Il comando `migrate` controlla le impostazioni di `INSTALLED_APPS` e crea tutte le tabelle del database che sono necessarie in accordo con le impostazioni di database nel tuo file `mysite/settings.py` e le migrazioni del database fornite con l’applicazione (ne parleremo dopo). Vedrai un messaggio per ogni migrazione che applica. Se sei interessato, lancia il client database dalla linea di comando e scrivi `\dt` (PostgreSQL), `SHOW TABLES;` (MariaDB, MySQL), `.tables` (SQLite) o `SELECT TABLE_NAME FROM USER_TABLES;` (Oracle) per mostrare le tabelle che Django ha creato.

Per i minimalisti

Come abbiamo detto sopra, le applicazioni predefinite sono incluse per il caso d’uso comune, ma non tutti ne hanno bisogno. Se non hai bisogno di nessuno o di tutti, sentiti libero di commentare o eliminare le righe appropriate da `INSTALLED_APPS` prima di eseguire `migrate`. Il comando `migrate` eseguirà solo le migrazioni per le app in `INSTALLED_APPS`.

## Creazione dei modelli

Ora definiremo i tuoi modelli – essenzialmente, la struttura del tuo database, con metadati aggiuntivi.

Filosofia

Un modello è la sorgente di informazione singola e definitiva sui tuoi dati. Contiene i campi essenziali ed i comportamenti dei dati che stai salvando. Django segue il DRY Principle. La finalità è quella di definire il tuo data model in un unico posto e derivare automaticamente altre cose da quello.

Ciò include le migrazioni: a differenza di Ruby On Rails, ad esempio, le migrazioni sono interamente derivate dal file dei modelli e sono essenzialmente una cronologia che Django può eseguire per aggiornare lo schema del database in modo che corrisponda ai modelli attuali.

Nella nostra app sondaggio, creeremo due modelli: `Question` e `Choice`. Una `Question` ha una domanda e una data di pubblicazione. Una `Choice` ha due campi: il testo della scelta e il conteggio dei voti. Ogni `Choice` è associato ad una `Question`.

Questi concetti sono rappresentati da classi Python. Modifica il file `polls / models.py` in questo modo:

`polls/models.py`

    from django.db import models

    class Question(models.Model):
        question_text = models.CharField(max_length=200)
        pub_date = models.DateTimeField("date published")

    class Choice(models.Model):
        question = models.ForeignKey(Question, on_delete=models.CASCADE)
        choice_text = models.CharField(max_length=200)
        votes = models.IntegerField(default=0)

Qui, ogni modello è rappresentato da una classe che è sottoclasse di `django.db.models.Model`. Ogni modello ha un certo numero di variabili di classe, ciascuna delle quali rappresenta un campo del database.

Ogni campo è rappresentato da un’istanza della classe `Field` – e.g., `CharField` per i campi carattere e `DateTimeField` per le date. Questo dice a Django che tipo di dati contiene ogni campo.

Il nome di ogni istanza `Field` (e.g. `question_text` o `pub_date`) è il nome del campo in formato machine-friendly. Userai questo valore nel tuo codice Python e il tuo database lo userà come nome della colonna.

Puoi passare un primo argomento posizionale opzionale alla classe `Field` per indicare un nome human-readable. Questo è usato in un paio di parti introspettive di Django e torna utile come documentazione. Se questo argomento non è fornito, Django userà il nome machine-readable. In questo esempio, abbiamo definite un nome human-readable solo per `Question.pub_date`. Per tutti gli altri campi in questo modello, il nome machine-readable di ogni campo sarà sufficiente come nome human-readable.

Alcune classi `Field` hanno argomenti obbligatori. `CharField`, per esempio, richiede che tu gli dia una `max_length`. Ciò non viene usato solo nello schema del database ma nella validazione, come vedremo presto.

Un `Field` può avere anche diversi argomenti opzionali; in questo caso, abbiamo impostato il valore `default` a 0.

Infine, nota che è stata definita una relazione usando `ForeignKey`. Quello dice a Django che ciascuna `Choice` è collegata ad una singola `Question`. Django supporta tutte le relazioni comuni dei database: many-to-one, many-to-many, and one-to-one.

## Attivazione dei modelli

Questo piccolo codice del modello fornisce a Django molte informazioni. Con esso, Django è in grado di:

- Creare uno schema di database (istruzione `CREATE TABLE`) per questa app.

- Creare un’API Python di accesso al database per accedere agli oggetti `Question` e `Choice`.

Ma prima dobbiamo dire al nostro progetto che l’app `polls` è installata.

Filosofia

Le app Django sono «collegabili»: puoi usare una app in più progetti e puoi distribuire le app perchè non sono legate ad una specifica installazione di Django.

Per includere l’app nel nostro progetto, dobbiamo aggiungere un riferimento alla sua classe di configurazione nell’impostazione `INSTALLED_APPS`. La classe `PollsConfig` è nel file `polls/apps.py`, quindi il suo percorso separato da punti è `'polls.apps.PollsConfig'`. Modifica il file `mysite/settings.py` e aggiungi quel percorso separato da punti all’impostazione `INSTALLED_APPS` setting. Sarà simile a questo:

`mysite/settings.py`

    INSTALLED_APPS = [
        "polls.apps.PollsConfig",
        "django.contrib.admin",
        "django.contrib.auth",
        "django.contrib.contenttypes",
        "django.contrib.sessions",
        "django.contrib.messages",
        "django.contrib.staticfiles",
    ]

Adesso Django sa che deve includere l’app `polls` . Lanciamo un altro comando:

/ 

    $ python manage.py makemigrations polls

    ...\> py manage.py makemigrations polls

Dovresti vedere qualcosa di simile a:

    Migrations for 'polls':
      polls/migrations/0001_initial.py
        + Create model Question
        + Create model Choice

Eseguendo `makemigrations`, stai dicendo a Django che hai apportato alcune modifiche ai tuoi modelli (in questo caso, ne hai aggiunti di nuovi) e che desideri che le modifiche vengano memorizzate come migrazione.

Le migrazioni sono il modo in cui Django memorizza i cambiamenti ai tuoi modelli (e quindi allo schema del tuo database) - sono file sul disco. Puoi leggere la migrazione del tuo nuovo modello se vuoi, all’interno del file `polls/migrations/0001_initial.py`. Non preoccuparti, non devi leggerle ogni volta che Django ne crea una, ma sono progettate per essere modificabili dagli sviluppatori nel caso tu voglia ritoccare il modo in cui Django modifica le cose.

C’è un comando che eseguirà le migrazioni per te e gestirà automaticamente lo schema del tuo database - che si chiama `migrate`, e ci arriveremo tra un attimo - ma prima, vediamo quale SQL eseguirà la migrazione. Il comando `sqlmigrate` accetta i nomi delle migrazioni e restituisce il loro SQL:

/ 

    $ python manage.py sqlmigrate polls 0001

    ...\> py manage.py sqlmigrate polls 0001

Dovresti vedere qualcosa di simile al seguente (è stato riformattato per leggibilità):

    BEGIN;
    --
    -- Create model Question
    --
    CREATE TABLE "polls_question" (
        "id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
        "question_text" varchar(200) NOT NULL,
        "pub_date" timestamp with time zone NOT NULL
    );
    --
    -- Create model Choice
    --
    CREATE TABLE "polls_choice" (
        "id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
        "choice_text" varchar(200) NOT NULL,
        "votes" integer NOT NULL,
        "question_id" bigint NOT NULL
    );
    ALTER TABLE "polls_choice"
      ADD CONSTRAINT "polls_choice_question_id_c5b4b260_fk_polls_question_id"
        FOREIGN KEY ("question_id")
        REFERENCES "polls_question" ("id")
        DEFERRABLE INITIALLY DEFERRED;
    CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id");

    COMMIT;

Nota bene:

- L’output esatto varierà a seconda del database in uso. L’esempio sopra è generato per PostgreSQL.

- I nomi delle tabelle vengono generati automaticamente combinando il nome dell’app (`polls`) e il nome minuscolo del modello – `question` and `choice`. (Puoi cambiare questo comportamento.)

- Le chiavi primarie (ID) vengono aggiunte automaticamente. (Puoi modificare questo comportamento.)

- Per convenzione, Django aggiunge `"_id"` al nome del campo della chiave esterna. (Sì, puoi modificare anche questo.)

- La relazione di chiave esterna è resa esplicita da un vincolo `FOREIGN KEY`. Non preoccuparti per le parti `DEFERRABLE`; sta dicendo a PostgreSQL di non applicare la chiave esterna fino alla fine della transazione.

- È personalizzato in funzione del database che stai utilizzando, quindi i tipi dei campi specifici per database quali `auto_increment` (MySQL), `bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY` (PostgreSQL), o `integer primary key autoincrement` (SQLite) sono gestiti automaticamente. Lo stesso vale per gli apici dei nomi di campi — ad esempio usando i doppi apici o gli apici singoli.

- Il comando `sqlmigrate` non esegue effettivamente la migrazione sul tuo database - invece, la mostra sullo schermo in modo che tu possa vedere quale SQL è ritenuto necessario da Django. È utile per controllare cosa farà Django o se hai amministratori di database che richiedono script SQL per le modifiche.

Se sei interessato, puoi anche eseguire `python manage.py check`; che verifica eventuali problemi nel progetto senza effettuare migrazioni o toccare il database.

Ora, esegui: djadmin:migrate di nuovo per creare quelle tabelle nel tuo database:

/ 

    $ python manage.py migrate
    Operations to perform:
      Apply all migrations: admin, auth, contenttypes, polls, sessions
    Running migrations:
      Rendering model states... DONE
      Applying polls.0001_initial... OK

    ...\> py manage.py migrate
    Operations to perform:
      Apply all migrations: admin, auth, contenttypes, polls, sessions
    Running migrations:
      Rendering model states... DONE
      Applying polls.0001_initial... OK

Il comando `migrate` prende tutte le migrazioni che non sono state applicate (Django tiene traccia di quali sono applicate usando una tabella speciale nel tuo database chiamata `django_migrations`) e le esegue sul tuo database - essenzialmente, sincronizzando le modifiche apportate ai modelli con lo schema nel database.

Le migrazioni sono molto potenti e ti consentono di modificare i tuoi modelli nel tempo, mentre sviluppi il tuo progetto, senza la necessità di eliminare il tuo database o tabelle e crearne di nuove - è specializzato nell’aggiornamento del tuo database in tempo reale, senza perdere dati. Li tratteremo in modo più approfondito in una parte successiva del tutorial, ma per ora, ricorda la procedura in tre passaggi per apportare modifiche al modello:

- Modifica i tuoi modelli (in `models.py`).

- Eseguire: djadmin:python manage.py makemigrations per creare le migrazioni per le modifiche fatte

- Eseguire: djadmin:python manage.py migrate <migrate> per applicare le modifiche al database.

Il motivo per cui esistono comandi separati per eseguire e applicare le migrazioni è perché invierai le migrazioni al tuo sistema di controllo della versione e le spedirai con la tua app; non solo semplificano lo sviluppo, ma sono anche utilizzabili da altri sviluppatori e in produzione.

Leggi documentazione di django-admin per le informazioni complete su cosa può fare l’utility `manage.py`.

## Giocare con le API

Ora, andiamo nella shell interattiva di Python e giochiamo con l’API inclusa che Django ti offre. Per richiamare la shell Python, usa questo comando:

/ 

    $ python manage.py shell

    ...\> py manage.py shell

We’re using this instead of simply typing «python», because `manage.py` sets the `DJANGO_SETTINGS_MODULE` environment variable, which gives Django the Python import path to your `mysite/settings.py` file. By default, the `shell` command automatically imports the models from your `INSTALLED_APPS`.

Una volta che sei nella shell, esplora le database API:

    # No questions are in the system yet.
    >>> Question.objects.all()
    <QuerySet []>

    # Create a new Question.
    # Support for time zones is enabled in the default settings file, so
    # Django expects a datetime with tzinfo for pub_date. Use timezone.now()
    # instead of datetime.datetime.now() and it will do the right thing.
    >>> from django.utils import timezone
    >>> q = Question(question_text="What's new?", pub_date=timezone.now())

    # Save the object into the database. You have to call save() explicitly.
    >>> q.save()

    # Now it has an ID.
    >>> q.id
    1

    # Access model field values via Python attributes.
    >>> q.question_text
    "What's new?"
    >>> q.pub_date
    datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=datetime.timezone.utc)

    # Change values by changing the attributes, then calling save().
    >>> q.question_text = "What's up?"
    >>> q.save()

    # objects.all() displays all the questions in the database.
    >>> Question.objects.all()
    <QuerySet [<Question: Question object (1)>]>

Aspetta un attimo. `<Question: Question object (1)>` non è una rappresentazione utile di questo oggetto. Mettiamolo a posto modificando il modello `Question` (nel file `polls/models.py`) ed aggiungendo un metodo `__str__()` sia a `Question` che a `Choice`:

`polls/models.py`

    from django.db import models

    class Question(models.Model):
        # ...
        def __str__(self):
            return self.question_text

    class Choice(models.Model):
        # ...
        def __str__(self):
            return self.choice_text

È importante aggiungere il metodo `__str__()` ai tuoi modelli, non solo per tua convenienza quando hai a che fare con il prompt interattivo ma anche perché le rappresentazioni degli oggetti sono utilizzate nell’admin auto-generato di Django.

Aggiungiamo anche un metodo personalizzato a questo modello:

`polls/models.py`

    import datetime

    from django.db import models
    from django.utils import timezone

    class Question(models.Model):
        # ...
        def was_published_recently(self):
            return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

Nota l’aggiunta di `import datetime` e `from django.utils import timezone` per fare rispettivamente riferimento al modulo standard `datetime` ed alle utility di Django relative alle time-zone in `django.utils.timezone`. Se non hai familiarità con la gestione delle time zone in Python, puoi saperne di più consultando la documentazione di supporto per le time zone.

Save these changes and start a new Python interactive shell. (If a three-chevron prompt (>>>) indicates you are still in the shell, you need to exit first using `exit()`). Run `python manage.py shell` again to reload the models.

    # Make sure our __str__() addition worked.
    >>> Question.objects.all()
    <QuerySet [<Question: What's up?>]>

    # Django provides a rich database lookup API that's entirely driven by
    # keyword arguments.
    >>> Question.objects.filter(id=1)
    <QuerySet [<Question: What's up?>]>
    >>> Question.objects.filter(question_text__startswith="What")
    <QuerySet [<Question: What's up?>]>

    # Get the question that was published this year.
    >>> from django.utils import timezone
    >>> current_year = timezone.now().year
    >>> Question.objects.get(pub_date__year=current_year)
    <Question: What's up?>

    # Request an ID that doesn't exist, this will raise an exception.
    >>> Question.objects.get(id=2)
    Traceback (most recent call last):
        ...
    DoesNotExist: Question matching query does not exist.

    # Lookup by a primary key is the most common case, so Django provides a
    # shortcut for primary-key exact lookups.
    # The following is identical to Question.objects.get(id=1).
    >>> Question.objects.get(pk=1)
    <Question: What's up?>

    # Make sure our custom method worked.
    >>> q = Question.objects.get(pk=1)
    >>> q.was_published_recently()
    True

    # Give the Question a couple of Choices. The create call constructs a new
    # Choice object, does the INSERT statement, adds the choice to the set
    # of available choices and returns the new Choice object. Django creates
    # a set (defined as "choice_set") to hold the "other side" of a ForeignKey
    # relation (e.g. a question's choice) which can be accessed via the API.
    >>> q = Question.objects.get(pk=1)

    # Display any choices from the related object set -- none so far.
    >>> q.choice_set.all()
    <QuerySet []>

    # Create three choices.
    >>> q.choice_set.create(choice_text="Not much", votes=0)
    <Choice: Not much>
    >>> q.choice_set.create(choice_text="The sky", votes=0)
    <Choice: The sky>
    >>> c = q.choice_set.create(choice_text="Just hacking again", votes=0)

    # Choice objects have API access to their related Question objects.
    >>> c.question
    <Question: What's up?>

    # And vice versa: Question objects get access to Choice objects.
    >>> q.choice_set.all()
    <QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
    >>> q.choice_set.count()
    3

    # The API automatically follows relationships as far as you need.
    # Use double underscores to separate relationships.
    # This works as many levels deep as you want; there's no limit.
    # Find all Choices for any question whose pub_date is in this year
    # (reusing the 'current_year' variable we created above).
    >>> Choice.objects.filter(question__pub_date__year=current_year)
    <QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>

    # Let's delete one of the choices. Use delete() for that.
    >>> c = q.choice_set.filter(choice_text__startswith="Just hacking")
    >>> c.delete()

Per avere più informazioni sulle relazioni dei modelli, vedi Accesso agli oggetti collegati. Per saperne di più su come usare il doppio underscore per fare field lookup con le API, vedi Field lookups. Per tutti i dettagli sulle API del database, vedi la nostra Database API reference.

## Presentazione dell’Amministrazione di Django

Filosofia

Generare un sito di amministrazione affinchè il tuo staff o i tuoi clienti possano aggiungere, cambiare e cancellare contenuti è un lavoro noioso e che non richiede molta creatività. Per questa ragione, Django automatizza interamente la creazione delle interfacce di amministrazione per i modelli.

Django è stato scritto in un ambiente di redazione, con una netta separazione tra gli «editori di contenuti» e il sito «pubblico». I gestori del sito utilizzano il sistema per aggiungere notizie, eventi, risultati sportivi, ecc. e il contenuto viene visualizzato sul sito pubblico. Django risolve il problema della creazione di un’interfaccia unificata per gli amministratori del sito per modificare i contenuti.

L’amministratore non è concepito per essere utilizzato dai visitatori del sito. È per coloro che gestiscono il sito.

### Creazione di un utente amministratore

Per prima cosa dobbiamo creare un utente che possa accedere al sito di amministrazione. Esegui il seguente comando:

/ 

    $ python manage.py createsuperuser

    ...\> py manage.py createsuperuser

Inserisci lo username e premi enter.

    Username: admin

Ti verrà quindi chiesto di inserire l’indirizzo email desiderato:

    Email address: admin@example.com

Il passaggio finale è inserire la tua password. Ti verrà chiesto di inserire la tua password due volte, la seconda come conferma della prima.

    Password: **********
    Password (again): *********
    Superuser created successfully.

### Avvia il server di sviluppo

Il sito di amministrazione di Django è attivato di default. Avviamo il server di sviluppo ed esploriamolo.

Se il server non è in esecuzione, avvialo con:

/ 

    $ python manage.py runserver

    ...\> py manage.py runserver

Ora, apri un browser web e vai su «/admin/» nel tuo dominio locale – per es. http://127.0.0.1:8000/admin/. Dovresti vedere la schermata di login dell’amministrazione:

Poiché translation è attivato di default, se imposti `LANGUAGE_CODE`, la schermata di login verrà visualizzata nella lingua indicata (se Django ha traduzioni appropriate).

### Accedi al sito di amministrazione

Ora prova ad accedere con l’account superutente che hai creato nel passaggio precedente. Dovresti vedere la pagina principale di Django admin:

Dovresti vedere alcuni tipi di contenuto modificabile: gruppi e utenti. Sono forniti da `django.contrib.auth`, il framework di autenticazione fornito da Django.

### Rendi l’applicazione Sondaggi modificabile nell’amministrazione

Ma dov’è la nostra app per i sondaggi? Non viene visualizzato nella pagina principale dell’amministratore.

Solo un’altra cosa da fare: dobbiamo dire all’admin che gli oggetti `Question` hanno un’interfaccia di amministrazione. Per fare ciò, apri il file `polls/admin.py` e modificalo in questo modo:

`polls/admin.py`

    from django.contrib import admin

    from .models import Question

    admin.site.register(Question)

### Esplora le funzionalità disponibili nell’amministrazione

Ora che abbiamo registrato `Question`, Django sa che dovrebbe essere visualizzato nell’indice dell’amministratore:

Fare clic su «Questions». Ora sei nella pagina «elenco modifiche» per le domande. Questa pagina mostra tutte le domande nel database e ti permette di sceglierne una per cambiarla. C’è la domanda «»What’s up?» che abbiamo creato in precedenza:

Fai clic sulla domanda «What’s up?» per modificarla:

Cose da notare qui:

- Il form viene generato automaticamente dal modello `Question`.

- I diversi tipi di campo del modello (`DateTimeField`, `CharField`) corrispondono al widget di input HTML appropriato. Ogni tipo di campo sa come mostrarsi nell’amministratore di Django.

- Ogni `DateTimeField` include delle scorciatoie JavaScript. Le date ricevono una scorciatoia «Oggi» e un popup del calendario, mentre le ore ottengono una scorciatoia «Adesso» e un comodo popup che elenca gli orari comunemente inseriti.

La parte inferiore della pagina offre un paio di opzioni:

- Salva – Salva le modifiche e rimanda alla pagina dell’elenco delle modifiche per questo tipo di oggetto.

- Salva e continua a modificare – Salva le modifiche e ricarica la pagina di amministrazione per questo oggetto.

- Salva e aggiungi un altro – Salva le modifiche e carica un nuovo modulo vuoto per questo tipo di oggetto.

- Elimina – Mostra una pagina di conferma dell’eliminazione.

Se il valore di «Data di pubblicazione» non corrisponde all’ora in cui hai creato la domanda in Tutorial 1, probabilmente significa che hai dimenticato di impostare il valore corretto per l’impostazione `TIME_ZONE`. Modificalo, ricarica la pagina e verifica che appaia il valore corretto.

Modificare la «Data di pubblicazione» facendo clic sui collegamenti «Oggi» e «Adesso». Quindi fai clic su «Salva e continua le modifiche». Quindi fai clic su «Cronologia» in alto a destra. Vedrai una pagina che elenca tutte le modifiche apportate a questo oggetto tramite l’amministratore Django, con il timestamp e lo username della persona che ha apportato la modifica:

Quando sei a tuo agio con l’API dei modelli e hai familiarizzato con il sito di amministrazione, leggi la parte 3 di questo tutorial per sapere come aggiungere più views alla nostra app per i sondaggi.