---
title: "Scrivere la tua prima applicazione in Django, parte 4"
version: 3.2
locale: it
source: https://docs.djangoproject.com/it/3.2/intro/tutorial04/
canonical: https://djangodocs.dev/it/3.2/intro/tutorial04/
---
# Scrivere la tua prima applicazione in Django, parte 4

Questo tutorial inizia dove finiva [Tutorial 3](/it/3.2/intro/tutorial03/). Stiamo continuando l’applicazione Web-poll e ci concentreremo sul form processing e sulla riduzione del codice.

> **Dove trovare aiuto:**
>
> Se hai difficoltà a completare questo tutorial,  per favore vai alla sezione [Getting Help](/it/3.2/faq/help/) delle FAQ.

## Scrivere un modulo minimale

Aggiorniamo il nostro template per i dettagli del questionario («polls/detail.html») dall’ultimo tutorial, così che il template contenga un elemento HTML `<form>`:

*`polls/templates/polls/detail.html`*

```html+django
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
<fieldset>
    <legend><h1>{{ question.question_text }}</h1></legend>
    {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
    {% for choice in question.choice_set.all %}
        <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
        <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
    {% endfor %}
</fieldset>
<input type="submit" value="Vote">
</form>
```

Una rapida carrellata:

- Il template di cui sopra mostra un radio button per ogni scelta del sondaggio. Il `valore` di ogni radio button è l’ID associato alla scelta. Il `nome` di ogni radio button è `"choice"`. Questo significa che quando qualcuno seleziona uno dei radio button ed invia il form, manderà il dato `choice=#` in POST, dove # è l’ID della scelta selezionata. Questo è il concetto alla base dei form HTML.
- Impostiamo la `action` del form a `{% url 'polls:vote' question.id %}` ed impostiamo `method="post"`. Utilizzare `method="post"` (al contrario `method="get"`) è molto importante , perchè l’atto di inviare questo form cambierà i dati a lato server. Tutte le volte che crei un form che altera i dati lato server, usa `method="post"`. Questo suggerimento non è specifico per Django; è una buona pratica di sviluppo web in generale.
- `forloop.counter` indica quante volte il tag [`for`](/it/3.2/ref/templates/builtins/#std-templatetag-for) ha attraversato suo loop
- Siccome stiamo creando un form POST (che può avere l’effetto di modificare i dati), dobbiamo preoccuparci delle Cross Site Request Forgeries. Per fortuna, non ce ne dobbiamo preoccupare troppo, perchè Django ci offre un sistema che ci aiuta molto a proteggerci. In breve, tutti i form POST che sono indirizzati dalle url interne devono usare il tag [`{% csrf_token %}`](/it/3.2/ref/templates/builtins/#std-templatetag-csrf_token).

Adesso, creiamo una view Django che gestisce i dati in submit e ci fa qualcosa. Ricorda che nel [Tutorial 3](/it/3.2/intro/tutorial03/), abbiamo creato una URLconf per l’applicazione sondaggio che include questa linea:

*`polls/urls.py`*

```python
path('<int:question_id>/vote/', views.vote, name='vote'),
```

Abbiamo anche creato una implementazione dummy della funzione `vote()`. Creiamone una versione reali. Aggiungi quanto di seguito a `polls/views.py`:

*`polls/views.py`*

```python
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse

from .models import Choice, Question
# ...
def vote(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected_choice = question.choice_set.get(pk=request.POST['choice'])
    except (KeyError, Choice.DoesNotExist):
        # Redisplay the question voting form.
        return render(request, 'polls/detail.html', {
            'question': question,
            'error_message': "You didn't select a choice.",
        })
    else:
        selected_choice.votes += 1
        selected_choice.save()
        # Always return an HttpResponseRedirect after successfully dealing
        # with POST data. This prevents data from being posted twice if a
        # user hits the Back button.
        return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
```

Questo codice comprende alcuni aspetti non ancora trattati in questo tutorial:

- [`request.POST`](/it/3.2/ref/request-response/#django.http.HttpRequest.POST) è un oggetto simil-dizionario che ti lascia accedere ai dati in submit per nome di chiave. In questo caso, `request.POST['choice']` restituisce l’ID della scelta selezionata, come stringa. I valori [`request.POST`](/it/3.2/ref/request-response/#django.http.HttpRequest.POST) sono sempre stringhe.

  Nota che Django ti offre anche [`request.GET`](/it/3.2/ref/request-response/#django.http.HttpRequest.GET) per accedere ai dati in GET allo stesso modo – ma stiamo esplicitamente usando [`request.POST`](/it/3.2/ref/request-response/#django.http.HttpRequest.POST) nel nostro codice, per assicurarci che i dati vengano alterati solo con una chiamata POST.
- `request.POST['choice']` solleverà [`KeyError`](https://docs.python.org/3/library/exceptions.html#KeyError) se `choice` non è presente tra i dati in POST. Il codice sopra controlla [`KeyError`](https://docs.python.org/3/library/exceptions.html#KeyError) e mostra di nuovo il form della domanda con un messaggio di errore se `choice` non viene fornita.
- Dopo aver incrementato il conteggio delle scelte, il codice restituisce una [`HttpResponseRedirect`](/it/3.2/ref/request-response/#django.http.HttpResponseRedirect) piuttosto che una normale [`HttpResponse`](/it/3.2/ref/request-response/#django.http.HttpResponse). [`HttpResponseRedirect`](/it/3.2/ref/request-response/#django.http.HttpResponseRedirect) prende un solo argomento: la URL alla quale l’utente sarà redirezionato (vedi il punto seguente per sapere come costruiamo la URL in questo caso).

  Come il commento Python sopra fa notare, dovresti sempre restituire un [`HttpResponseRedirect`](/it/3.2/ref/request-response/#django.http.HttpResponseRedirect) dopo aver avuto a che fare con successo con dei dati in POST. Questo suggerimento non è specifico per Django; è una buona pratica per lo sviluppo Web in generale.
- In questo esempio stiamo usando la funzione [`reverse()`](/it/3.2/ref/urlresolvers/#django.urls.reverse) nel costruttore [`HttpResponseRedirect`](/it/3.2/ref/request-response/#django.http.HttpResponseRedirect). Questa funzione aiuta ad evitare di dover codificare la URL nella funzione view. E” dato il nome della view a cui vogliamo passare il controllo e la porzione della URL relativa alla variabile che punta alla URL. In questo caso, usando la URLconf che abbiamo impostato nel [Tutorial 3](/it/3.2/intro/tutorial03/), questa chiamata [`reverse()`](/it/3.2/ref/urlresolvers/#django.urls.reverse) restituirà una stringa come:

  ```
  '/polls/3/results/'
  ```

  dove il `3` è il valore di `question.id`. Questa URL redirezionata poi chiamerà la view `'results'` per mostrare la pagina finale.

Come menzionato in [Tutorial 3](/it/3.2/intro/tutorial03/), `request` è un oggetto [`HttpRequest`](/it/3.2/ref/request-response/#django.http.HttpRequest). Per saperne di più sugli oggetti [`HttpRequest`](/it/3.2/ref/request-response/#django.http.HttpRequest), vedi la [documentazione su request e response](/it/3.2/ref/request-response/).

Dopo che qualcuno ha votato una domanda, la vista `vote()` reindirizza alla pagina dei risultati per la domanda. Scriviamo quella vista:

*`polls/views.py`*

```python
from django.shortcuts import get_object_or_404, render

def results(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'polls/results.html', {'question': question})
```

Questa è praticamente la stessa view di `detail()` dal [Tutorial 3](/it/3.2/intro/tutorial03/). L’unica differenza è il nome di template. Metteremo a posto questa ridondanza più tardi.

Ora, crea un template `polls/results.html`  :

*`polls/templates/polls/results.html`*

```html+django
<h1>{{ question.question_text }}</h1>

<ul>
{% for choice in question.choice_set.all %}
    <li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
</ul>

<a href="{% url 'polls:detail' question.id %}">Vote again?</a>
```

Adesso, vai su `/polls/1/` nel browser e vota il sondaggio. Dovresti vedere la pagina dei risultati che si aggiorna ogni volta che voti. Se invii il form senza scegliere una risposta, dovresti vedere il messaggio di errore.

> **Note**
>
> Il codice per la view `vote()` ha un piccolo problema. Prende prende l’oggetto `selected_choice` dal db, poi li risalva nel database. Se due utenti del sito cercano di votare *esattamente* allo stesso momento, qualcosa potrebbe andare storto: lo stesso valore, diciamo 42, verrebbe ritirato per `votes`. Poi, per entrambi gli utenti verrebbe calcolato il valore 43 e salvato ma 44 sarebbe il valore giusto.
>
> Questa viene chiamata *race condition*. Se sei interessato, puoi leggere [Avoiding race conditions using F()](/it/3.2/ref/models/expressions/#avoiding-race-conditions-using-f) per sapere come risolvere questo problema.

## Usa viste generiche: meno codice è meglio

Le view `detail()` (dal [Tutorial 3](/it/3.2/intro/tutorial03/)) e `results()` sono molto brevi – e, come menzionato sopra, ridondanti. La view `index()`, che mostra una lista di sondaggi, è simile.

Queste view rappresentano un caso comune di sviluppo Web: prendere dati dal database secondo un parametro passato nella URL, caricare un template e restituire il template. Dal momento che è così comune, Django offre una scorciatoia, chiamato sistema delle «view generiche».

Le view generiche fanno astrazione di pattern comuni al punto che non hai nemmeno più bisogno di codice Python per scrivere una app.

Convertiamo la nostra app dei sondaggi affinchè utilizzi il sistema delle view generiche, in modo da poter cancellare un sacco di codice. Dovremo fare la conversione in qualche step.

1. Converti la URLconf.
2. Cancella alcune delle vecchie, non necessarie viste.
3. Introduci nuove visualizzazioni basate sulle generic views di Django.

Continua a leggere per i dettagli.

> **Perchè il code-shuffle?**
>
> Solitamente, quando scrivi un’applicazione in Django, dovresti valutare quali viste generiche vanno bene per il tuo problema, invece di ristrutturare il codice a metà strada Ma questa guida era intenzionalmente focalizzato fino ad ora, sullo scrivere le viste nel modo più difficile, per mettere a punto i concetti principali.
>
> Dovresti conoscere la matematica di base prima di iniziare a usare una calcolatrice.

### Correggere la URLconf

Prima di tutto, apri la URLconf `polls/urls.py` e cambiala così:

*`polls/urls.py`*

```python
from django.urls import path

from . import views

app_name = 'polls'
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('<int:pk>/', views.DetailView.as_view(), name='detail'),
    path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
    path('<int:question_id>/vote/', views.vote, name='vote'),
]
```

Nota che il nome del pattern che combacia nelle stringhe dei percorsi del secondo e terzo pattern è cambiato da `<question_id>` a `<pk>`.

### Correggere le viste

Poi, andremo a rimuovere le nostre vecchie view `index`, `detail` e `results` per usare le view generiche di Django. Per farlo, apri il file `polls/views.py` e cambialo così:

*`polls/views.py`*

```python
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic

from .models import Choice, Question

class IndexView(generic.ListView):
    template_name = 'polls/index.html'
    context_object_name = 'latest_question_list'

    def get_queryset(self):
        """Return the last five published questions."""
        return Question.objects.order_by('-pub_date')[:5]

class DetailView(generic.DetailView):
    model = Question
    template_name = 'polls/detail.html'

class ResultsView(generic.DetailView):
    model = Question
    template_name = 'polls/results.html'

def vote(request, question_id):
    ... # same as above, no changes needed.
```

Stiamo usando due view generiche qui: [`ListView`](/it/3.2/ref/class-based-views/generic-display/#django.views.generic.list.ListView) e [`DetailView`](/it/3.2/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView). Rispettivamente, queste due view astraggono il concetto di «mostrare una lista di oggetti» e «mostrare una pagina di dettaglio per un particolare tipo di oggetto».

- Ogni view generica ha bisogno di sapere su che modello agirà. Questa cosa viene definita con l’attributo `model`.
- La view generica  [`DetailView`](/it/3.2/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView) si aspetta che la chiave primaria che viene catturata dalla URL si chiami `"pk"`, quindi abbiamo cambiato `question_id` in `pk` per le view generiche.

Di default, la view generica  [`DetailView`](/it/3.2/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView) usa un template chiamato \<app name\>/\<model name\>\_detail.html\`. Nel nostro caso, dovrebbe usare il template `"polls/question_detail.html"`. L’attributo `template_name` è utile per usare un template specifico invece del nome di template generato automaticamente. Specifichiamo anche il `template_name` per la list view `results` – questo ci assicura che la view dei risultati e la view dei dettagli abbiamo una interfaccia diversa quando vengono mostrate, anche se, dietro le quinte, sono entrambe [`DetailView`](/it/3.2/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView).

In modo simile, la view generica [`ListView`](/it/3.2/ref/class-based-views/generic-display/#django.views.generic.list.ListView) usa un template di default chiamato `<app name>/<model name>_list.html`; usiamo `template_name` per dire a [`ListView`](/it/3.2/ref/class-based-views/generic-display/#django.views.generic.list.ListView) di usare il nostro template esistente `"polls/index.html"`.

Nella parte precedente di questo tutorial, i template sono stati forniti con un contesto che contiene le variabili `question` e `latest_question_list`. Per `DetailView` la variabile `question` viene fornita automaticamente – visto che stiamo usando un modello Django (`Question`), Django è in grado di determinare un nome appropriato per la variabile di contesto. Comunque, per ListView, la variabile di contesto generata automaticamente è `question_list`. Per sovrascrivere questo, forniamo l’attributo context\_object\_name\`, specificando che vogliamo usare `latest_question_list` al suo posto. Come approccio alternativo, puoi cambiare i tuoi template per rispecchiare le nuove variabili di contesto di default – ma è molto più facile dire a Django di usare le variabili che vuoi.

Esegui il server e usa la tua nuova applicazione di sondaggio basata su visualizzazioni generiche.

Per i dettagli completi sulle viste generiche, vedere la: doc:generic views documentation \</topics/class-based-views/index\>.

Quando hai dimestichezza con i moduli e le visualizzazioni generiche, leggi la [parte 5 di questo tutorial](/it/3.2/intro/tutorial05/) per scoprire come testare la nostra app per i sondaggi.
