# Documentazione Django 5.2.8

# Scrivere la tua prima applicazione in Django, parte 3

Questo tutorial inizia dove si è interrotto il Tutorial 2 . Stiamo proseguendo con l’applicazione dei questionari online e ci focalizzeremo nella creazione dell’interfaccia pubblica – «views.»

Dove trovare aiuto:

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

## Panoramica

Una view è un «tipo» di pagina web nella tua applicazione Django, che generalmente serve una specifica funzione ed ha un template specifico. Per esempio, in una applicazione blog, potresti avere le seguenti views:

- Home page del blog – mostra le ultime voci.

- Pagina di «dettaglio» della voce – pagina permanente per una singola voce.

- Pagina di archivio in base all’anno – visualizza tutti i mesi con le voci nell’anno specificato.

- L’archivio mensile – mostra tutti i giorni con le relative pubblicazioni in un dato mese.

- L’archivio giornaliero – mostra tutte le pubblicazioni in un determinato giorno.

- L’azione per i commenti – gestisce la possibilità di commentare una determinata pubblicazione.

Nella nostra applicazione di sondaggi, avremo le seguenti quattro visualizzazioni:

- L” «indice» delle domande – mostra una selezione delle ultime domande.

- La pagina «dettagli» della domanda – mostra il testo della domanda, senza risultati ma con un form per votare.

- La pagina «risultati» delle domande – mostra i risultati per una determinata domanda.

- L’azione del voto – gestisce il voto per una scelta particolare in una azione particolare.

In Django, le pagine web e gli altri contenuti sono serviti dalle views. Ogni view è rappresentata da una funzione Python (o un metodo, in caso di views basate su classi). Django sceglierà una view esaminando la URL che viene richiesta (per essere precisi, la parte di URL dopo il nome di dominio).

Adesso, nel tempo che hai trascorso sul web potresti essere incappato in amenità come `ME2/Sites/dirmod.htm?sid=&type=gen&mod=Core+Pages&gid=A6CD4967199A42D9B65B1B`. Sarai felice di sapere che Django ci permette di utilizzare pattern per le URL che sono molto più eleganti di quelli.

Un pattern URL è la forma generale di una URL - per esempio: `/newsarchive/<year>/<month>/`.

Per prendere una URL da una view, Django usa quelle che sono chiamate “URLconfs”. Una URLconf mappa i pattern delle URL sulle view.

Questo tutorial fornisce istruzioni di base per l’uso di URLconfs e puoi fare riferimento a URL dispatcher per maggiori informazioni.

## Scrivere altre visualizzazioni

Adesso aggiungiamo poche altre view a `polls/views.py`. Queste view sono leggermente differenti, perchè prendono un argomento:

`polls/views.py`

    def detail(request, question_id):
        return HttpResponse("You're looking at question %s." % question_id)

    def results(request, question_id):
        response = "You're looking at the results of question %s."
        return HttpResponse(response % question_id)

    def vote(request, question_id):
        return HttpResponse("You're voting on question %s." % question_id)

Collega queste nuove view nel modulo `polls.urls` aggiungendo le seguenti chiamate `path()`:

`polls/urls.py`

    from django.urls import path

    from . import views

    urlpatterns = [
        # ex: /polls/
        path("", views.index, name="index"),
        # ex: /polls/5/
        path("<int:question_id>/", views.detail, name="detail"),
        # ex: /polls/5/results/
        path("<int:question_id>/results/", views.results, name="results"),
        # ex: /polls/5/vote/
        path("<int:question_id>/vote/", views.vote, name="vote"),
    ]

Take a look in your browser, at «/polls/34/». It’ll run the `detail()` function and display whatever ID you provide in the URL. Try «/polls/34/results/» and «/polls/34/vote/» too – these will display the placeholder results and voting pages.

