Menangani formulir dengan tampilan berdasarkan-kelas¶
Pengolahan formulir umumnya mempunyai 3 jalur:
- Inisial GET (kosong atau formulir diisi dimuka)
- POST dengan data tidak sah (khususnya memperlihatkan kembali formulir dengan kesalahan)
- POST dengan data sah (pengolahan data dan khususnya pengalihan)
Menerapkan ini anda sendiri sering menghasilkan banyak perulangan kode boilerplate (lihat Using a form in a view). Untuk menghindai ini, Django menyediakan kumpulan dari tampilan berdasarkan-kelas umum untuk pengolahan formulir.
Formulir dasar¶
Diberikan formulir kontak sederhana:
from django import forms
class ContactForm(forms.Form):
name = forms.CharField()
message = forms.CharField(widget=forms.Textarea)
def send_email(self):
# send email using the self.cleaned_data dictionary
pass
Tampilan dapat dibangun menggunakan FormView
:
from myapp.forms import ContactForm
from django.views.generic.edit import FormView
class ContactView(FormView):
template_name = 'contact.html'
form_class = ContactForm
success_url = '/thanks/'
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
form.send_email()
return super().form_valid(form)
Catatan:
- FormView mewarisi
TemplateResponseMixin
jaditemplate_name
dapat digunakan disini. - Penerapan awalan untuk
form_valid()
cukup mengalihkan kesuccess_url
.
Formulir model¶
Tampilan umum bersinar ketika bekerja dengan model. Tampilan umum ini akan secara otomatis membuat sebuah ModelForm
, selama mereka dapat bekerya kelas model mana digunakan:
- Jika atribut
model
diberikan, kelas model itu akan digunakan. - Jika
get_object()
mengembalikan sebuah obyek, kelas dari obyek akan digunakan. - Jika sebuah
queryset
diberikan, model untuk queryset itu akan digunakan.
Tampilan formulir model menyediakan sebuah penerapan form_valid()
yang menyimpan model secara otomatis. Anda dapat menimpa ini jika anda mempunyai persyaratan khusus lainnya; lihat dibawah untuk contoh.
Anda tidak perlu menyediakan sebuah success_url
untuk CreateView
atau UpdateView
- mereka akan menggunakan get_absolute_url()
pada obyek model jika tersedia.
Jika anda ingin menggunakan penyesuaian ModelForm
(sebagai contoh untuk menambah pengesahan tambahan) cukup setel form_class
pada tampilan anda.
Catatan
Ketika menentukan sebuah penyesuaian kelas formulir, anda harus masih menentukan model, meskipun form_class
mungkin berupa sebuah ModelForm
.
Pertama kami butuh menambahkan get_absolute_url()
ke kelas Author
kami:
from django.db import models
from django.urls import reverse
class Author(models.Model):
name = models.CharField(max_length=200)
def get_absolute_url(self):
return reverse('author-detail', kwargs={'pk': self.pk})
Kemudian kami dapat menggunakan CreateView
dan teman-teman untuk melakukan pekerjaan sebenarnya. Perhatikan bagaimana kami hanya mengkonfigurasi tampilan berdasarkan-kelas umum disini; kami tidak harus menulis logika apapun kami sendiri:
from django.urls import reverse_lazy
from django.views.generic.edit import CreateView, DeleteView, UpdateView
from myapp.models import Author
class AuthorCreate(CreateView):
model = Author
fields = ['name']
class AuthorUpdate(UpdateView):
model = Author
fields = ['name']
class AuthorDelete(DeleteView):
model = Author
success_url = reverse_lazy('author-list')
Catatan
Kami harus menggunakan reverse_lazy()
disini, tidak hanya reverse()
sebagai url tidak dimuat ketika berkas diimpor.
Atribut fields
bekerja cara sama seperti atribut fields
pada kelas Meta
sebelah dalam pada ModelForm
. Meskipun anda menentukan kelas formulir di cara lain, atribut dibutuhkan dan tampilan akan munculkan sebuah pengecualian ImproperlyConfigured
jika itu tidak.
Jika anda menentukan kedua atribut fields
dan form_class
, sebuah pengecualian ImproperlyConfigured
akan dimunculkan.
Akhirnya, kami mengaitkan tampilan baru ini kedalam URLconf:
from django.urls import path
from myapp.views import AuthorCreate, AuthorDelete, AuthorUpdate
urlpatterns = [
# ...
path('author/add/', AuthorCreate.as_view(), name='author-add'),
path('author/<int:pk>/', AuthorUpdate.as_view(), name='author-update'),
path('author/<int:pk>/delete/', AuthorDelete.as_view(), name='author-delete'),
]
Catatan
Tampilan ini mewarisi class:~django.views.generic.detail.SingleObjectTemplateResponseMixin yang menggunakan template_name_suffix
untuk membangun template_name
berdasarkan pada model.
Di contoh ini:
CreateView
danUpdateView
menggunakanmyapp/author_form.html
DeleteView
menggunakanmyapp/author_confirm_delete.html
Jika anda berharap untuk mempunyai cetakan terpisah untuk CreateView
dan UpdateView
, anda dapat menyetel antara template_name
atau template_name_suffix
pada kelas tampilan anda.
Models dan request.user
¶
Untuk melacak pengguna yang membuat sebuah obyek menggunakan sebuah CreateView
, anda dapat menggunakan sebuah penyesuaian ModelForm
untuk melakukan ini. Pertama, tambah hubungan foreign key pada model:
from django.contrib.auth.models import User
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=200)
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
# ...
Di tampilan, pastikan bahwa anda tidak menyertakan created_by
di daftar dari bidang untuk menyunting, dan menimpa form_valid()
untuk menambah pengguna:
from django.views.generic.edit import CreateView
from myapp.models import Author
class AuthorCreate(CreateView):
model = Author
fields = ['name']
def form_valid(self, form):
form.instance.created_by = self.request.user
return super().form_valid(form)
Catata bahwa anda akan butuh decorate this view menggunakan login_required()
, atau cara lain menangani pengguna tidak berhak di form_valid()
.
Contoh AJAX¶
Ini adalah contoh sederhana menunjukkan bagaimana anda mungkin pergi tentang menerapkan sebuah formulir yang bekerja untuk permintaan AJAX sama seperti formulir POST 'normal':
from django.http import JsonResponse
from django.views.generic.edit import CreateView
from myapp.models import Author
class AjaxableResponseMixin:
"""
Mixin to add AJAX support to a form.
Must be used with an object-based FormView (e.g. CreateView)
"""
def form_invalid(self, form):
response = super().form_invalid(form)
if self.request.is_ajax():
return JsonResponse(form.errors, status=400)
else:
return response
def form_valid(self, form):
# We make sure to call the parent's form_valid() method because
# it might do some processing (in the case of CreateView, it will
# call form.save() for example).
response = super().form_valid(form)
if self.request.is_ajax():
data = {
'pk': self.object.pk,
}
return JsonResponse(data)
else:
return response
class AuthorCreate(AjaxableResponseMixin, CreateView):
model = Author
fields = ['name']