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 wcontextdostę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 lubNonejeśli nie ma stronicowaniapage_obj: obiekt strony, lubNone
allow_empty: True/False. Interesujący parametr. Jeśli ustawiony naFalsei 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 HTTPPOSTi przetwarza dane wprowadzone przez użytkownika. Tworzy nowy obiektNotena 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-exampleget_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_urlobiektu.success_urlto 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_classwskazuje, 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. WCreateViewstosuje sięmodeli Django samo generuje formularz.get: obsługuje żądania HTTPGETi 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 HTTPPOSTi 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 obiektuNotedo 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 HTTPGETi 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 HTTPPOSTi przeprowadza faktyczne usunięcie obiektu. Po usunięciu przekierowuje użytkownika na stronę określoną przez atrybutsuccess_urllub 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!