Django mette a disposizione delle views per i metodi CRUD.
Appartengono ai moduli django.views.generic.*
.
È presente una classe View per ogni operazione CRUD:
CreateView
ListView
: elenca le entry di una tabella, ritornandolo comeQuerySet
in automaticoUpdateView
DeleteView
DetailView
from django.views.generic import ListView
class ListStudentsView(ListView):
model = Student
template_name = 'iscrizioni/stud_list.html'
Come rendere raggiungibile questa classe tramite l'url routing? #Nota a differenza dei precedenti esempi è una class view, non una function view
In path
inseriamo: path('studlist', views.ListStudentsView.as_view(), name='studlist')
Perché non specifichiamo il contesto? è ovvio dall'operazione che stiamo facendo. Il risultato è in object_list
: una variabile di contesto che contiene il risultato (come QuerySet) della ListView
.
Come con le function view, anche con le class view, posso fare preprocessing sul QuerySet
passato alla vista.
DaView
generiche sono ereditati i metodi:
get_queryset
: per fare operazioni sulQuerySet
ritornato dalla vista, dipendentemente dal modello selezionatoget_context_data
: per aggiungere variabili di contesto
Posso fare override dei metodi:
class ListaInsegnamentiAttivi(ListView):
model = Insegnamento
template_name = 'iscrizioni/insegnamenti_attivi.html'
def get_queryset(self):
return self.model.objects.exclude(studenti__isnull = True)
def get_context_data(self, *+kwargs):
context = super().get_context_data(**kwargs)
context['titolo'] = 'Insegnamenti Attivi'
return context
Posso assicurarmi di star facendo override del metodo con la notazione @override
offerta da Django.
Usando le view generiche di Django, otteniamo gratuitamente, all'interno del contesto, una variabile view
. Ovvero un riferimento alla view class dalla quale stiamo rispondendo. Possiamo quindi chiamare dalla vista i metodi della classe.
Dal template non posso chiamare metodi con argomenti (escluso self
), per mantenere il paradigma MTV ben delineato.
È una view pre-confezionata che permette di creare entry per una tabella.
Come al solito, devo specificare model
e template
.
In più:
fields
posto uguale ad una lista contenente i campi della relazione da compilare, oppure'__all__'
success_url = reverse_lazy('iscrizioni:listastudenti'
. La funzionereverse_lazy
inibisce la lazy evaluation dell'endpoint specificato
Esiste un'altra funzione simile: reverse
Questa funzione ha la stessa firma di reverse_lazy
, ma si usa come valore di ritorno dai metodi.
La ragione per cui esistono queste funzioni risiede nella lazy evaluation delle classi in Python. Infatti, per valutare un attributo di istanza, è necessario eseguire il corpo della funzione; questo può avvenire in momenti diversi a seconda dell'implementazione.
Lato view, abbiamo delle utility già fatte:
<form method='post'> {% csrf_token %}
{{ form.as_p }}
<input type='sumbit' value'Save'>
</form>
Perché post? con GET alcuni tipi di dato non possono essere passati. Eg. files.
Il dizionario con cui ottenere parametri passati con metodo POST può essere acceduto con request.POST['name']
Cos'è csrf_token
? È un meccanismo di sicurezza che siamo obbligati ad utilizzare nel DTL. Serve per evitare Cross Site Reference Forgery. Si tratta di un token associato al form, ottenuto in base all'utente che sta utilizzando il sito; l'identificazione può avvenire mediante sessione o autenticazione. È gestito dal Django middleware.
Il controllo sui vincoli dei campi è sia lato client che lato server.
#Vedi differenze tra GET e POST: bookmarking, caching, idempotenza
Ha un comportamento simile alla ListView, ma ritorna un dettaglio, ovvero una sola entry della relazione. L'elemento è specificato tramite url path.
path('studente/<pk>', ...)
class InsegnamentoView(DetailView):
model = Insegnamento
template_name = 'iscrizioni/insegnamento.html'
Ritorna una vista che presenta un form precompilato, mediante il quale sono modificabili alcune celle della entry. L'elemento è specificato con url path.
class UpddateInsegnamentoView(UpdateView):
model = Insegnamento
template_name = 'iscrizioni/edit_insegnamento.html'
fields = '__all__'
def get_success_url(self):
pk = self.get_context_data()['object'].pk
return reverse('iscrizioni:insegnamento', kwargs={'pk'=pk})
Similmente a update a detail, l'elemento da eliminare è specificato mediante url path.
class DeleteEntitaView(DeleteView):
template_name = 'iscrizioni/cancella_studente.html'
def get_context_data(self, **kwargs):
ctx = super().get_context_data()
entita = 'Studente' if self.model == Studenti else 'Insegnante'
ctx['entita'] = entita
return ctx
def get_success_url(self):
url = 'iscrizioni:lista_insegnamenti'if self.model == Insegnamento else 'iscrizioni:lista_studenti'
return reverse(url)
Ad esempio, ritornare elementi filtrati secondo un criterio passato nell'url path, può essere fatto definendo un metodo annidato nella class view.
def get_queryset(self):
surname = self.kwargs['cognome']
# filter
# and then return