When somebody requests a page from your website – say, «/polls/34/», Django will load the `mysite.urls` Python module because it’s pointed to by the `ROOT_URLCONF` setting. It finds the variable named `urlpatterns` and traverses the patterns in order. After finding the match at `'polls/'`, it strips off the matching text (`"polls/"`) and sends the remaining text – `"34/"` – to the “polls.urls” URLconf for further processing. There it matches `'<int:question_id>/'`, resulting in a call to the `detail()` view like so:

    detail(request=<HttpRequest object>, question_id=34)

La parte `question_id=34` viene da `<int:question_id>`. L’utilizzo delle parentesi angolari «cattura» parte della URL e la invia come argomento keyword alla funzione della view. La parte `question_id` della stringa definisce un nome che sarà utilizzato per identificare il pattern individuato, e la parte `int` è un elemento di conversione che determina quali pattern dovrebbero essere individuati da questa parte del percorso URL. I due punti (`:`) separano il convertitore dal nome del pattern.

## Scrivi delle visualizzazioni che fanno effettivamente qualcosa

Ogni view è responsabile di fare una delle due cose: restituire un oggetto `HttpResponse` con il contenuto della pagina richiesta oppure sollevare una eccezione come `Http404`. Il resto spetta a te.

La tua view può leggere dati dal database oppure no. Può usare un sistema di template come quello di Django – o un sistema di template per Python di terze parti – o no. Può generare un file PDF, un XML in output, creare un file ZIP sul momento, usare qualsiasi libreria Python tu voglia.

Tutto quel che Django vuole è quella `HttpResponse`. Oppure un’eccezione.

Dal momento che conviene, usiamo l’API database di Django, che abbiamo visto nella guida 2. Ecco una prova per la nuova view `index()`, che mostra le ultime 5 domande dei sondaggi nel sistema, separati dalla virgola, secondo la data di pubblicazione:

`polls/views.py`

    from django.http import HttpResponse

    from .models import Question

    def index(request):
        latest_question_list = Question.objects.order_by("-pub_date")[:5]
        output = ", ".join([q.question_text for q in latest_question_list])
        return HttpResponse(output)

    # Leave the rest of the views (detail, results, vote) unchanged

Eppure c’è un problema qui: il design della pagina è codificato nella view. Se vuoi cambiare il modo in cui la pagina appare, dovrai modificare questo codice Python. Usiamo il sistema di template di Django per separare il design da Python creando un template che la view possa usare.

Per prima cosa, crea una directory chiamata `templates` nella tua directory `polls`. Django cercherà i templates lì dentro.

