# dokumentasi Django 2.2.9.dev20191202104323

# 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:

forms.py

    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

    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` jadi `template_name` dapat digunakan disini.
- Penerapan awalan untuk `form_valid()` cukup mengalihkan ke `success_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:

models.py

    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

    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:

urls.py

    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` dan `UpdateView` menggunakan `myapp/author_form.html`
- `DeleteView` menggunakan `myapp/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:

models.py

    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

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