Django
Klassbaserade vyer
Sök…
Anmärkningar
När vi använder CBV behöver vi ofta veta exakt vilka metoder vi kan skriva över för varje generisk klass. Denna sida med django-dokumentationen visar alla generiska klasser med alla sina metoder plattade och klassattribut som vi kan använda.
Dessutom ger webbplatsen Classy Class Based View samma information med ett trevligt interaktivt gränssnitt.
Klassbaserade vyer
Klassbaserade vyer låter dig fokusera på det som gör dina åsikter speciella.
En statisk sida om sidan kanske inte har något speciellt, förutom den använda mallen. Använd en mallvy ! Allt du behöver göra är att ange ett mallnamn. Jobbet färdig. Nästa.
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'),
]
Lägg märke till hur vi inte använder direkt AboutView
i url- AboutView
. Det beror på att en kalkylbar förväntas och det är exakt vad as_view()
returnerar.
Kontextdata
Ibland behöver din mall lite mer information. Vi vill till exempel ha användaren i sidhuvudet med en länk till sin profil bredvid utloggningslänken. I dessa fall använder get_context_data
metoden 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
Du måste ringa metoden get_context_data i superklassen och den kommer att returnera standardkontextinstansen. Alla objekt som du lägger till i denna ordlista kommer att vara tillgängliga för mallen.
book.html
<h3>Active publishers</h3>
<ul>
{% for publisher in publishers %}
<li>{{ publisher.name }}</li>
{% endfor %}
</ul>
Listor och detaljer
Mallvyer är bra för statisk sida och du kan använda dem för allt med get_context_data
men det skulle knappt vara bättre än att använda funktion som vyer.
Ange ListView och 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
Det är allt du behöver för att skapa en vy där alla dina objekt för modeller och vyer av enskilda objekt visas. Listan är till och med paginerad. Du kan ange template_name
om du vill ha något specifikt. Som standard genereras det från modellnamnet.
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>
Kontextet fylls med listan över objekt under två namn, object_list
och en andra bygger från modellnamnet, här pokemon_list
. Om du har paginerat listan måste du ta hand om nästa och föregående länk också. Paginator- objektet kan hjälpa till med det, det är tillgängligt i kontextdata också.
app / templates / app / pokemon_detail.html
<!DOCTYPE html>
<title>Pokemon {{ pokemon.name }}</title>
<h1>{{ pokemon.name }}</h1>
<h2>{{ pokemon.species }} </h2>
Som tidigare fylls sammanhanget med ditt modellobjekt under object
och pokemon
, den andra kommer från modellnamnet.
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'),
]
I det här utdraget byggs webbadressen för detaljvyn med den primära nyckeln. Det är också möjligt att använda en snigel som argument. Detta ger en finare url som är lättare att komma ihåg. Det kräver emellertid närvaron av ett fält som heter slug i din modell.
url(r'^pokemon/(?P<slug>[A-Za-z0-9_-]+)/$', views.PokemonView.as_view(), name='pokemon'),
Om ett fält som heter slug
inte finns, kan du använda slug_field
inställningen i DetailView
att peka på ett annat fält.
För pagination, använd en sida för att få parametrar eller lägg en sida direkt i url-adressen.
Form och objekt skapande
Att skriva en vy för att skapa objekt kan vara ganska tråkigt. Du måste visa ett formulär, du måste bekräfta det, du måste spara objektet eller returnera formuläret med ett fel. Om du inte använder en av de generiska redigeringsvyerna .
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
och UpdateView
har två obligatoriska attribut, model
och fields
. Som standard använder båda ett mallnamn baserat på modellnamnet som är "fixat" av formen. Du kan bara ändra suffixet med attributet template_name_suffix. DeleteView visar ett bekräftelsemeddelande innan objektet tas bort.
Både UpdateView
och DeleteView
måste hämta på objekt. De använder samma metod som DetailView
, extraherar variabeln från url och matchar objektfälten.
app / mallar / app / pokemon_form.html (extrakt)
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Save" />
</form>
form
innehåller formuläret med alla fält som behövs. Här kommer det att visas med ett stycke för varje fält på grund av as_p
.
app / mallar / app / pokemon_confirm_delete.html (extrakt)
<form action="" method="post">
{% csrf_token %}
<p>Are you sure you want to delete "{{ object }}"?</p>
<input type="submit" value="Confirm" />
</form>
csrf_token
taggen krävs på grund av django-skydd mot förfalskning av begäran. Attributåtgärden lämnas tom eftersom webbadressen som visar formuläret är densamma som den som hanterar borttagningen / spara.
Två problem kvarstår med modellen, om de använder samma som med listan och exemplen på detaljer. Först skapar och uppdaterar klagomål om en saknad omdirigeringsadress. Det kan lösas genom att lägga till en get_absolute_url
till pokemonmodellen. Den andra frågan är att raderingsbekräftelsen inte visar meningsfull information. För att lösa detta är den enklaste lösningen att lägga till en strängrepresentation.
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
Klassdekoratören kommer att se till att allt fungerar smidigt under python 2.
Minimalt exempel
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()),
]
Läs mer om Django-dokumentation »
Django klassbaserade vyer: exempel på CreateView
Med klassbaserade generiska vyer är det mycket enkelt och enkelt att skapa CRUD-vyer från våra modeller. Ofta är den inbyggda Django-admin inte tillräckligt eller föredras och vi måste rulla våra egna CRUD-vyer. CBV: er kan vara mycket praktiska i sådana fall.
CreateView
behöver CreateView
saker - en modell, fälten som ska användas och framgångsadressen.
Exempel:
from django.views.generic import CreateView
from .models import Campaign
class CampaignCreateView(CreateView):
model = Campaign
fields = ('title', 'description')
success_url = "/campaigns/list"
När skapandet har lyckats omdirigeras användaren till success_url
. Vi kan också definiera en metod get_success_url
istället och använda reverse
eller reverse_lazy
att få framgångsadressen.
Nu måste vi skapa en mall för den här vyn. Mallen ska namnges i formatet <app name>/<model name>_form.html
. Modellnamnet måste vara i nedre lock. Till exempel, om mitt appnamn är dashboard
måste jag skapa en mall med dashboard/campaign_form.html
för ovanstående dashboard/campaign_form.html
.
I mallen, en form
skulle variabel innehåller formuläret. Här är ett exempelkod för mallen:
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Save" />
</form>
Nu är det dags att lägga till vyn i våra url-mönster.
url('^campaign/new/$', CampaignCreateView.as_view(), name='campaign_new'),
Om vi besöker URL: n bör vi se ett formulär med de fält vi valde. När vi skickar in kommer den att försöka skapa en ny instans av modellen med data och spara den. Vid framgång kommer användaren att omdirigeras till framgångsadressen. Vid fel kommer formuläret att visas igen med felmeddelandena.
En vy, flera formulär
Här är ett snabbt exempel på att använda flera former i en Django-vy.
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)