1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
|
---
title: 'Django Tutorial Part 6: Generic list and detail views'
slug: Learn/Server-side/Django/Generic_views
tags:
- Template
- Tutorial
- View
- django
- django view
- imparare
- inizio
- template django
- views
- viste django
translation_of: Learn/Server-side/Django/Generic_views
---
<div>{{LearnSidebar}}</div>
<div>{{PreviousMenuNext("Learn/Server-side/Django/Home_page", "Learn/Server-side/Django/Sessions", "Learn/Server-side/Django")}}</div>
<p class="summary">Questo tutorial estenderà il nostro sito <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a>, aggiungendo pagine di elenco e pagine di dettaglio per libri e autori. Qui apprenderemo le viste generiche basate su classi e mostreremo come possono ridurre la quantità di codice che devi scrivere per casi di uso comune. Passeremo inoltre alla gestione degli URL in maggiore dettaglio, mostrando come eseguire la corrispondenza di base dei pattern.</p>
<table class="learn-box standard-table">
<tbody>
<tr>
<th scope="row">Prerequisiti:</th>
<td>Completare tutti i tutorial precedenti, incluso <a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a>.</td>
</tr>
<tr>
<th scope="row">Obiettivi:</th>
<td>Comprendere dove e come utilizzare viste generiche basate su classi e come estrarre modelli dagli URL e passare le informazioni alle viste.</td>
</tr>
</tbody>
</table>
<h2 id="Panoramica">Panoramica</h2>
<p>In questo tutorial completeremo la prima versione del sito Web LocalLibrary aggiungendo pagine di elenco e dettagli per libri e autori (o per essere più precisi, ti mostreremo come implementare le pagine del libro e ti guideremo nella creazione dellle pagine dell'autore in modo che possa farle tu stesso!)</p>
<p>Il processo è simile alla creazione della pagina indice, che abbiamo mostrato nel precedente tutorial. Dovremo comunque creare mappe URL, viste e template. La differenza principale è che per le pagine di dettaglio avremo la sfida aggiuntiva di estrarre le informazioni dai pattern nell'URL e passarle alla view. Per queste pagine, mostreremo un tipo di view completamente diverso: view di elenco e view di dettaglio generiche e basate su classi. Queste possono ridurre in modo significativo la quantità di codice necessario per la view, semplificandone la scrittura e la manutenzione.</p>
<p>La parte finale del tutorial mostrerà come impaginare i dati quando si utilizzano view generiche di elenco basate su classi.</p>
<h2 id="Pagina_lista_di_libri">Pagina lista di libri</h2>
<p>Nella pagina dell'elenco dei libri verrà visualizzato un elenco di tutti i record di libri disponibili nella biblioteca, a cui è possibile accedere utilizzando l'URL: <code>catalog/books/</code>. La pagina mostrerà un titolo e un autore per ogni record, con il titolo che è un collegamento ipertestuale alla relativa pagina dei dettagli del libro. La pagina avrà la stessa struttura e la stessa navigazione di tutte le altre pagine del sito e, pertanto, possiamo estendere il template di base (<strong>base_generic.html</strong>).</p>
<h3 id="URL_mapping">URL mapping</h3>
<p>Apri <strong>/catalog/urls.py</strong> e copia la riga in grassetto sotto. Come per la pagina index, la funzione <code>path()</code> definisce un pattern da matchare con l' URL (<strong>'books/'</strong>), una funzione di view che verrà richiamata se l' URL matcha (<code>views.BookListView.as_view()</code>), e un nome per questa particolare mappatura.</p>
<pre class="brush: python">urlpatterns = [
path('', views.index, name='index'),
<strong> </strong>path<strong>('books/', views.BookListView.as_view(), name='books'),</strong>
]</pre>
<p>Come discusso nel precedente tutorial, l'URL deve avere già matchato <code>/catalog</code>, quindi la view sarà richiamata per l'URL: <code>/catalog/books/</code>.</p>
<p>La funzione view ha un formato diverso rispetto a prima - questo perché questa vista verrà effettivamente implementata come una classe. Noi erediteremo da una funzione di visualizzazione generica esistente che già fa la maggior parte di ciò che vogliamo, invece di scriverla noi stessi daccapo.</p>
<p>Per le view class-based di Django, si accede a una funzione view appropriata chiamando il metodo di classe <code>as_view()</code>. Questo fa tutto il lavoro necessario per creare un'istanza della classe e assicurarsi che i giusti metodi handler vengano chiamati per le richieste HTTP in arrivo.</p>
<h3 id="Viste_(class-based)">Viste (class-based)</h3>
<p>Potremmo facilmente scrivere la view dell'elenco dei libri come una funzione regolare (proprio come la nostra precedente vista indice), che interrogherebbe il database cercando tutti i libri e quindi chiamerebbe <code>render()</code> per passare l'elenco a un template specificato. Invece, utilizzeremo una view elenco generica basata su classi (<code>ListView</code>) — una classe che eredita da una vista esistente. Poiché la vista generica implementa già la maggior parte delle funzionalità di cui abbiamo bisogno e segue la best practice di Django, saremo in grado di creare una vista elenco più robusta con meno codice, meno ripetizioni e, in definitiva, meno manutenzione.</p>
<p>Apri <strong>catalog/views.py</strong>, e copia il seguente codice nel file:</p>
<pre class="brush: python">from django.views import generic
class BookListView(generic.ListView):
model = Book</pre>
<p>Ecco fatto! la list view generica effettuerà una query al database per prendere tutti i record per lo specifico model (<code>Book</code>) poi effettuerà un render tramite il template in <strong>/locallibrary/catalog/templates/catalog/book_list.html</strong> che creeremo sotto. Dentro al template puoi accedere alla lista dei libri con la variabile <code>object_list</code> OR <code>book_list</code> (cioè, genericamente "<code><em>the_model_name</em>_list</code>").</p>
<div class="note">
<p><strong>Nota</strong>: Questo percorso scomodo per la posizione del template non è un errore di stampa: le view generiche cercano i template in <code>/<em>application_name</em>/<em>the_model_name</em>_list.html</code> (<code>catalog/book_list.html</code> in questo caso) dentro l'applicazione <code>/<em>application_name</em>/templates/</code> nella directory (<code>/catalog/templates/)</code>.</p>
</div>
<p>È possibile aggiungere attributi per modificare il comportamento predefinito sopra. Ad esempio, è possibile specificare un altro file template se è necessario disporre di più viste che utilizzano questo stesso model oppure si potrebbe voler utilizzare un dievrso nome di variabile di template se <code>book_list</code> non è intuitivo per il proprio specifico caso d'uso del template. Probabilmente la variante più utile è quella di modificare/filtrare il sottoinsieme di risultati che vengono restituiti, quindi, invece di elencare tutti i libri, potresti elencare i primi 5 libri letti da altri utenti.</p>
<pre class="brush: python">class BookListView(generic.ListView):
model = Book
context_object_name = 'my_book_list' # your own name for the list as a template variable
queryset = Book.objects.filter(title__icontains='war')[:5] # Get 5 books containing the title war
template_name = 'books/my_arbitrary_template_name_list.html' # Specify your own template name/location</pre>
<h4 id="Override_dei_metodi_nelle_viste_class-based">Override dei metodi nelle viste class-based</h4>
<p>Anche se non è necessario farlo qui, puoi anche sovrascrivere alcuni dei metodi di classe.</p>
<p>Possiamo, per esempio, sovrascrivere <code>get_queryset()</code> per modificare la lista di record restituiti. Questa metodologia è molto più flessibile rispetto all'attributo <code>queryset</code> come abbiamo fatto nel precedente frammento di codice (sebbene in questo caso non ci sia alcun beneficio reale):</p>
<pre class="brush: python">class BookListView(generic.ListView):
model = Book
def get_queryset(self):
return Book.objects.filter(title__icontains='war')[:5] # Get 5 books containing the title war
</pre>
<p>Possiamo anche sovrascrivere <code>get_context_data()</code> per passare altre variabili addizionali di context al template (es. la lista di libri è passata per default). Il frammento sotto mostra come aggiungere una variabile "<code>some_data</code>" al context (sarà quindi disponibile come variabile del template).</p>
<pre class="brush: python">class BookListView(generic.ListView):
model = Book
def get_context_data(self, **kwargs):
# Call the base implementation first to get the context
context = super(BookListView, self).get_context_data(**kwargs)
# Create any data and add it to the context
context['some_data'] = 'This is just some data'
return context</pre>
<p>Quando si esegue questa operazione è importante seguire lo schema usato sopra:</p>
<ul>
<li>Per prima cosa prendi il contesto esistente dalla nostra superclasse.</li>
<li>Quindi aggiungi le tue nuove informazioni di contesto.</li>
<li>Quindi restituisci il nuovo contesto (aggiornato).</li>
</ul>
<div class="note">
<p><strong>Nota</strong>: Leggi <a href="https://docs.djangoproject.com/en/2.1/topics/class-based-views/generic-display/">Built-in class-based generic views</a> (Django docs) per vedere molti altri esempi di cosa puoi fare.</p>
</div>
<h3 id="Creare_List_View_template">Creare List View template</h3>
<p>Crea il file HTML <strong>/locallibrary/catalog/templates/catalog/book_list.html</strong> e copia il testo sotto. Come discusso sopra, questo è il file predefinito per un template previsto dalla vista elenco generica basata su classi (per un modello denominato <code>Book</code> in un'applicazione denominata <code>catalog</code>)</p>
<p>I template per le view generiche sono come qualsiasi altro template (anche se ovviamente il contesto/informazioni passate al template possono differire). Come con il nostro template di <em>index</em>, estendiamo il nostro template di base nella prima riga e poi sostituiamo il blocco denominato <code>content</code>.</p>
<pre class="brush: html">{% extends "base_generic.html" %}
{% block content %}
<h1>Book List</h1>
<strong>{% if book_list %}</strong>
<ul>
{% for book in book_list %}
<li>
<a href="\{{ book.get_absolute_url }}">\{{ book.title }}</a> (\{{book.author}})
</li>
{% endfor %}
</ul>
<strong>{% else %}</strong>
<p>There are no books in the library.</p>
<strong>{% endif %} </strong>
{% endblock %}</pre>
<p>La view passa il contesto (elenco di libri) di default con <code>object_list</code> e <code>book_list</code> come alias; in ogni caso funzionerà.</p>
<h4 id="Esecuzione_condizionale">Esecuzione condizionale</h4>
<p>Usiamo i tag template <code><a href="https://docs.djangoproject.com/en/2.1/ref/templates/builtins/#if">if</a></code>, <code>else</code>, ed <code>endif</code> per controllare se la <code>book_list</code> è stata definita e non è vuota. Se <code>book_list</code> è vuota, allora la clausola <code>else</code> mostra un testo alternativo in cui spiega che non sono presenti record da elencare. Se <code>book_list</code> non è vuota, allora iteriamo sulla lista di libri.</p>
<pre class="brush: html"><strong>{% if book_list %}</strong>
<!-- code here to list the books -->
<strong>{% else %}</strong>
<p>There are no books in the library.</p>
<strong>{% endif %}</strong>
</pre>
<p>La condizione sopra fa il test su un'unica condizione, ma si possono effettuare ulteriori test e gestire ulteriori casi, per testare condizioni addizionali si può usare ad esempio il tag <code>elif </code>(es. <code>{% elif var2 %}</code>). Per maggiori informazioni sugli operatori condizionali consultare: <a href="https://docs.djangoproject.com/en/2.1/ref/templates/builtins/#if">if</a>, <a href="https://docs.djangoproject.com/en/2.1/ref/templates/builtins/#ifequal-and-ifnotequal">ifequal/ifnotequal</a>, <a href="https://docs.djangoproject.com/en/2.1/ref/templates/builtins/#ifchanged">ifchanged</a> in <a href="https://docs.djangoproject.com/en/2.1/ref/templates/builtins">Built-in template tags and filters</a> (Django Docs).</p>
<h4 id="Cicli_for">Cicli for</h4>
<p>Il template utilizza i tag <a href="https://docs.djangoproject.com/en/2.1/ref/templates/builtins/#for">for</a> <code>endfor</code> per ciclare la lista di libri, come sotto. Ogni iterazione popola la variabile di template <code>book</code> con le informazioni per l'elemento corrente della lista.</p>
<pre class="brush: html">{% for <strong>book</strong> in book_list %}
<li> <!-- code here get information from each <strong>book</strong> item --> </li>
{% endfor %}
</pre>
<p>Anche se non usato qui, all'interno del loop Django creerà anche altre variabili che puoi usare per tracciare l'iterazione. Ad esempio, è possibile testare la variabile <code>forloop.last</code> per eseguire l'elaborazione condizionale l'ultima volta che viene eseguito il ciclo.</p>
<h4 id="Accedere_alle_variabili">Accedere alle variabili</h4>
<p>Il codice all'interno del ciclo crea un item di elenco per ogni libro che mostra sia il titolo (come collegamento alla vista dei dettagli ancora da creare) sia l'autore.</p>
<pre class="brush: html"><a href="\{{ book.get_absolute_url }}">\{{ book.title }}</a> (\{{book.author}})
</pre>
<p>Accediamo ai campi del record del libro associato utilizzando la "notazione dot" (es. <code>book.title</code> e <code>book.author</code>), dove il testo che segue <code>book</code> è il nome del campo (come definito nel model).</p>
<p>Possiamo anche chiamare delle <em>functions</em> nel model da dentro il nostro template — in questo caso <code>Book.get_absolute_url()</code> per ottenere un URL che è possibile utilizzare per visualizzare il record di dettaglio associato. Questo funziona a condizione che la funzione non abbia argomenti (non c'è modo di passare argomenti!)</p>
<div class="note">
<p><strong>Nota</strong>: Dobbiamo stare attenti agli "effetti collaterali" quando chiamiamo le funzioni nei model. Qui visualizziamo solo un URL, ma una funzione può fare praticamente qualsiasi cosa: non vogliamo rischiare di cancellare il nostro database (per esempio) semplicemente mostrando il nostro template!</p>
</div>
<h4 id="Update_del_template_di_base">Update del template di base</h4>
<p>Apri il template di base (<strong>/locallibrary/catalog/templates/<em>base_generic.html</em></strong>) ed inserisci <strong>{% url 'books' %} </strong>dentro il link Url per <strong>All books</strong>, come sotto. Questo abiliterà il link in tutte le pagine (possiamo metterlo in pratica con successo ora che abbiamo creato il mapper URL "libri").</p>
<pre class="brush: python"><li><a href="{% url 'index' %}">Home</a></li>
<strong><li><a href="{% url 'books' %}">All books</a></li></strong>
<li><a href="">All authors</a></li></pre>
<h3 id="Come_viene_mostrato">Come viene mostrato?</h3>
<p>Non sarà ancora possibile creare l'elenco dei libri, perché manca ancora una dipendenza: la mappa degli URL per le pagine dei dettagli del libro, necessaria per creare collegamenti ipertestuali a singoli libri. Mostreremo entrambe le viste elenco e dettaglio dopo la prossima sezione.</p>
<h2 id="Pagina_di_dettaglio_dei_libri">Pagina di dettaglio dei libri</h2>
<p>La pagina dei dettagli del libro mostrerà le informazioni su un libro specifico, accessibile tramite l'URL <code>catalog/book/<em><id></em></code> (dove <code><em><id></em></code> è la chiave primaria per il libro). Oltre ai campi nel model Book (autore, sommario, ISBN, lingua e genere), elencheremo anche i dettagli delle copie disponibili (<code>BookInstances</code>) compreso lo stato, la data di ritorno prevista, l'edizione e l'id. Ciò consentirà ai nostri lettori non solo di conoscere il libro, ma anche di confermare se/quando è disponibile.</p>
<h3 id="URL_mapping_2">URL mapping</h3>
<p>Apri <strong>/catalog/urls.py</strong> e aggiungi l'URL mapper '<strong>book-detail</strong>' mostrato in grassetto qui sotto. Questa funzione <code>path()</code> definisce un pattern, una vista di dettaglio generica basata sulla classe e un nome.</p>
<pre class="brush: python">urlpatterns = [
path('', views.index, name='index'),
path('books/', views.BookListView.as_view(), name='books'),
<strong> path('book/<int:pk>', views.BookDetailView.as_view(), name='book-detail'),</strong>
]</pre>
<p>Per il path dei dettagli del libro, il pattern URL utilizza una sintassi speciale per catturare l'ID specifico del libro che vogliamo vedere. La sintassi è molto semplice: le parentesi angolari definiscono la parte dell'URL da catturare, racchiudendo il nome della variabile che la vista può utilizzare per accedere ai dati acquisiti. Per esempio, <strong><something></strong> , catturerà il pattern marcato, e passerà il valore alla view come variabile con nome "something". Puoi anche far precedere al nome della variabile una <a href="https://docs.djangoproject.com/en/2.1/topics/http/urls/#path-converters">specifica di conversione</a> che definisce il tipo di dato (int, str, slug, uuid, path).</p>
<p>In questo caso usiamo <code>'<int:pk>'</code><strong> </strong>per acquisire l'id del libro, che deve essere una stringa appositamente formattata e passarla alla vista come parametro chiamato <code>pk</code> (abbreviazione di primary key). Questo è l'ID che viene utilizzato per archiviare il libro in modo univoco nel database, come definito nel Modello Book.</p>
<div class="note">
<p><strong>Nota</strong>: Come discusso precedentemente, il nostro URL matchato in realtà è <code>catalog/book/<digits></code> (ma perchè siamo nell'applicazione <strong>catalog</strong> <code>/catalog/</code> è sottinteso).</p>
</div>
<div class="warning">
<p><strong>Importante</strong>: La vista di dettaglio generica basata sulla classe prevede di passare un parametro denominato pk. Se stai scrivendo la tua vista funzione puoi usare qualsiasi nome di parametro che ti piace, o addirittura passare le informazioni in un argomento senza nome.</p>
</div>
<h4 id="Manuale_di_nozioni_avanzate_su_path_matching_ed_espressioni_regolari">Manuale di nozioni avanzate su path matching ed espressioni regolari</h4>
<div class="note">
<p><strong>Nota</strong>: Non avrai bisogno di questa sezione per completare il tutorial! Lo forniamo perché conoscere questa opzione rischia di essere utile nel tuo futuro incentrato su Django.</p>
</div>
<p>Il pattern matching fornito da <code>path()</code> è semplice ed utile per il caso (molto diffuso) in cui vuoi solo catturare ogni stringa od intero. Se è necessario un filtro più raffinato (ad esempio, per filtrare solo le stringhe con un determinato numero di caratteri), è possibile utilizzare il metodo <a href="https://docs.djangoproject.com/en/2.1/ref/urls/#django.urls.re_path">re_path()</a>.</p>
<p>Questo metodo funziona esattamente come <code>path()</code> eccetto per il fatto che permette di specificare un pattern utilizzando una Regex. Vedi: <a href="https://docs.python.org/3/library/re.html">Regular expression</a>. Per esempio, avremmo potuto specificare il path precedente con:</p>
<pre class="brush: python"><strong>re_path(r'^book/(?P<pk>\d+)$', views.BookDetailView.as_view(), name='book-detail'),</strong>
</pre>
<p>Le espressioni regolari sono uno strumento di mappatura dei pattern incredibilmente potente. Sono, francamente, abbastanza non intuitive e spaventose per i principianti. Di seguito è riportato un primer molto breve!</p>
<p>La prima cosa da sapere è che di solito le espressioni regolari dovrebbero essere dichiarate usando la sintassi "raw string" letterale (cioè, sono incluse come mostrato: <strong>r'<testo della regex>'</strong>).</p>
<p>Le parti principali della sintassi che devi conoscere per dichiarare i match del pattern sono:</p>
<table class="standard-table">
<thead>
<tr>
<th scope="col">Symbol</th>
<th scope="col">Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td>^</td>
<td>Matcha l'inizio del testo</td>
</tr>
<tr>
<td>$</td>
<td>Matcha la fine del testo</td>
</tr>
<tr>
<td>\d</td>
<td>Matcha un numero (0, 1, 2, ... 9)</td>
</tr>
<tr>
<td>\w</td>
<td>Matcha una parola word character, es. ogni maiuscola- o minuscola- dell'alfabeto, numero o underscore (_)</td>
</tr>
<tr>
<td>+</td>
<td>Matcha uno o più caratteri precedenti. Ad esempio, per matchare una o più cifre useresti <code>\d+</code>. Per abbinare uno o più caratteri "a", potresti usare <code>a+</code></td>
</tr>
<tr>
<td>*</td>
<td>Abbina zero o più del carattere precedente. Ad esempio, per abbinare niente o una parola che potresti usare <code>\w*</code></td>
</tr>
<tr>
<td>( )</td>
<td>Cattura la parte del pattern all'interno delle parentesi. Tutti i valori acquisiti verranno passati alla vista come parametri senza nome (se vengono catturati più pattern, i parametri associati verranno forniti nell'ordine in cui sono state dichiarate le acquisizioni)</td>
</tr>
<tr>
<td>(?P<<em>name</em>>...)</td>
<td>Cattura il pattern (indicato da ...) come una variabile con nome (in questo caso "name"). I valori catturati sono passati alla view con il nome specificato. La tua view deve dichiarare un argomento con lo stesso nome!</td>
</tr>
<tr>
<td>[ ]</td>
<td>Abbina uno dei caratteri del set. Per esempio, [abc] matcherà con 'a' o 'b' o 'c'. [-\w] restituirà un match con il carattere '-' o con ogni parola.</td>
</tr>
</tbody>
</table>
<p>La maggioranza degli altri caratteri può essere presa letteralmente!</p>
<p>Consideriamo alcuni esempi di pattern realistici:</p>
<table class="standard-table">
<thead>
<tr>
<th scope="col">Pattern</th>
<th scope="col">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>r'^book/(?P<pk>\d+)$'</strong></td>
<td>
<p>Matcha una stringa che ha <code>book/</code> all'inizio della linea (<strong>^book/</strong>), dopo ha una o più cifre (<code>\d+</code>), e quindi termina (senza caratteri non numerici prima dell'indicatore di fine riga).</p>
<p>Cattura anche tutte le cifre <strong>(?P<pk>\d+)</strong> e le passa alla vista in un parametro chiamato 'pk'. <strong>I valori catturati vengono sempre passati come una stringa!</strong></p>
<p>Ad esempio, <code>book/1234</code> invierà una variabile <code>pk = '1234</code>' alla view.</p>
</td>
</tr>
<tr>
<td><strong>r'^book/(\d+)$'</strong></td>
<td>Questo corrisponde agli stessi URL del caso precedente. Le informazioni acquisite verranno inviate come argomento senza nome alla vista.</td>
</tr>
<tr>
<td><strong>r'^book/(?P<stub>[-\w]+)$'</strong></td>
<td>
<p>Matcha una stringa che ha <code>book/</code> all'inizio della linea (<strong>^book/</strong>), quindi ha uno o più caratteri che sono o un carattere '-' o una parola (<strong>[-\w]+</strong>), e si conclude. Cattura anche questo set di caratteri e li passa alla vista in un parametro chiamato 'stub'.</p>
<p>Questo è uno schema abbastanza tipico per uno "stub". Gli stub sono chiavi primarie basate sull'uso di URL per i dati. È possibile utilizzare uno stub se si desidera che l'URL del libro sia più informativo. Per esempio <code>/catalog/book/the-secret-garden</code> anzichè <code>/catalog/book/33</code>.</p>
</td>
</tr>
</tbody>
</table>
<p>È possibile acquisire più pattern nello stesso match e quindi codificare molte informazioni diverse in un URL.</p>
<div class="note">
<p><strong>Nota</strong>: Come sfida, considera come potresti codificare un URL per elencare tutti i libri pubblicati in un particolare anno, mese, giorno e RE che potrebbero essere utilizzati per abbinarlo.</p>
</div>
<h4 id="Passare_opzioni_addizionali_nelle_tue_mappe_URL">Passare opzioni addizionali nelle tue mappe URL</h4>
<p>Una caratteristica che non abbiamo usato qui, ma che potresti trovare di valore, è che puoi dichiarare e passare alla view <a href="https://docs.djangoproject.com/en/2.1/topics/http/urls/#views-extra-options">opzioni aggiuntive</a>. Le opzioni sono dichiarate come dizionario che si passa come terzo argomento non assegnato (senza nome) alla funzione <code>path()</code>. Questo approccio può essere utile se si desidera utilizzare la stessa view per più risorse e passare i dati per configurarne il comportamento in ciascun caso (di seguito forniamo un template diverso in ciascun caso).</p>
<pre class="brush: python">path('url/', views.my_reused_view, <strong>{'my_template_name': 'some_path'}</strong>, name='aurl'),
path('anotherurl/', views.my_reused_view, <strong>{'my_template_name': 'another_path'}</strong>, name='anotherurl'),
</pre>
<div class="note">
<p><strong>Nota:</strong> Entrambe le opzioni extra e i pattern nominati catturati vengono passati alla view come argomenti con nome. Se si utilizza lo stesso nome sia per un pattern catturato che per un'opzione extra, solo il valore del pattern catturato verrà inviato alla vista (il valore specificato nell'opzione aggiuntiva verrà scartato).</p>
</div>
<h3 id="View_(class-based)">View (class-based)</h3>
<p>Apri <strong>catalog/views.py</strong>, e copia il seguente codice alla fine del file:</p>
<pre class="brush: python">class BookDetailView(generic.DetailView):
model = Book</pre>
<p>Fatto! Tutto ciò che ti serve fare ora è creare un template chiamato <strong>/locallibrary/catalog/templates/catalog/book_detail.html</strong>, e la view passerà al database l'informazione per lo specifico record di tipo <code>Book</code> estratto dall'URL mapper. All'interno del modello è possibile accedere all'elenco di libri con la variabile template denominata <code>object</code> OR <code>book</code> (cioè genericamente "the_model_name").</p>
<p>Se necessario, è possibile modificare il template utilizzato e il nome dell'oggetto contesto utilizzato per fare riferimento al libro nel template. È inoltre possibile sovrascrivere i metodi per aggiungere ulteriori informazioni al contesto, ad esempio.</p>
<h4 id="Cosa_succede_se_il_record_non_esiste">Cosa succede se il record non esiste?</h4>
<p>Se un record richiesto non esiste, la vista generica basata sulla classe genererà un'eccezione Http404 automaticamente: in produzione, verrà automaticamente visualizzata una pagina appropriata "risorsa non trovata", che è possibile personalizzare se lo si desidera. Solo per darti un'idea di come funziona, il frammento di codice seguente mostra come implementare la vista basata su classi come una funzione se non si stesse utilizzando la vista di dettaglio generica basata sulla classe.</p>
<pre class="brush: python">def book_detail_view(request, primary_key):
try:
book = Book.objects.get(pk=primary_key)
except Book.DoesNotExist:
raise Http404('Book does not exist')
return render(request, 'catalog/book_detail.html', context={'book': book})
</pre>
<p>La vista prima cerca di ottenere il record del libro specifico dal modello. Se questo fallisce, la vista dovrebbe sollevare un'eccezione Http404 per indicare che il libro è "non trovato". Il passo finale è quindi, come al solito, chiamare render () con il nome del modello e i dati del libro nel parametro di contesto (come dizionario).</p>
<p>In alternativa, possiamo usare la funzione <code>get_object_or_404()</code> come scorciatoia per sollevare un'eccezione <code>Http404</code> se il record non viene trovato.</p>
<pre class="brush: python">from django.shortcuts import get_object_or_404
def book_detail_view(request, primary_key):
book = get_object_or_404(Book, pk=primary_key)
return render(request, 'catalog/book_detail.html', context={'book': book})</pre>
<h3 id="Creare_il_template_per_la_vista_dettaglio">Creare il template per la vista dettaglio</h3>
<p>Crea il file HTML <strong>/locallibrary/catalog/templates/catalog/book_detail.html</strong> ed inserisci il seguente contenuto. come discusso precedentmente, questo nome file di default per il template è quello atteso dalla generica class-based <em>detail</em> view (per un modello di nome <code>Book</code> in una applicazione di nome <code>catalog</code>).</p>
<pre class="brush: html">{% extends "base_generic.html" %}
{% block content %}
<h1>Title: \{{ book.title }}</h1>
<p><strong>Author:</strong> <a href="">\{{ book.author }}</a></p> <!-- author detail link not yet defined -->
<p><strong>Summary:</strong> \{{ book.summary }}</p>
<p><strong>ISBN:</strong> \{{ book.isbn }}</p>
<p><strong>Language:</strong> \{{ book.language }}</p>
<p><strong>Genre:</strong> {% for genre in book.genre.all %} \{{ genre }}{% if not forloop.last %}, {% endif %}{% endfor %}</p>
<div style="margin-left:20px;margin-top:20px">
<h4>Copies</h4>
{% for copy in book.bookinstance_set.all %}
<hr>
<p class="{% if copy.status == 'a' %}text-success{% elif copy.status == 'm' %}text-danger{% else %}text-warning{% endif %}">\{{ copy.get_status_display }}</p>
{% if copy.status != 'a' %}
<p><strong>Due to be returned:</strong> \{{copy.due_back}}</p>
{% endif %}
<p><strong>Imprint:</strong> \{{copy.imprint}}</p>
<p class="text-muted"><strong>Id:</strong> \{{copy.id}}</p>
{% endfor %}
</div>
{% endblock %}</pre>
<ul>
</ul>
<div class="note">
<p>Il link dell'autore nel template sopra ha un URL vuoto perché non abbiamo ancora creato una pagina dei dettagli dell'autore. Una volta che esisterà, dovresti aggiornare l'URL in questo modo:</p>
<pre><a href="<strong>{% url 'author-detail' book.author.pk %}</strong>">\{{ book.author }}</a>
</pre>
</div>
<p>Anche se un po 'più grande, quasi tutto in questo template è stato descritto in precedenza:</p>
<ul>
<li>Estendiamo il nostro template di base e facciamo l'override del blocco "content".</li>
<li>Utilizziamo l'elaborazione condizionale per determinare se visualizzare o meno il contenuto specifico.</li>
<li>Usiamo i loop per scorrere gli elenchi di oggetti.</li>
<li>Accediamo ai campi di context usando la notazione dot (poiché abbiamo usato la vista generica di dettaglio, il context è denominato <code>book</code>, potremmo anche usare "<code>object</code>")</li>
</ul>
<p>Prima non abbiamo visto la funzione interessante <code>book.bookinstance_set.all()</code>. Questo metodo viene auto-magicamente creato da Django per restituire un set di record <code>BookInstance</code> associati con un particolare <code>Book</code>.</p>
<pre class="brush: python">{% for copy in book.bookinstance_set.all %}
<!-- code to iterate across each copy/instance of a book -->
{% endfor %}</pre>
<p>Questo metodo è necessario perchè hai dichiarato una <code>ForeignKey</code> (uno-a-molti) solamente da una parte della relazione. Poichè non hai fatto nulla per dichiarare la relazione negli altri ("molti") modelli, non ci sono alcun campo da cui prendere il set di record associati. Per superare questo problema, Django costruisce un appropriata funzione di nome "reverse lookup" (ricerca inversa) che puoi usare. Il nome della funzione viene costruito con le lettere minuscole del modello in cui la <code>ForeignKey</code> è stata dichiarata, seguita da <code>_set</code> (ovvero la funzione creata in <code>Book</code> è <code>bookinstance_set()</code>).</p>
<div class="note">
<p><strong>Nota</strong>: Qui usiamo <code>all()</code> per ottenere tutti i record (di default). Anche se puoi usare il metodo <code>filter()</code> per ricevere un sottoinsieme di record nel tuo codice, non puoi farlo direttamente nei template perchè non puoi specificare argomenti nelle funzioni.</p>
<p>Fai attenzione anche a non definire un ordine (sulla tua vista class-based o model), altrimenti vedrai anche degli errori dal server di sviluppo come questo:</p>
<pre>[29/May/2017 18:37:53] "GET /catalog/books/?page=1 HTTP/1.1" 200 1637
/foo/local_library/venv/lib/python3.5/site-packages/django/views/generic/list.py:99: UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list: <QuerySet [<Author: Ortiz, David>, <Author: H. McRaven, William>, <Author: Leigh, Melinda>]>
allow_empty_first_page=allow_empty_first_page, **kwargs)
</pre>
<p>Ciò si verifica perché <a href="https://docs.djangoproject.com/en/2.1/topics/pagination/#paginator-objects">paginator object</a> si aspetta di vedere alcuni ORDER BY eseguiti sul database sottostante. Senza di esso, non può essere sicuro che i record siano restituiti effettivamente nell'ordine corretto! </p>
<p>In questo tutorial non abbiamo ancora visto <strong>Pagination</strong> (ancora, ma presto), ma poichè non puoi utilizzare <code>sort_by()</code> e passare un parametro, (stessa cosa con <code>filter()</code>) dovrai scegliere tra tre strade:</p>
<ol>
<li>Aggiungere un <code>ordering</code> dentro una dichiarazione <code>class Meta</code> nel tuo modello.</li>
<li>Aggiungere un attibuto <code>queryset</code> nella tua view custom class-based, specificando un <code>order_by()</code>.</li>
<li>Aggiungere un metodo <code>get_queryset</code> alla tua view custom class-based e specificando un <code>order_by()</code>.</li>
</ol>
<p>Se decidi di usare una classe Meta per il model Author (probabilmente non così flessibile come personalizzare la vista basata sulla classe, ma abbastanza facile), ti ritroverai con qualcosa di simile a questo</p>
<pre>class Author(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
date_of_birth = models.DateField(null=True, blank=True)
date_of_death = models.DateField('Died', null=True, blank=True)
def get_absolute_url(self):
return reverse('author-detail', args=[str(self.id)])
def __str__(self):
return f'{self.last_name}, {self.first_name}'
<strong> class Meta:
ordering = ['last_name']</strong></pre>
<p>Ovviamente, il campo non necessita di essere un <code>last_name</code>: può essere qualunque altro.</p>
<p>E per ultimo, ma non meno importante, dovresti ordinare un attributo/colonna che abbia effettivamente un indice (unico o meno) sul tuo database per evitare problemi di prestazioni. Ovviamente, questo non sarà necessario qui, con così pochi libri (e utenti!), ma è qualcosa da tenere a mente per i progetti futuri.</p>
</div>
<h2 id="Come_viene_visualizzato">Come viene visualizzato?</h2>
<p>A questo punto, avremmo dovuto creare tutto il necessario per visualizzare sia l'elenco dei libri sia le pagine di dettaglio dei libri. Lancia il comando (<code>python3 manage.py runserver</code>) ed apri sul tuo browser <a href="http://127.0.0.1:8000/">http://127.0.0.1:8000/</a>.</p>
<div class="warning">
<p><strong>Warning: </strong>Non fare ancora clic su nessun link di autore o di dettaglio dell'autore: creerai quelli nella sfida!</p>
</div>
<p>Click su <strong>All books</strong> per vedere la lista di tutti i libri. </p>
<p><img alt="Book List Page" src="https://mdn.mozillademos.org/files/14049/book_list_page_no_pagination.png" style="border-style: solid; border-width: 1px; display: block; height: 216px; margin: 0px auto; width: 823px;"></p>
<p>Quindi fai clic su un link a uno dei tuoi libri. Se tutto è impostato correttamente, dovresti vedere qualcosa come il seguente screenshot.</p>
<p><img alt="Book Detail Page" src="https://mdn.mozillademos.org/files/14051/book_detail_page_no_pagination.png" style="border-style: solid; border-width: 1px; display: block; height: 783px; margin: 0px auto; width: 926px;"></p>
<h2 id="Impaginazione">Impaginazione</h2>
<p>Se hai appena qualche record, la nostra pagina di elenco dei libri sembrerà a posto. Tuttavia, inserendo decine o centinaia di record la pagina impiegherà più tempo a caricarsi (e avrà troppi contenuti per navigare in modo ragionevole). La soluzione a questo problema è di aggiungere l'impaginazione alle visualizzazioni della lista, riducendo il numero di elementi visualizzati su ciascuna pagina.</p>
<p>Django ha un eccellente supporto per l'impaginazione built-in. Ancora meglio, questo è incorporato nelle view lista generiche basate su classe, quindi non devi fare molto per abilitarlo!</p>
<h3 id="Views">Views</h3>
<p>Apri <strong>catalog/views.py</strong>, ed aggiungi la riga di codice <code>paginate_by</code> mostrata sotto.</p>
<pre class="brush: python">class BookListView(generic.ListView):
model = Book
<strong>paginate_by = 10</strong></pre>
<p>Con questa aggiunta, non appena si hanno più di 10 record, la vista inizierà a impaginare i dati che invia al modello. Si accede alle diverse pagine usando i parametri GET - per accedere alla pagina 2 si utilizzerà l'URL: <code>/catalog/books/<strong>?page=2</strong></code>.</p>
<h3 id="Templates">Templates</h3>
<p>Ora che i dati sono impaginati, è necessario aggiungere il supporto al template per scorrere il set di risultati. Poiché potremmo volerlo fare in tutte le view elenco, lo faremo in un modo che possa essere aggiunto al template base.</p>
<p>Apri <strong>/locallibrary/catalog/templates/<em>base_generic.html</em></strong> e copiaci dentro il seguente blocco di paginazione (evidenziato in grassetto qui in basso) sotto il nostro block content. Il codice controlla innanzitutto se l'impaginazione è abilitata nella pagina corrente. In tal caso, aggiunge i collegamenti successivo e precedente se appropriato (e il numero di pagina corrente).</p>
<pre class="brush: python">{% block content %}{% endblock %}
<strong>{% block pagination %}
{% if is_paginated %}
<div class="pagination">
<span class="page-links">
{% if page_obj.has_previous %}
<a href="\{{ request.path }}?page=\{{ page_obj.previous_page_number }}">previous</a>
{% endif %}
<span class="page-current">
<p>Page \{{ page_obj.number }} of \{{ page_obj.paginator.num_pages }}.</p>
</span>
{% if page_obj.has_next %}
<a href="\{{ request.path }}?page=\{{ page_obj.next_page_number }}">next</a>
{% endif %}
</span>
</div>
{% endif %}
{% endblock %} </strong></pre>
<p>Il <code>page_obj</code> è un oggetto <a href="https://docs.djangoproject.com/en/2.1/topics/pagination/#paginator-objects">Paginator</a> che esisterà se la paginazione viene utilizzata nella pagina corrente. Ti permette di ottenere tutte le informazioni sulla pagina corrente, le pagine precedenti, quante pagine ci sono, ecc.</p>
<p>Usiamo <code>\{{ request.path }}</code> per ottenere l'URL della pagina corrente per la creazione dei collegamenti di paginazione. Questo è utile perché è indipendente dall'oggetto che stiamo impaginando.</p>
<p>Ecco fatto!</p>
<h3 id="Come_viene_visualizzato_2">Come viene visualizzato?</h3>
<p>Lo screenshot qui sotto mostra l'aspetto della paginazione: se non hai inserito più di 10 titoli nel tuo database, puoi testarlo più facilmente abbassando il numero specificato in <code>paginate_by.</code></p>
<p>I link di impaginazione sono visualizzati in basso, con i link successivo / precedente visualizzati a seconda della pagina in cui ti trovi.</p>
<p><img alt="Book List Page - paginated" src="https://mdn.mozillademos.org/files/14057/book_list_paginated.png" style="border-style: solid; border-width: 1px; display: block; height: 216px; margin: 0px auto; width: 924px;"></p>
<h2 id="Sfida_te_stesso">Sfida te stesso</h2>
<p>La sfida in questo articolo è di creare le view di dettaglio e le view di elenco dell'autore richieste per completare il progetto. Questi dovrebbero essere resi disponibili ai seguenti URL:</p>
<ul>
<li><code>catalog/authors/</code> — lista di tutti gli authors.</li>
<li><code>catalog/author/<em><id></em></code><em> </em>— Vista di dettaglio dell'autore con chiave primaria <em><code><id></code></em></li>
</ul>
<p>Il codice richiesto per i mappatori di URL e le viste dovrebbe essere praticamente identico all'elenco di libri e alle viste di dettaglio che abbiamo creato sopra. I modelli saranno diversi ma condivideranno un comportamento simile.</p>
<div class="note">
<p><strong>Note</strong>:</p>
<ul>
<li>Una volta creato il mapper URL per la pagina di elenco dell'autore, sarà necessario aggiornare il collegamento <strong>Tutti gli autori</strong> nel modello di base. Segui lo stesso processo che abbiamo fatto quando abbiamo aggiornato il link <strong>Tutti i libri.</strong></li>
<li>Una volta creato il mapper URL per la pagina dei dettagli dell'autore, è necessario aggiornare anche il <a href="#Creating_the_Detail_View_template">template della vista dettagliata dei libri</a> (<strong>/locallibrary/catalog/templates/catalog/book_detail.html</strong>) in modo che il link dell'autore punti alla nuova pagina dei dettagli dell'autore (anziché essere un URL vuoto). La linea cambierà per aggiungere il tag template mostrato in grassetto sotto.
<pre class="brush: html"><p><strong>Author:</strong> <a href="<strong>{% url 'author-detail' book.author.pk %}</strong>">\{{ book.author }}</a></p>
</pre>
</li>
</ul>
</div>
<p>Quando hai finito, le tue pagine dovrebbero apparire come gli screenshot qui sotto.</p>
<p><img alt="Author List Page" src="https://mdn.mozillademos.org/files/14053/author_list_page_no_pagination.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p>
<ul>
</ul>
<p><img alt="Author Detail Page" src="https://mdn.mozillademos.org/files/14055/author_detail_page_no_pagination.png" style="border-style: solid; border-width: 1px; display: block; height: 358px; margin: 0px auto; width: 825px;"></p>
<ul>
</ul>
<h2 id="Sommario">Sommario</h2>
<p>Congratulazioni, la nostra funzionalità di libreria di base è ora completa!</p>
<p>In questo articolo, abbiamo imparato come utilizzare la lista generica basata sulla classe e le viste di dettaglio e li abbiamo usati per creare pagine per visualizzare i nostri libri e autori. Lungo la strada abbiamo imparato a conoscere la corrispondenza dei modelli con le espressioni regolari e come puoi passare i dati dagli URL alle tue visualizzazioni. Abbiamo anche imparato qualche altro trucco per l'utilizzo dei modelli. Infine, abbiamo mostrato come impaginare le visualizzazioni degli elenchi in modo che le nostre liste siano gestibili anche quando abbiamo molti record.</p>
<p>Nei nostri prossimi articoli, estenderemo questa libreria per supportare gli account utente, dimostrando in tal modo l'autenticazione dell'utente, permissons, sessioni e moduli.</p>
<h2 id="Vedi_anche">Vedi anche</h2>
<ul>
<li><a href="https://docs.djangoproject.com/en/2.1/topics/class-based-views/generic-display/">Built-in class-based generic views</a> (Django docs)</li>
<li><a href="https://docs.djangoproject.com/en/2.1/ref/class-based-views/generic-display/">Generic display views</a> (Django docs)</li>
<li><a href="https://docs.djangoproject.com/en/2.1/topics/class-based-views/intro/">Introduction to class-based views</a> (Django docs)</li>
<li><a href="https://docs.djangoproject.com/en/2.1/ref/templates/builtins">Built-in template tags and filters</a> (Django docs).</li>
<li><a href="https://docs.djangoproject.com/en/2.1/topics/pagination/">Pagination</a> (Django docs)</li>
</ul>
<p>{{PreviousMenuNext("Learn/Server-side/Django/Home_page", "Learn/Server-side/Django/Sessions", "Learn/Server-side/Django")}}</p>
<h2 id="In_questo_modulo">In questo modulo</h2>
<ul>
<li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li>
<li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li>
<li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li>
<li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li>
<li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li>
<li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li>
<li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li>
<li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li>
<li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li>
<li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li>
<li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li>
<li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li>
<li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li>
<li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li>
<li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li>
</ul>
|