L’impostazione `TEMPLATES` del tuo progetto descrive come Django caricherà e mostrerà i template. Il file di impostazioni di default configura un backend DjangoTemplates` la cui opzione `APP_DIRS` è impostata a True. Per convenzione `DjangoTemplates` cerca una sottocartella «templates» in ognuna delle `INSTALLED_APPS`.

Nella directory `templates` che hai appena creato, crea un’altra directory chiamata `polls`, e in quella crea un file chiamato `index.html`. In altre parole, il tuo template dovrebbe trovarsi in `polls/templates/polls/index.html`. Siccome il caricamento dei template delle `app_directories` lavora come spiegato poco fa, puoi fare riferimento a questo template in Django come `polls/index.html`.

Spazio nomi template

Adesso dovremmo essere in grado di cavarcela mettendo i template direttamente in `polls/templates` (invece che creare un’altra sottodirectory `polls`), ma sarebbe una cattiva idea. Django sceglierà il primo template che troverà il cui nome combaci con quello che cerca e sei hai un template con lo stesso nome in una applicazione differente, Django potrebbe non essere in grado di operare una distinzione. Dobbiamo essere in grado di far puntare Django a quello giusto, ed il miglior modo di assicurarcene è facendone il namespacing. Il che significa, mettendo questi template in un”altra directory chiamata come l’applicazione stessa.

Inserisci il seguente codice nel template:

`polls/templates/polls/index.html`

    {% if latest_question_list %}
        <ul>
        {% for question in latest_question_list %}
            <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
        {% endfor %}
        </ul>
    {% else %}
        <p>No polls are available.</p>
    {% endif %}

Nota

Per rendere più corto il tutorial, tutti gli esempi dei templati utilizzano un HTML incompleto. Nei tuoi progetti devi usare documenti HTML completi.

Ora aggiorniamo la nostra vista `index` in `polls/views.py` per utilizzare il modello:

`polls/views.py`

    from django.http import HttpResponse
    from django.template import loader

    from .models import Question

    def index(request):
        latest_question_list = Question.objects.order_by("-pub_date")[:5]
        template = loader.get_template("polls/index.html")
        context = {"latest_question_list": latest_question_list}
        return HttpResponse(template.render(context, request))

Il codice carica il template chiamato `polls/index.html` e gli passa un context. Il context è un dizionario che associa i nomi delle variabili nel template agli oggetti Python.

Carica la pagina puntando il browser su «/polls/», e dovresti vedere una lista puntata che contiene la domanda «Come va» dal Tutorial 2. Il link punta alla pagina di dettaglio della domanda.

### Una scorciatoia: `render()`

E” un idioma molto comune per caricare un template, quello di riempire un context e restituire un oggetto `HttpResponse` con il risultato del template mostrato. Django fornisce una scorciatoia. Ecco la view `index()` completa, riscritta:

`polls/views.py`

    from django.shortcuts import render

    from .models import Question

    def index(request):
        latest_question_list = Question.objects.order_by("-pub_date")[:5]
        context = {"latest_question_list": latest_question_list}
        return render(request, "polls/index.html", context)

Nota che una volta che abbiamo fatto questo in tutte le view, non abbiamo più bisogno di importare `loader` e `HttpResponse` (potresti voler tenere `HttpResponse` nel caso tu non abbia ancora i metodi stub per `detail`, `results` e `vote`).

La funzione `render()` prende l’oggetto request come primo argomento, un nome di template come secondo argomento ed un dizionario come terzo argomento opzionale. Restituisce un oggetto `HttpResponse` del template dato reso con il contesto dato.

## Generazione di un errore 404

Adesso affrontiamo la questione della view del dettaglio – la pagina che mostra il testo della domanda per un dato sondaggio. Ecco la view:

`polls/views.py`

    from django.http import Http404
    from django.shortcuts import render

    from .models import Question

    # ...
    def detail(request, question_id):
        try:
            question = Question.objects.get(pk=question_id)
        except Question.DoesNotExist:
            raise Http404("Question does not exist")
        return render(request, "polls/detail.html", {"question": question})

Il concetto nuovo qui: La view solleva l’eccezione `Http404` se non esiste un sondaggio con l’ID richiesto.

Discuteremo cosa potresti mettere in quel template `polls/detail.html` un po” più tardi, ma se ti piacerebbe avere l’esempio di cui sopra funzionale in un tempo rapido, un file che contiene solo:

`polls/templates/polls/detail.html`

    {{ question }}

ti farà iniziare per ora.

### Una scorciatoia: `get_object_or_404()`

E” un idioma molto comune usare `get()` e sollevare `Http404` se l’oggetto non esiste. Django offre una scorciatoia. Ecco la view `detail()`, riscritta:

`polls/views.py`

    from django.shortcuts import get_object_or_404, render

    from .models import Question

    # ...
    def detail(request, question_id):
        question = get_object_or_404(Question, pk=question_id)
        return render(request, "polls/detail.html", {"question": question})

La funzione `get_object_or_404()` prende un modello Django come primo argomento e un numero arbitrario di argomenti keyword, che passa alla funzione `get()` del manager del modello. Solleva `Http404` se l’oggetto non esiste.

Filosofia

Perchè usiamo una funzione helper `get_object_or_404()` invece di catturare automaticamente l’eccezione `ObjectDoesNotExist` ad un livello più alto o di avere l’API del modello che solleva `Http404` invece di `ObjectDoesNotExist`?

Perchè quello accoppierebbe il layer del modello alla layer della view. Uno dei primi obiettivi di design di Django è di mantenere un accoppiamento blando. Un po” di accoppiamento controllato è introdotto nel modulo `django.shortcuts` .

Esiste anche un funzione `get_list_or_404()` , che funziona esattamente come `get_object_or_404()` – ad eccezione di usare `filter()` invece di `get()`. Solleva `Http404` se la lista è vuota.

## Utilizzare il sistema di template

Torniamo alla view `detail()` della nostra applicazione dei sondaggi. Data la variabile di contesto question`, ecco come potrebbe apparire il template `polls/detail.html`:

