Zapraszam do kolejnego posta na temat widoków klasowych w Django. W poprzednim poście opisałem:
- najważniejszą metodę w widokach -
get_context_data
- widoki: TemplateView, DetailView, RedirectView.
W tym poście omówię:
- ListView
- CreateView
- FormView
- DeleteView
Cała seria postów jest rozwinięciem webinaru, w którym pokazałem jak szybko zbudować stronę internetową z wykorzystaniem CBV: Django w godzinę: Tworzenie aplikacji z Class Based Views.
Na sam początek należy zdefiniować model Note
(notatki), który będzie używany w przykładach.
# models.py
from django.db import models
# Create your models here.
class Note(models.Model):
title = models.CharField(max_length=255)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self) -> str:
return self.title
źródło: Własne: https://github.com/jacoor/django-w-godzine-webinar/
ListView
ListView
umożliwia proste wyświetlenie listy obiektów na stronie. Przykładem może być lista produktów w sklepie, lista uczniów w klasie, czy też lista książek w bibliotece.
# views.py
from django.views.generic import (
ListView
)
from django.urls import reverse_lazy
from .models import Note
class NoteListView(ListView):
model = Note
template_name = "notes_list.html"
{# note.html #}
<h1>Notatki</h1>
<ul>
{% for object in object_list %}
<li><a href="{% url 'note_detail' object.pk %}">{{object}}</a></li>
{% endfor %}
</ul>
żródło: Własne: https://github.com/jacoor/django-w-godzine-webinar/
Powyższy kod wyświetli na stronie wszystkie obiekty klasy Note
. Obiekty będą dostępne w szablonie pod standardową zmienną object_list
. Tę nazwę można zmienić poprzez atrybut context_object_name
.
Najważniejsze parametry i metody dostępne w ListView
:
get_context_data
- metoda pozwalająca na dodanie własnych danych do szablonu: https://akademiait.com.pl/class-based-views-w-django-wygodny-sposob-tworzenia-widokow-czesc-1/#get_context_datamodel
: nazwa modelu do pobrania z bazy. Domyślnie pobiera wszystkie obiekty, czylimodel.objects.all()
- metoda
get_queryset
: umożliwia zdefiniowanie własnego zapytania do bazy. Domyślnie, Django prosi o wszystkie obiekty modelu:model.objects.all()
. Użycie własnego queryset pozwala na przykład na sortowanie po cenie, nazwisku, tytule, lub wyszukiwanie. Co ciekawe, nie musi zwracać Queryset, wystarczy iterable, czyli obiekt iterowany w postaci listy. To z kolei umożliwia zwracanie danych na przykład różnych modeli: książek i czasopism. template_name
: nazwa szablonu, który będzie wykorzystany do wyświetlenia danychpaginate_by
: numer, określa ilość elementów na stronie jeśli chcemy korzystać ze stronicowania. Więcej informacji zawiera dokumentacja: https://docs.djangoproject.com/en/4.2/ref/class-based-views/mixins-multiple-object/#django.views.generic.list.MultipleObjectMixin.paginate_by. Warto spojrzeć na parametrypaginate_orphans
,page_kwarg
. Przy wykorzystaniu stronicowania wcontext
dostępne są dodatkowe obiekty, które umożliwiają pełną obsługę listy stron i przechodzenia między nimi:is_paginated
: True jeśli jest wykorzystane stronicowaniepaginator
: instancja paginatora lubNone
jeśli nie ma stronicowaniapage_obj
: obiekt strony, lubNone
allow_empty
: True/False. Interesujący parametr. Jeśli ustawiony naFalse
i w bazie nie ma obiektów do wyświetlenia, Django zwróci błąd404 Not Found
.
CreateView
CreateView
to klasa widoku w Django, która zapewnia łatwy sposób tworzenia nowych obiektów w bazie danych za pomocą formularza generowanego automagicznie przez Django na podstawie modelu. Wykorzystuje standardowe operacje HTTP, takie jak GET
i POST
, aby obsłużyć wyświetlanie formularza i przetwarzanie danych wprowadzonych przez użytkownika.
# views.py
from django.views.generic.edit import CreateView
from .models import Note
class NoteCreateView(CreateView):
model = Note
fields = ['title', 'content']
źródło: Własne: https://github.com/jacoor/django-w-godzine-webinar/
To cały kod widoku potrzebny do stworzenia strony do dodawania obiektu Note
! Klasa NoteCreateView
dziedziczy poCreateView
. Atrybut model
na Note
wskazuje, że ten widok będzie tworzył obiekty na podstawie modelu Note
. fields
określa, które pola z modelu Note
będą wyświetlane w formularzu. To, czy pole jest wymagane, oraz sposoby jego walidacji, określa model.
Po zaimplementowaniu klasy NoteCreateView
trzeba zmodyfikować plik urls.py
:
from django.urls import path
from .views import NoteCreateView
urlpatterns = [
path('note/create/', NoteCreateView.as_view(), name='note_create'),
]
żródło: Własne
W pliku note_form.html
dodaję formularz, który będzie wyświetlany dla użytkownika.
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Create Note</button>
</form>
źródło: Własne: https://github.com/jacoor/django-w-godzine-webinar/
Tag {% csrf_token %}
, zabezpiecza formularz przed atakami CSRF. Dzięki temu tylko zapytania wysłane z naszej strony zostaną wykonane. {{ form.as_p }}
z kolei wyświetla formularz w postaci akapitów.
Najważniejsze metody i parametry dostępne w CreateView
:
-
model
: nazwa modelu, który będzie bazą do stworzenia formularza. Parametr wymagany. -
get
: obsługuje żądania HTTP GET i wyświetla formularz. Wykorzystuje szablon{{nazwa_aplikacji}}/note_form.html
(o ile nie zostanie podana inna wartość dla atrybututemplate_name
). Bardzo rzadko wymaga modyfikacji. -
post
: obsługuje żądania HTTPPOST
i przetwarza dane wprowadzone przez użytkownika. Tworzy nowy obiektNote
na podstawie przesłanych danych i zapisuje go w bazie danych. Jeśli dane są poprawne, użytkownik zostanie przekierowany na stronę sukcesu (domyślnie nanote_detail.html
). Tej metody również najczęściej nie modyfikujemy. -
form_valid
: wywoływana po pomyślnym przetworzeniu formularza w metodziepost
. Tutaj możemy dostosować dodatkowe zachowanie, na przykład przypisać bieżącego użytkownika jako autora notatki lub wysłać maila z informacją o utworzeniu nowego obiektu (https://docs.djangoproject.com/en/4.2/topics/class-based-views/generic-editing/#models-and-request-user). Nie jest wymagana i rzadko modyfikowana. -
form_invalid
: Metoda wywoływana przy błędzie podczas przetwarzania danych formularza. Tutaj możemy dopisać dodatkowe informacje do błędu, wysłać maila z informacją o błędzie, itp. Również nie jest wymagana i rzadko modyfikowana. Dokumentacja: https://docs.djangoproject.com/en/4.2/topics/class-based-views/generic-editing/#content-negotiation-example -
get_success_url
: zwraca URL, na który zostanie przekierowany użytkownik po pomyślnym utworzeniu obiektu. Domyślnie przekierowuje na stronę szczegółów nowo utworzonego obiektu (note_detail.html
), korzystając z metodyget_absolute_url
obiektu.success_url
to parametr, który można zastosować zamiast metodyget_success_url
, może na przykład kierować do strony z listą notatek zamiast właśnie utworzonej notatki.
CreateView to bardzo prosty, a zarazem potężny widok. Django samo tworzy niezbędne formularze, obsługuje sprawdzenie poprawności wprowadzonych danych oraz zapis do bazy, dzięki czemu my możemy się skupić na logice aplikacji.
FormView
FormView
w Django jest używany do wyświetlania formularzy, przetwarzania danych wprowadzonych przez użytkownika i podejmowania akcji zależnych od wprowadzonych danych. Różnicą w porównaniu do CreateView
jest to, że w FormView
nie korzystamy bezpośrednio z modelu, a zdefiniowanego przez nas formularza.
Poniżej umieszczam kod formularza — warto zwrócić uwagę, że jest on niemal identyczny z kodem NoteCreateView
.
# forms.py
from django import forms
from .models import Note
class NoteForm(forms.ModelForm):
class Meta:
model = Note
fields = ('title', 'content')
Implementacja FormView
:
# views.py
from django.views.generic.edit import FormView
from .forms import NoteForm
class NoteCreateView(FormView):
form_class = NoteForm
template_name = 'note_form.html'
success_url = '/success/'
def form_valid(self, form):
form.save() # Zapisanie formularza do bazy danych
return super().form_valid(form)
źródło: Własne
Klasa NoteCreateView
dziedziczy po klasie FormView
. Atrybut form_class
wskazuje, który formularz będzie wykorzystany w widoku. Atrybut template_name
określa nazwę szablonu, który zostanie wyrenderowany dla tego widoku. success_url
wskazuje URL, na który zostanie przekierowany użytkownik po pomyślnym przetworzeniu formularza.
Teraz gdy mamy już zaimplementowany widok FormView
dla klasy NoteForm
, można przejść do wyświetlenia formularza w szablonie HTML. W pliku note_form.html
możemy dodać formularz, który będzie wyświetlany dla użytkownika.
{# note_form.html #}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Create Note</button>
</form>
Podobnie jak przy CreateView
używamy {% csrf_token %}
, aby zabezpieczyć formularz przed atakami CSRF, oraz {{ form.as_p }}
, aby wyświetlić pola formularza w uproszczonej postaci akapitów.
Pozostaje dodać widok do pliku urls.py
, co pozostawiam dla Was jako ćwiczenie.
Najważniejsze metody i parametry dostępne w FormView
są bardzo zbliżone CreateView
:
-
form_class
: wskazuje, który formularz będzie wykorzystany w widoku. Parametr wymagany. WCreateView
stosuje sięmodel
i Django samo generuje formularz. -
get
: obsługuje żądania HTTPGET
i wyświetla formularz. Wykorzystuje szablonnote_form.html
(o ile nie zostanie podana inna wartość dla atrybututemplate_name
). Bardzo rzadko wymaga modyfikacji. -
post
: obsługuje żądania HTTPPOST
i przetwarza dane wprowadzone przez użytkownika. Wykorzystuje formularzNoteForm
, a następnie wykonuje odpowiednie operacje w zależności od wyników. Bardzo rzadko wymaga modyfikacji. -
form_valid
: wywoływana po pomyślnym przetworzeniu formularza w metodziepost
. Tutaj można dostosować zachowanie, np. poprzez zapisanie obiektuNote
do bazy danych. -
form_invalid
: wywoływana, gdy przesłane dane formularza zawierają błędy. Można tutaj dostosować działania, na przykład ponownie wyrenderować formularz z informacjami zwrotnymi dla użytkownika. Ponieważ Django samo zapewnia obsługę błędów, metoda ta bardzo rzadko wymaga modyfikacji. -
get_success_url
: zwraca URL, na który zostanie przekierowany użytkownik po pomyślnym przetworzeniu formularza. W przykładzie powyżej przekierowowujemy użytkownika na/success/
(korzystając z parametrusuccess_url
)
DeleteView
DeleteView
jest używany do usuwania obiektu z bazy danych. Widok ten automatycznie wygeneruje potwierdzenie usunięcia i obsłuży żądania HTTP GET
i POST
związane z usunięciem obiektu.
Widok, umożliwiający usunięcie konkretnej notatki:
# views.py
from django.views.generic import DeleteView
from .models import Note
from django.urls import reverse_lazy
class NoteDeleteView(DeleteView):
model = Note
template_name = 'note_confirm_delete.html'
success_url = reverse_lazy('note_list')
Klasa NoteDeleteView
dziedziczy po klasie DeleteView
. Atrybut model
na Note
wskazuje, że ten widok będzie operował na obiektach tego modelu. Atrybut template_name
określa nazwę szablonu, który zostanie wyrenderowany dla tego widoku. success_url
wskazuje URL, na który zostanie przekierowany użytkownik po pomyślnym usunięciu obiektu.
Plik note_confirm_delete.html
zawiera kod HTML niezbędny do wykonania zadania:
{# note_confirm_delete.html #}
<h1>Czy na pewno chcesz usunąć tę notatkę?</h1>
<h2>{{object.title}}</h2>
<form method="post">
{% csrf_token %}
<button type="submit">Usuń</button>
</form>
Pozostaje dodać widok do pliku urls.py
, co pozostawiam dla Was jako ćwiczenie.
Powyższy kod HTML wyświetli prosty komunikat pytający użytkownika, czy na pewno chce usunąć notatkę, a poniżej formularz z jednym przyciskiem: "Usuń". Formularz jest wysyłany przy pomocy metody POST
, co znacznie zwiększa bezpieczeństwo aplikacji, dzięki zastosowaniu {% csrf_token %}
, który zabezpiecza przed atakami CSRF. Bez tego tokena, atakujący mógłby stworzyć skrypt, który po prostu wyśle wiele zapytań do naszej aplikacji w celu usunięcia wszystkich obiektów z bazy.
Najważniejsze metody i parametry DeleteView
to:
-
model
: nazwa modelu, którego obiekty będą usuwane. Parametr wymagany. -
get
: obsługuje żądania HTTPGET
i wyświetla potwierdzenie usunięcia. Wykorzystuje szablon{{nazwa_aplikacji}}/note_confirm_delete.html
(o ile nie zostanie podana inna wartość dla atrybututemplate_name
). Bardzo rzadko wymaga modyfikacji. -
post
: obsługuje żądania HTTPPOST
i przeprowadza faktyczne usunięcie obiektu. Po usunięciu przekierowuje użytkownika na stronę określoną przez atrybutsuccess_url
lub zwrócony przez metodęget_success_url
. Bardzo rzadko wymaga modyfikacji. -
get_object
: zwraca obiekt, który ma zostać usunięty. Możemy dostosować jej działanie, na przykład w celu uwzględnienia dodatkowych warunków lub filtrowania obiektów. Bardzo rzadko wymaga modyfikacji. -
get_success_url
: zwraca URL, na który zostanie przekierowany użytkownik po pomyślnym usunięciu obiektu. W przykładzie powyżej przekierowujemy użytkownika na listę notatek (note_list
).
W następnym poście na temat widoków klasowych (Class Based Views) przybliżę widoki wykorzystujące daty: ArchiveIndexView
, YearArchiveView
, MonthArchiveView
, WeekArchiveView
, DayArchiveView
, DateDetailView
- idealne narzędzie do tworzenia bloga. Niedługo!
Zapraszam do zadawania pytań przez formularz kontaktowy. Oczywiście, proponuję też samemu poeksperymentować z kodem. Jeśli natomiast potrzebujesz indywidualnych konsultacji, zapraszam do mentoringu
Spodobał Ci się post?
Podziel się nim!
Masz uwagi do posta, chcesz porozmawiać, szukasz pomocy z Pythonem i Django? Napisz do mnie!