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:
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 ContactFormView(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
(misalnya untuk menambahkan validasi ekstra), atur 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 AuthorCreateView(CreateView):
model = Author
fields = ["name"]
class AuthorUpdateView(UpdateView):
model = Author
fields = ["name"]
class AuthorDeleteView(DeleteView):
model = Author
success_url = reverse_lazy("author-list")
Catatan
Kami harus menggunakan reverse_lazy()
daripada reverse()
, ketika 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 AuthorCreateView, AuthorDeleteView, AuthorUpdateView
urlpatterns = [
# ...
path("author/add/", AuthorCreateView.as_view(), name="author-add"),
path("author/<int:pk>/", AuthorUpdateView.as_view(), name="author-update"),
path("author/<int:pk>/delete/", AuthorDeleteView.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.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic.edit import CreateView
from myapp.models import Author
class AuthorCreateView(LoginRequiredMixin, CreateView):
model = Author
fields = ["name"]
def form_valid(self, form):
form.instance.created_by = self.request.user
return super().form_valid(form)
LoginRequiredMixin
mencegah pengguna yang tidak masuk untuk mengakses formulir. Jika anda mengabaikannya, Anda harus menangani pengguna yang tidak sah di form_valid()
.
Contoh negosiasi isi¶
Here is an example showing how you might go about implementing a form that works with an API-based workflow as well as 'normal' form POSTs:
from django.http import JsonResponse
from django.views.generic.edit import CreateView
from myapp.models import Author
class JsonableResponseMixin:
"""
Mixin to add JSON 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.accepts("text/html"):
return response
else:
return JsonResponse(form.errors, status=400)
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.accepts("text/html"):
return response
else:
data = {
"pk": self.object.pk,
}
return JsonResponse(data)
class AuthorCreateView(JsonableResponseMixin, CreateView):
model = Author
fields = ["name"]