Django
Widoki oparte na klasach
Szukaj…
Uwagi
Podczas korzystania z CBV często musimy dokładnie wiedzieć, jakie metody możemy zastąpić dla każdej klasy ogólnej. Ta strona dokumentacji django zawiera listę wszystkich klas ogólnych wraz ze spłaszczonymi metodami oraz atrybutami klas, których możemy użyć.
Ponadto strona internetowa Classy Class Based View zapewnia te same informacje z ładnym interaktywnym interfejsem.
Widoki klasowe
Widoki oparte na klasach pozwalają skupić się na tym, co czyni Twoje widoki wyjątkowymi.
Statyczne informacje o stronie mogą nie mieć nic specjalnego oprócz użytego szablonu. Użyj TemplateView ! Wszystko, co musisz zrobić, to ustawić nazwę szablonu. Zadanie wykonane. Kolejny.
views.py
from django.views.generic import TemplateView
class AboutView(TemplateView):
template_name = "about.html"
urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url('^about/', views.AboutView.as_view(), name='about'),
]
Zauważ, że nie używamy bezpośrednio AboutView
w AboutView
URL. Jest tak, ponieważ oczekuje się as_view()
i właśnie to as_view()
.
Dane kontekstowe
Czasami twój szablon potrzebuje trochę więcej informacji. Na przykład chcielibyśmy mieć użytkownika w nagłówku strony, z linkiem do jego profilu obok linku wylogowania. W takich przypadkach użyj metody get_context_data
.
views.py
class BookView(DetailView):
template_name = "book.html"
def get_context_data(self, **kwargs)
""" get_context_data let you fill the template context """
context = super(BookView, self).get_context_data(**kwargs)
# Get Related publishers
context['publishers'] = self.object.publishers.filter(is_active=True)
return context
Musisz wywołać metodę get_context_data dla superklasy, a ona zwróci domyślną instancję kontekstu. Każdy element dodany do tego słownika będzie dostępny w szablonie.
book.html
<h3>Active publishers</h3>
<ul>
{% for publisher in publishers %}
<li>{{ publisher.name }}</li>
{% endfor %}
</ul>
Widoki listy i szczegółów
Widoki szablonów są odpowiednie dla stron statycznych i można ich używać do wszystkiego z get_context_data
ale byłoby to niewiele lepsze niż używanie funkcji jako widoków.
Wejdź w ListView i DetailView
app / models.py
from django.db import models
class Pokemon(models.Model):
name = models.CharField(max_length=24)
species = models.CharField(max_length=48)
slug = models.CharField(max_length=48)
app / views.py
from django.views.generic import ListView, DetailView
from .models import Pokemon
class PokedexView(ListView):
""" Provide a list of Pokemon objects """
model = Pokemon
paginate_by = 25
class PokemonView(DetailView):
model = Pokemon
To wszystko, czego potrzebujesz, aby wygenerować widok z listą wszystkich obiektów modeli i widoków pojedynczego elementu. Lista jest nawet paginowana. Możesz podać template_name
jeśli chcesz coś konkretnego. Domyślnie jest generowany na podstawie nazwy modelu.
app / templates / app / pokemon_list.html
<!DOCTYPE html>
<title>Pokedex</title>
<ul>{% for pokemon in pokemon_list %}
<li><a href="{% url "app:pokemon" pokemon.pk %}">{{ pokemon.name }}</a>
– {{ pokemon.species }}
</ul>
Kontekst jest wypełniony listą obiektów pod dwiema nazwami, object_list
i drugą object_list
z nazwy modelu, tutaj pokemon_list
. Jeśli paginujesz listę, musisz również zadbać o następny i poprzedni link. Obiekt Paginator może w tym pomóc, jest również dostępny w danych kontekstowych.
app / templates / app / pokemon_detail.html
<!DOCTYPE html>
<title>Pokemon {{ pokemon.name }}</title>
<h1>{{ pokemon.name }}</h1>
<h2>{{ pokemon.species }} </h2>
Tak jak poprzednio, kontekst jest zapełniany obiektem modelu pod nazwą object
i pokemon
, przy czym drugi pochodzi od nazwy modelu.
app / urls.py
from django.conf.urls import url
from . import views
app_name = 'app'
urlpatterns = [
url(r'^pokemon/$', views.PokedexView.as_view(), name='pokedex'),
url(r'^pokemon/(?P<pk>\d+)/$', views.PokemonView.as_view(), name='pokemon'),
]
W tym fragmencie adres URL widoku szczegółowego jest tworzony przy użyciu klucza podstawowego. Można również użyć ślimaka jako argumentu. Daje to ładniej wyglądający adres URL, który jest łatwiejszy do zapamiętania. Wymaga to jednak obecności w twoim polu pola o nazwie ślimak.
url(r'^pokemon/(?P<slug>[A-Za-z0-9_-]+)/$', views.PokemonView.as_view(), name='pokemon'),
Jeśli pole zwany slug
nie jest obecny, można użyć slug_field
ustawienia w DetailView
do punktu na innym polu.
Do paginacji użyj parametrów pobierania strony lub umieść stronę bezpośrednio w adresie URL.
Tworzenie formularzy i obiektów
Pisanie widoku w celu stworzenia obiektu może być dość nudne. Musisz wyświetlić formularz, musisz go zweryfikować, musisz zapisać element lub zwrócić formularz z błędem. Chyba że użyjesz jednego z ogólnych widoków edycji .
app / views.py
from django.core.urlresolvers import reverse_lazy
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from .models import Pokemon
class PokemonCreate(CreateView):
model = Pokemon
fields = ['name', 'species']
class PokemonUpdate(UpdateView):
model = Pokemon
fields = ['name', 'species']
class PokemonDelete(DeleteView):
model = Pokemon
success_url = reverse_lazy('pokedex')
CreateView
i UpdateView
mają dwa wymagane atrybuty, model
i fields
. Domyślnie oba używają nazwy szablonu opartej na nazwie modelu z przyrostkiem „_form”. Możesz zmienić tylko przyrostek za pomocą atrybutu nazwa_szablonu_sufiks. DeleteView pokazuje komunikat potwierdzający przed usunięciem obiektu.
Zarówno UpdateView
jak i DeleteView
muszą pobierać na obiekcie. Używają tej samej metody co DetailView
, wydobywając zmienną z DetailView
URL i dopasowując pola obiektu.
app / templates / app / pokemon_form.html (rozpakuj)
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Save" />
</form>
form
zawiera formularz ze wszystkimi potrzebnymi polami. Tutaj będzie wyświetlany akapit dla każdego pola z powodu as_p
.
app / templates / app / pokemon_confirm_delete.html (rozpakuj)
<form action="" method="post">
{% csrf_token %}
<p>Are you sure you want to delete "{{ object }}"?</p>
<input type="submit" value="Confirm" />
</form>
Tag csrf_token
jest wymagany ze względu na ochronę django przed fałszowaniem żądań. Akcja atrybutu pozostaje pusta, ponieważ adres URL wyświetlający formularz jest taki sam, jak adres obsługujący usuwanie / zapisywanie.
Z modelem pozostają dwa problemy, jeśli używasz go tak samo jak z listą i przykładami szczegółów. Po pierwsze, tworzenie i aktualizacja będą narzekać na brakujący adres przekierowania. Można to rozwiązać, dodając get_absolute_url
do modelu get_absolute_url
. Drugi problem to potwierdzenie usunięcia, które nie wyświetla istotnych informacji. Aby rozwiązać ten problem, najłatwiejszym rozwiązaniem jest dodanie reprezentacji ciągu.
app / models.py
from django.db import models
from django.urls import reverse
from django.utils.encoding import python_2_unicode_compatible
@python_2_unicode_compatible
class Pokemon(models.Model):
name = models.CharField(max_length=24)
species = models.CharField(max_length=48)
def get_absolute_url(self):
return reverse('app:pokemon', kwargs={'pk':self.pk})
def __str__(self):
return self.name
Dekorator klasy upewni się, że wszystko działa poprawnie w Pythonie 2.
Minimalny przykład
views.py :
from django.http import HttpResponse
from django.views.generic import View
class MyView(View):
def get(self, request):
# <view logic>
return HttpResponse('result')
urls.py :
from django.conf.urls import url
from myapp.views import MyView
urlpatterns = [
url(r'^about/$', MyView.as_view()),
]
Dowiedz się więcej o dokumentacji Django »
Widoki oparte na klasach Django: Przykład CreateView
Dzięki widokom ogólnym opartym na klasach tworzenie widoków CRUD z naszych modeli jest bardzo proste i łatwe. Często wbudowany administrator Django nie jest wystarczający lub nie jest preferowany i musimy stworzyć własne widoki CRUD. W takich przypadkach CBV mogą być bardzo przydatne.
Klasa CreateView
potrzebuje 3 rzeczy - modelu, pól do użycia i CreateView
URL sukcesu.
Przykład:
from django.views.generic import CreateView
from .models import Campaign
class CampaignCreateView(CreateView):
model = Campaign
fields = ('title', 'description')
success_url = "/campaigns/list"
Po pomyślnym utworzeniu użytkownik zostaje przekierowany na success_url
. Możemy również zdefiniować metodę get_success_url
zamiast tego i użyć reverse
lub reverse_lazy
aby uzyskać adres URL sukcesu.
Teraz musimy utworzyć szablon dla tego widoku. Szablon powinien mieć nazwę <app name>/<model name>_form.html
. Nazwa modelu musi być zapisana małymi literami. Na przykład, jeśli nazwa mojej aplikacji to dashboard
, to dla powyższego widoku tworzenia muszę utworzyć szablon o nazwie dashboard/campaign_form.html
.
W szablonie zmienna form
zawierałaby formularz. Oto przykładowy kod szablonu:
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Save" />
</form>
Czas dodać widok do naszych wzorców adresów URL.
url('^campaign/new/$', CampaignCreateView.as_view(), name='campaign_new'),
Jeśli odwiedzimy adres URL, powinniśmy zobaczyć formularz z wybranymi polami. Po przesłaniu spróbuje utworzyć nową instancję modelu z danymi i zapisać ją. Po sukcesie użytkownik zostanie przekierowany do adresu URL sukcesu. W przypadku błędów formularz zostanie wyświetlony ponownie z komunikatem o błędzie.
Jeden widok, wiele formularzy
Oto szybki przykład użycia wielu formularzy w jednym widoku Django.
from django.contrib import messages
from django.views.generic import TemplateView
from .forms import AddPostForm, AddCommentForm
from .models import Comment
class AddCommentView(TemplateView):
post_form_class = AddPostForm
comment_form_class = AddCommentForm
template_name = 'blog/post.html'
def post(self, request):
post_data = request.POST or None
post_form = self.post_form_class(post_data, prefix='post')
comment_form = self.comment_form_class(post_data, prefix='comment')
context = self.get_context_data(post_form=post_form,
comment_form=comment_form)
if post_form.is_valid():
self.form_save(post_form)
if comment_form.is_valid():
self.form_save(comment_form)
return self.render_to_response(context)
def form_save(self, form):
obj = form.save()
messages.success(self.request, "{} saved successfully".format(obj))
return obj
def get(self, request, *args, **kwargs):
return self.post(request, *args, **kwargs)