`polls/templates/polls/detail.html`

    <h1>{{ question.question_text }}</h1>
    <ul>
    {% for choice in question.choice_set.all %}
        <li>{{ choice.choice_text }}</li>
    {% endfor %}
    </ul>

Il sistema di template usa una sintassi «a ricerca con il punto» per accedere alle variabili attributo. Nell’esempio di `{{ question.question_text }}`, prima Django effettua una ricerca a dizionario sull’oggetto `question`. Fallendo quella, prova una ricerca dell’attributo – che funziona, in questo caso. Se la ricerca dell’attributo avesse fallito, avrebbe provato con una ricerca sugli indici della lista.

La chiamata a metodo avviene nel `{% for %}` loop: `question.choice_set.all` viene interpretato come il codice Python `question.choice_set.all()`, che restituisce un iterable di oggetti `Choice` ed è adatto ad essere usato nel tag `{% for %}`.

Vedi la template guide per maggiori informazioni sui templates.

## Rimuovere le URL codificate nei template

Ricorda, quando abbiamo scritto il link ad una domanda nel template `polls/index.html`, il link era parzialmente hardcodato come:

    <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>

The problem with this hardcoded, tightly-coupled approach is that it becomes challenging to change URLs on projects with a lot of templates. However, since you defined the `name` argument in the `path()` functions in the `polls.urls` module, you can remove a reliance on specific URL paths defined in your url configurations by using the `{% url %}` template tag:

    <li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>

Il modo in cui funziona è ricercando la definizione della URL così come è definita nel modulo `polls.urls`. Puoi vedere esattamente dove il nome della URL di “detail” è definita qui sotto:

    ...
    # the 'name' value as called by the {% url %} template tag
    path("<int:question_id>/", views.detail, name="detail"),
    ...

Se vuoi cambiare la URL della vista di dettaglio del sondaggio a qualcos’altro, magari a qualcosa come `polls/specifics/12/` invece di farlo nel template (o nei template) lo cambieresti in `polls/urls.py`:

    ...
    # added the word 'specifics'
    path("specifics/<int:question_id>/", views.detail, name="detail"),
    ...

## Assegnazione dello spazio dei nomi alle URL

Il progetto del tutorial ha solo una app, `polls`. Nei veri progetti Django, ci possono essere cinque, dieci, venti app o anche più. Come fa Django a differenziare i nomi delle URL tra di esse? Per esempio, l’app `polls` ha una view `detail`, e così potrebbe averla una app sullo stesso progetto che serve per un blog. Come si a fare in modo che Django sappia quale view di quale app creare da un url quando si usa il tag di template `{% url %}`?

La risposta è di aggiungere namespaces al tuo URLconf. Nel file `polls/urls.py`, procedi ed inserisci un `app_name` per impostare il namespace della applicazione.

`polls/urls.py`

    from django.urls import path

    from . import views

    app_name = "polls"
    urlpatterns = [
        path("", views.index, name="index"),
        path("<int:question_id>/", views.detail, name="detail"),
        path("<int:question_id>/results/", views.results, name="results"),
        path("<int:question_id>/vote/", views.vote, name="vote"),
    ]

Adesso cambia il tuo template `polls/index.html` da:

`polls/templates/polls/index.html`

    <li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>

per puntare al namespace detail della vista:

`polls/templates/polls/index.html`

    <li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>

Quando ti senti a tuo agio a scrivere le view, leggi la parte 4 di questo tutorial per imparare le basi del processamento dei form e le view generiche.