Menangani formulir dengan tampilan berdasarkan-kelasLink to this heading

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 dasarLink to this heading

Diberikan formulir kontak:

forms.py
Python
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:

views.py
Python
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:

Formulir modelLink to this heading

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.

If you want to use a custom ModelForm (for instance to add extra validation), set form_class on your view.

Pertama kami butuh menambahkan get_absolute_url() ke kelas Author kami:

models.py
Python
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:

views.py
Python
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')

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:

urls.py
Python
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'),
]

Models dan request.userLink to this heading

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:

models.py
Python
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:

views.py
Python
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic.edit import CreateView
from myapp.models import Author

class AuthorCreate(LoginRequiredMixin, CreateView):
    model = Author
    fields = ['name']

    def form_valid(self, form):
        form.instance.created_by = self.request.user
        return super().form_valid(form)

LoginRequiredMixin prevents users who aren't logged in from accessing the form. If you omit that, you'll need to handle unauthorized users in form_valid().

Contoh AJAXLink to this heading

Here is an example showing how you might go about implementing a form that works for AJAX requests as well as 'normal' form POSTs:

Code
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']