Perkenalan ke tampilan berdasarkan-kelas¶
Tampilan berdasarkan-kelas menyediakan cara alternatif untuk menerapkan tampilan sebagai obyek Python daripada fungsi. Mereka tidak mengganti tampilan berdasarkan-fungsi, tetapi mempunyai perbedaan dan keuntungan tertentu ketika dibandingkan pada tampilan berdasarkan-fungsi:
- Kode organisasi terkait pada metode HTTP tertentu (
GET
,POST
, dll.) dapat dialamatkan oleh metode terpisah sebagai gantinya dari percabangan bersyarat. - Teknik-teknik berorientasi obyek seperti mixin (banyak warisan) dapat digunakan pada kode faktor kedalam komponen digunakan kembali.
Hubungan dan riwayat dari tampilan umum, tampilan berdasarkan-kelas, dan tampilan umum berdasarkan-kelas¶
Dalam permulaan ada hanya kontrak fungsi tampilan, Django melewatkan fungsi anda sebuah HttpRequest
dan berharap kembali sebuah HttpResponse
. Ini adalah perpanjangan dari apa Django sediakan.
Lebih awal pada itu telah dikenali dimana ada dialek umum dan pola ditemukan di pengembangan tampilan. Tampilan umum berdasarkan-fungsi telah diperkenalkan untuk meringkas pola ini dan pengembangan tampilan mudah untuk kasus-kasus umum.
The problem with function-based generic views is that while they covered the simple cases well, there was no way to extend or customize them beyond some configuration options, limiting their usefulness in many real-world applications.
Tampilan umum berdasarkan-kelas telah dibuat dengan tujuan sama sebagai tampilan umum berdasarkan-fungsi, untuk membuat tampilan pengembangan lebih mudah. Bagaimanapun, cara pemecahan diterapkan, melalui penggunaan dari mixin, menyediakan sebuah alat bantu yang menghasilkan di tampilan umum berdasarkan-kelas menjadi lebih diperpanjang dan lentur daripada pasangan berdasarkan-fungsi mereka.
If you have tried function based generic views in the past and found them lacking, you should not think of class-based generic views as a class-based equivalent, but rather as a fresh approach to solving the original problems that generic views were meant to solve.
The toolkit of base classes and mixins that Django uses to build class-based
generic views are built for maximum flexibility, and as such have many hooks in
the form of default method implementations and attributes that you are unlikely
to be concerned with in the simplest use cases. For example, instead of
limiting you to a class-based attribute for form_class
, the implementation
uses a get_form
method, which calls a get_form_class
method, which in
its default implementation returns the form_class
attribute of the class.
This gives you several options for specifying what form to use, from an
attribute, to a fully dynamic, callable hook. These options seem to add hollow
complexity for simple situations, but without them, more advanced designs would
be limited.
Menggunakan tampilan berdasarkan-kelas¶
Pada intinya, tampilan berdasarkan-kelas mengizinkan anda menanggapi ke permintaan HTTP berbeda dengan metode instance kelas berbeda, daripada dengan kode cabang bersyarat didalam fungsi tampilan tunggal.
Jadi dimana kode untuk menangani HTTP GET
di sebuah fungsi tampilan akan terlihat seperti:
from django.http import HttpResponse
def my_view(request):
if request.method == 'GET':
# <view logic>
return HttpResponse('result')
Di tampilan berdasarkan-kelas, ini akan menjadi:
from django.http import HttpResponse
from django.views import View
class MyView(View):
def get(self, request):
# <view logic>
return HttpResponse('result')
Because Django's URL resolver expects to send the request and associated
arguments to a callable function, not a class, class-based views have an
as_view()
class method which returns a
function that can be called when a request arrives for a URL matching the
associated pattern. The function creates an instance of the class, calls
setup()
to initialize its attributes, and
then calls its dispatch()
method.
dispatch
looks at the request to determine whether it is a GET
,
POST
, etc, and relays the request to a matching method if one is defined,
or raises HttpResponseNotAllowed
if not:
# urls.py
from django.urls import path
from myapp.views import MyView
urlpatterns = [
path('about/', MyView.as_view()),
]
Itu perlu dicatat bahwa apa metode anda kembalikan mirip ke apa anda kembalikan dari tampilan berdasarkan-fungsi, yaitu beberapa formulir dari HttpResponse
. Ini berarti bahwa obyek http shortcuts atau TemplateResponse
sah digunakan didalam tampilan berdasarkan-kelas.
Selagi tampilan berdasarkan-kelas paling rendah tidak membutuhkan atribut kelas apapun untuk melakukan pekerjaannya, atribut kelas berguna di banyak perancangan berdasarkan-kelas, dan ada dua cara mengkonfigurasi atau mensetel atribut kelas.
Pertama adalah cara Python standar dari mensubkelaskan dan menimpa atribut dan metode di subkelas. Sehingga jika induk anda mempunyai sebuah atribut greeting
seperti ini:
from django.http import HttpResponse
from django.views import View
class GreetingView(View):
greeting = "Good Day"
def get(self, request):
return HttpResponse(self.greeting)
Anda dapat menimpa itu di subkelas:
class MorningGreetingView(GreetingView):
greeting = "Morning to ya"
Pilihan lain adalah mengkonfigurasi atribut kelas sebagai argumen kata kunci pada panggailan as_view()
di URLconf:
urlpatterns = [
path('about/', GreetingView.as_view(greeting="G'day")),
]
Catatan
Selagi kelas anda diinstasiasikan untuk setiap permintaan dikirimkan ke itu, atribut kelas menyetel melalui titik masukan as_view()
dikonfigurasikan hanya sekali pada waktu URL anda diimpor.
Menggunakan mixin¶
Mixin adalah sebuah formulit dari banyak warisan dimana perilaku dan atribut dari banyak kelas-kelas induk dapat dipadukan
Sebagai contoh, di tampilan berdasarkan-kelas umum adalah sebuah mixin dipanggil TemplateResponseMixin
yang tujuan utamanya adalah menentukan metode render_to_response()
. Ketika memadukan dengan perilaku dari kelas dasar View
, hasil adalah kelas TemplateView
yang akan mengirim permintaan ke metode pencocokan sesuai (sebuah perilaku ditentukan di kelas dasar View
), dan itu mempunyai sebuah metode render_to_response()
yang menggunakan sebuah atribut template_name
untuk mengembalikan sebuah obyek TemplateResponse
(sebuah perilaku ditentukan di TemplateResponseMixin
).
Mixin adalah sebuah cara istimewa dari menggunakan kembali kode terhadap banyak kelas, tetapi mereka datang dengan beberapa biaya. Semakin kode anda tersebar diantara mixin, semakin keras itu akan dibaca kelas anak dan mengetahui apa yang sebenarnya itu lakukan, dan semakin keras itu akan diketahui metode mana dari mixin mana untuk ditimpa jika anda mensubkelaskan sesuatu yang mempunyai pohon warisan dalam.
Catat juga bahwa anda dapat hanya mewarisi dari satu tampilan umum - yaitu, hanya satu kelas induk mungkin mewarisi dari View
dan sisa (jika ada) harus berupa mixin. Mencoba mewarisi lebih dari satu kelas yang mewarisi dari View
- sebagai contoh, mencoba menggunakan sebuah formulir pada atas dari daftar dan memadukan ProcessFormView
dan ListView
- tidak bekerja sesuai harapan.
Menangani formulir dengan tampilan berdasarkan-kelas¶
Sebuah dasar tampilan berdasarkan-fungsi yang menangani formulir mungkin terlihat sesuatu seperti ini:
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import MyForm
def myview(request):
if request.method == "POST":
form = MyForm(request.POST)
if form.is_valid():
# <process form cleaned data>
return HttpResponseRedirect('/success/')
else:
form = MyForm(initial={'key': 'value'})
return render(request, 'form_template.html', {'form': form})
Tampilan berdasarkan-kelas yang mirip mungkin terlihat seperti:
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.views import View
from .forms import MyForm
class MyFormView(View):
form_class = MyForm
initial = {'key': 'value'}
template_name = 'form_template.html'
def get(self, request, *args, **kwargs):
form = self.form_class(initial=self.initial)
return render(request, self.template_name, {'form': form})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
# <process form cleaned data>
return HttpResponseRedirect('/success/')
return render(request, self.template_name, {'form': form})
This is a minimal case, but you can see that you would then have the option
of customizing this view by overriding any of the class attributes, e.g.
form_class
, via URLconf configuration, or subclassing and overriding one or
more of the methods (or both!).
Menghias tampilan berdasarkan-kelas¶
Tambahan dari tampilan berdasarkan-kelas tidak terbatas menggunakan mixin. Anda dapat juga menggunakan penghias. Sejak tampilan berdasarkan-kelas bukan fungsi, mengias mereka bekerja secara berbeda tergantung pada jika anda sedang menggunakan as_view()
atau membuat sebuah subkelas.
Menghias URLconf¶
You can adjust class-based views by decorating the result of the
as_view()
method. The easiest place to do
this is in the URLconf where you deploy your view:
from django.contrib.auth.decorators import login_required, permission_required
from django.views.generic import TemplateView
from .views import VoteView
urlpatterns = [
path('about/', login_required(TemplateView.as_view(template_name="secret.html"))),
path('vote/', permission_required('polls.can_vote')(VoteView.as_view())),
]
Pendekatan ini memberlakukan penghias pada dasar per-instance. Jika anda ingin setiap instance dari tampilan dihias, anda butuh mengambil pendekatan berbeda.
Menghias kelas¶
Untuk menghias setiap instance dari tampilan berdasarkan-kelas, anda butuh menghias pengertian kelas itu sendiri. Untuk melakukan ini anda berlakukan penghias ke metode dispatch()
dari kelas.
Sebuah metode pada sebuah kelas tidak agak sama seperti fungsi berdiri sendiri, jadi anda tidak hanya memberlakukan penghias fungsi ke metode -- anda butuh merubah itu menjadi penghias metode dahulu. Penghias method_decorator
merubah sebuah penghias fungsi kedalam penghias metode sehingga itu dapat digunakan pada metode instance. Sebagai contoh:
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView
class ProtectedView(TemplateView):
template_name = 'secret.html'
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs)
Atau, lebih ringkas, anda dapat menghias kelas dan melewatkan nama dari metode untuk di hias sebagai argumen kata kunci name
:
@method_decorator(login_required, name='dispatch')
class ProtectedView(TemplateView):
template_name = 'secret.html'
Jika anda mempunyai sekumpulan penghias umum digunakan di beberapa tempat, anda dapat menentukan daftar atau tuple dari penghias dan menggunakan ini sebagai gantinya meminta method_decorator()
berulang kali. Kedua kelas ini adalah setara:
decorators = [never_cache, login_required]
@method_decorator(decorators, name='dispatch')
class ProtectedView(TemplateView):
template_name = 'secret.html'
@method_decorator(never_cache, name='dispatch')
@method_decorator(login_required, name='dispatch')
class ProtectedView(TemplateView):
template_name = 'secret.html'
Penghias akan mengolah sebuah permintaan dalam urutan mereka dilewatkan ke penghias. Dalam contoh, never_cache()
akan mengolah permintaan sebelum login_required()
.
In this example, every instance of ProtectedView
will have login
protection. These examples use login_required
, however, the same behavior
can be obtained by using
LoginRequiredMixin
.
Catatan
method_decorator
melewatkan *args
dan **kwargs
sebagai parameter untuk menghiasi metode pada kelas. Jika metode anda tidak menerima sekumpulan cocok dari parameter itu akan memunculkan sebuah pengecualian TypeError
.