---
title: "Menggunakan mixin dengan tampilan berdasarkan-kelas"
version: 2.0
locale: id
source: https://docs.djangoproject.com/id/2.0/topics/class-based-views/mixins/
canonical: https://djangodocs.dev/id/2.0/topics/class-based-views/mixins/
---
# Menggunakan mixin dengan tampilan berdasarkan-kelas

> **Caution**
>
> Ini adalah sebuah topik lanjut. Sebuah pengetahuan dari [Django's class-based views](/id/2.0/topics/class-based-views/) disarankan sebelum menjelajahi teknik-teknis ini.

Tampilan berdasarkan-kelas siap-pakai Django menyediakan banyak fungsionalitas, tetapi beberapa dari itu anda mungkin ingin menggunakannya terpisah. Sebagai contoh, anda mungkin ingin menulis sebuah tampilan yang membangun cetakan untuk membuat tanggapan HTTP, tetapi anda tidak dapat menggunakan [`TemplateView`](/id/2.0/ref/class-based-views/base/#django.views.generic.base.TemplateView); mungkin anda butuh membangun cetakan hanya pada `POST`, dengan `GET` melakukan sesuatu lain seluruhnya. Selagi anda dapat menggunakan [`TemplateResponse`](/id/2.0/ref/template-response/#django.template.response.TemplateResponse) langsung, ini akan kemungkinan hasil di kode ganda.

Untuk alasan ini, Django juga menyediakan sejumlah mixin yang menyediakan fungsionalitas diskrit lebih. Pembangunan cetakan, sebagai contoh, dienkapsulasi di [`TemplateResponseMixin`](/id/2.0/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin). Dokumentasi acuan Django mengandung [full documentation of all the mixins](/id/2.0/ref/class-based-views/mixins/).

## Tanggapan koteks dan cetakan

Dua mixin pusat disediakan yang membantu dalam antarmuka tetap untuk bekerja dengan cetakan di tampilan berdasarkan-kelas.

**[`TemplateResponseMixin`](/id/2.0/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin)**

  Setiap tampilan siap pakai yang mengembalikan [`TemplateResponse`](/id/2.0/ref/template-response/#django.template.response.TemplateResponse) akan memanggil metode [`render_to_response()`](/id/2.0/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin.render_to_response) yang `TemplateResponseMixin` sediakan. Kebanyakan dari waktu ini akan dipanggil untuk anda (sebagai contoh, itu dipanggil oleh metode `get()` diterapkan oleh kedua [`TemplateView`](/id/2.0/ref/class-based-views/base/#django.views.generic.base.TemplateView) and [`DetailView`](/id/2.0/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView)); demikian pula, itu tidak mungkin anda butuh menimpa itu, meskipun jika anda ingin tanggapan anda mengembalikan sesuatu tidak dibangun melalui cetakan Django kemudian anda akan ingin melakukan itu. Sebagai contoh dari ini, lihat [JSONResponseMixin example](#jsonresponsemixin-example).

  `render_to_response()` itu sendiri memanggil [`get_template_names()`](/id/2.0/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin.get_template_names), yang secara awalan akan hanya mencari [`template_name`](/id/2.0/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin.template_name) pada tampilan berdasarkan-kelas; dua mixin lainnya ([`SingleObjectTemplateResponseMixin`](/id/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectTemplateResponseMixin) dan [`MultipleObjectTemplateResponseMixin`](/id/2.0/ref/class-based-views/mixins-multiple-object/#django.views.generic.list.MultipleObjectTemplateResponseMixin)) menimpa ini untuk menyediakan awalan lebih elastis ketika berurusan dengan obyek sebenarnya.

**[`ContextMixin`](/id/2.0/ref/class-based-views/mixins-simple/#django.views.generic.base.ContextMixin)**

  Setiap tampilan siap pakai uang butuh data konteks, seperti membangun sebuah cetakan (termasuk `TemplateResponseMixin` diatas), harus memanggil [`get_context_data()`](/id/2.0/ref/class-based-views/mixins-simple/#django.views.generic.base.ContextMixin.get_context_data) melewatkan data apapun mereka ingin pastikan ada disana sebagai argumen kata kunci. `get_context_data()` mengembalikan sebuah dictionary; di `ContextMixin` itu cukup mengembalikan argumen kata kunci nya, tetapi itu adalah umum untuk menimpa ini untuk menambahkan anggota lagi ke dictionary. Anda dapat juga menggunakan atribut [`extra_context`](/id/2.0/ref/class-based-views/mixins-simple/#django.views.generic.base.ContextMixin.extra_context).

## Membangun tampilan berdasarkan-kelas umum Django

Mari kita lihat bagaimana tampilan berdasarkan-kelas umum Django adalah membangun dari mixin disediakan fungsionalitas diskrit. Kami akan mempertimbangkan [`DetailView`](/id/2.0/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView), yang membangun tampilan "detail" dari sebuah obyek, dan [`ListView`](/id/2.0/ref/class-based-views/generic-display/#django.views.generic.list.ListView), yang akan membangun sebuah daftar dari obyek, khususnya dari queryset, dan pilihannya memberi nomor mereka. Ini akan memperkenalkan kita untuk empat mixin yang diantara mereka menyediakan fungsionalitas berguna dengan antara obyek Django tunggal, atau banyak obyek.

Ada juga mixin terlibat di tampilan sunting umum ([`FormView`](/id/2.0/ref/class-based-views/generic-editing/#django.views.generic.edit.FormView), dan tampilan model-tertentu [`CreateView`](/id/2.0/ref/class-based-views/generic-editing/#django.views.generic.edit.CreateView), [`UpdateView`](/id/2.0/ref/class-based-views/generic-editing/#django.views.generic.edit.UpdateView) dan [`DeleteView`](/id/2.0/ref/class-based-views/generic-editing/#django.views.generic.edit.DeleteView)), dan di tampilan umum berdasarkan-tanggal. Ini dicakupi di [mixin reference documentation](/id/2.0/ref/class-based-views/mixins/).

### `DetailView`: bekerja dengan obyek tunggal Django

Untuk menunjukkan rincian dari sebuah obyek, kami dasarnya butuh melakukan dua hal: kami butuh mencari obyek dan kemudian kami butuh membuat [`TemplateResponse`](/id/2.0/ref/template-response/#django.template.response.TemplateResponse) dengan cetakan yang cocok, dan obyek itu sebagai konteks.

Untuk mendapatkan obyek, [`DetailView`](/id/2.0/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView) bergantung pada [`SingleObjectMixin`](/id/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin), yang menyediakan sebuah metode [`get_object()`](/id/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin.get_object) yang mencari tahu berdasarkan obyek pada URL dari permintaan (itu sepertinya untuk argumen kata kunci `pk` dan `slug` seperti dinyatakan di URLConf, dan mencari obyek antara dari atribut [`model`](/id/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin.model) pada tampilan, atau atribut [`queryset`](/id/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin.queryset) jika itu disediakan). `SingleObjectMixin` juga menimpa [`get_context_data()`](/id/2.0/ref/class-based-views/mixins-simple/#django.views.generic.base.ContextMixin.get_context_data), yang digunakan terhadap semua tampilan siap-pakai Django untuk memasok data konteks untuk membangun cetakan.

Untuk kemudian sebuah [`TemplateResponse`](/id/2.0/ref/template-response/#django.template.response.TemplateResponse), [`DetailView`](/id/2.0/ref/class-based-views/flattened-index/#DetailView) menggunakan [`SingleObjectTemplateResponseMixin`](/id/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectTemplateResponseMixin), yang memperpanjang [`TemplateResponseMixin`](/id/2.0/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin), menimpa [`get_template_names()`](/id/2.0/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin.get_template_names) seperti diobrolkan diatas. Itu sebenarnya menyediakan kumpulan cukup canggih pilihan, tetapi satu utama yang paling orang akan gunakan adalah `<app_label>/<model_name>_detail.html`. Bagian `_detail` dapat dirubah dengan mengatur [`template_name_suffix`](/id/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix) pada subkelas atau sesuatu lain. (Sebagai contoh,  [generic edit views](/id/2.0/topics/class-based-views/generic-editing/) menggunakan `_form` untuk membuat dan memperbaharui tampilan, dan `_confirm_delete` untuk tampilan menghapus.)

### `ListView`: bekerja dengan banyak obyek Django

Daftar dari obyek mengikuti kurang lebih pola sama: kami butuh sebuah (kemungkinan diberikan nomor) daftar obyek, khususnya sebuah [`QuerySet`](/id/2.0/ref/models/querysets/#django.db.models.query.QuerySet), dan kemudian kami butuh membuat sebuah [`TemplateResponse`](/id/2.0/ref/template-response/#django.template.response.TemplateResponse) dengan cetakan cocok menggunakan daftar itu dari obyek.

Untuk mendapatkan obyek, [`ListView`](/id/2.0/ref/class-based-views/generic-display/#django.views.generic.list.ListView) menggunakan [`MultipleObjectMixin`](/id/2.0/ref/class-based-views/mixins-multiple-object/#django.views.generic.list.MultipleObjectMixin), yang menyediakan kedua [`get_queryset()`](/id/2.0/ref/class-based-views/mixins-multiple-object/#django.views.generic.list.MultipleObjectMixin.get_queryset) dan [`paginate_queryset()`](/id/2.0/ref/class-based-views/mixins-multiple-object/#django.views.generic.list.MultipleObjectMixin.paginate_queryset). Tidak seperti dengan [`SingleObjectMixin`](/id/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin), tidak perlu key off bagian dari URL untuk mencari tahu queryset bekerja, jadi awalan hanya menggunakan atribut [`queryset`](/id/2.0/ref/class-based-views/mixins-multiple-object/#django.views.generic.list.MultipleObjectMixin.queryset) atau [`model`](/id/2.0/ref/class-based-views/mixins-multiple-object/#django.views.generic.list.MultipleObjectMixin.model) pada kelas tampilan. Sebuah alasan umum untun menimpa [`get_queryset()`](/id/2.0/ref/class-based-views/mixins-multiple-object/#django.views.generic.list.MultipleObjectMixin.get_queryset) disini akan menjadi secara dinamis beragam obyek, seperti bergantung pada pengguna saat ini atau mengeluarkan penempatan di masa depan untuk sebuah blog.

[`MultipleObjectMixin`](/id/2.0/ref/class-based-views/mixins-multiple-object/#django.views.generic.list.MultipleObjectMixin) juga menimpa [`get_context_data()`](/id/2.0/ref/class-based-views/mixins-simple/#django.views.generic.base.ContextMixin.get_context_data) untuk menyertakan variabel konteks sesuai untuk penomoran halaman (menyediakan contoh jika penomoran halaman ditiadakan). Itu bergantung pada 11object\_list\`\` dilewatkan di sebuah argumen kata kunci, yang [`ListView`](/id/2.0/ref/class-based-views/flattened-index/#ListView) mengatur untuk itu.

Untuk membuat sebuah [`TemplateResponse`](/id/2.0/ref/template-response/#django.template.response.TemplateResponse), [`ListView`](/id/2.0/ref/class-based-views/flattened-index/#ListView) kemudian menggunakan [`MultipleObjectTemplateResponseMixin`](/id/2.0/ref/class-based-views/mixins-multiple-object/#django.views.generic.list.MultipleObjectTemplateResponseMixin); seperti [`SingleObjectTemplateResponseMixin`](/id/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectTemplateResponseMixin) diatas, ini menimpa `get_template_names()` untuk menyediakan [`a range of options`](/id/2.0/ref/class-based-views/mixins-multiple-object/#django.views.generic.list.MultipleObjectTemplateResponseMixin), yang paling digunakan-umum berwujud `<app_label>/<model_name>_list.html`, dengan bagian `_list` kembali diambil dari atribut [`template_name_suffix`](/id/2.0/ref/class-based-views/mixins-multiple-object/#django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix). (Tampilan umum berdasarkan tanggal menggunakan akhiran seperti `_archive`, `_archive_year` dan sebagainya untuk menggunakan cetakan berbeda untuk beragam tampilan daftar berdasarkan-tanggal khusus.)

## Menggunakan mixin tampilan berdasarkan-kelas Django

Sekarang kami telah melihat bagaimana tampilan berdasarkan-kelas umum Django menggunakan mixin disediakan, mari kita melihat pada cara lain kami dapat padukan mereka. Tentu saja kami masih akan memadukan mereka dengan tampulan berdasarkan-kelas siap-pakai, atau tampilan berdasarkan-kelas umum, tetapi ada jangkauan dari masalah jarang anda dapat selesaikan daripada disediakan untuk Django keluar dari kotak.

> **Warning**
>
> Tidak semua mixin dapat digunakan bersama-sama, dan tidak semua tampilan berdasarkan kelas umum dapat digunakan dengan semua mixin lain. Disini kami menghadirkan beberapa contoh yang melakukan pekerjaan; jika anda ingin membawa bersama-sama fungsionalitas lain kemudian anda akan harus mempertimbangkan interaksi diantara atribut dan metode yang tumpang tindih diantara kelas-kelas berbeda anda sedang gunakan, dan bagaimana [method resolution order](https://www.python.org/download/releases/2.3/mro/) akan mempengaruhi versi mana dari metode akan dipanggil di urutan apa.
>
> Acuan dokumentasi untuk [class-based views](/id/2.0/ref/class-based-views/) dan [class-based view mixins](/id/2.0/ref/class-based-views/mixins/) Django akan membantu anda dalam memahami atribut dan metode mana mungkin menyebabkan pertentangan diantara kelas dan mixin berbeda.
>
> Jika ragu, itu sering lebih baik mundur dan dasarkan pekerjaan anda pada [`View`](/id/2.0/ref/class-based-views/flattened-index/#View) atau [`TemplateView`](/id/2.0/ref/class-based-views/flattened-index/#TemplateView), mungkin dengan [`SingleObjectMixin`](/id/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin) dan [`MultipleObjectMixin`](/id/2.0/ref/class-based-views/mixins-multiple-object/#django.views.generic.list.MultipleObjectMixin). Meskipun anda akan mungkin mengakhiri menulis kode lebih, itu lebih mungkin jelas dapat dimengerti pada seseorang lain datang ke itu kemudian, dan dengan sedikit interaksi untuk khawatir tentang anda akan menyimpan beberapa pemikiran anda sendiri. (Tentu saja, anda dapat selalu mempelajari kedalam penerapan Django dari tampilan berdasarkan-kelas umum untuk ilham pada bagaimana memecahkan masalah.)

### Menggunakan `SingleObjectMixin` dengan View

Jika kami ingin menulis tampilan berdasarkan-kelas sederhana yang menanggapi hanya pada `POST`, kami akan mensubkelaskan [`View`](/id/2.0/ref/class-based-views/base/#django.views.generic.base.View) dan menulis sebuah metode `post()` di subkelas. Bagaimanapun jika kami ingin pengolahan kami bekerja pada obyek tertentu, cirikan dari URL, kami akan ingin fungsionalitas disediakan oleh [`SingleObjectMixin`](/id/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin).

Kami akan mempertunjukkan ini dengan model `Author` kami gunakan di [generic class-based views introduction](/id/2.0/topics/class-based-views/generic-display/).

*views.py*

```
from django.http import HttpResponseForbidden, HttpResponseRedirect
from django.urls import reverse
from django.views import View
from django.views.generic.detail import SingleObjectMixin
from books.models import Author

class RecordInterest(SingleObjectMixin, View):
    """Records the current user's interest in an author."""
    model = Author

    def post(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return HttpResponseForbidden()

        # Look up the author we're interested in.
        self.object = self.get_object()
        # Actually record interest somehow here!

        return HttpResponseRedirect(reverse('author-detail', kwargs={'pk': self.object.pk}))
```

Dalam praktiknya anda mungkin ingin merekam ketertarikan dalam penyimpanan kunci-nilai daripada ddi basisdata hubungan, jadi kami telah meninggalkan sedikit. Hanya sedikit dari tampilan yang butuh dikhawatirkan tentang menggunakan [`SingleObjectMixin`](/id/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin) adalah dimana kami ingin mencari penulis kami tertarik, yang itu hanya dilakukan dengan panggulan sederhana pada `self.get_object()`. Yang lainnya diurus untuk kami oleh mixin.

Kami dapat menghubungkan kedalam URL kami dengan cukup mudah:

*urls.py*

```
from django.urls import path
from books.views import RecordInterest

urlpatterns = [
    #...
    path('author/<int:pk>/interest/', RecordInterest.as_view(), name='author-interest'),
]
```

Catat kelompok bernama `pk`, yang [`get_object()`](/id/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin.get_object) menggunakan untuk mencari instance `Author`. Anda dapat juga menggunakan sebuah keong, atau apapun dari fitur-fitur lain dari [`SingleObjectMixin`](/id/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin).

### Menggunakan `SingleObjectMixin` dengan `ListView`

[`ListView`](/id/2.0/ref/class-based-views/generic-display/#django.views.generic.list.ListView) menyediakan penomoran siap-pakai, tetapi anda mungkin ingin memberi nomor daftar dari obyek yang semua terkait (oleh foreign key) ke obyek lain. Di contoh penerbitan kami, anda mungkin ingin memberi nomor melalui semua buku-buku oleh penerbit tertentu.

Satu cara melakukan ini adalah memadukan [`ListView`](/id/2.0/ref/class-based-views/flattened-index/#ListView) dengan [`SingleObjectMixin`](/id/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin), sehingga queryset untuk memberi nomor halaman dari buku dapat  menggantung penerbit ditemukan sebagai obyek tunggal. Untuk melakukan ini, kami butuh memiliki dua queryset berbeda:

**Queryset `Book` untuk digunakan oleh [`ListView`](/id/2.0/ref/class-based-views/generic-display/#django.views.generic.list.ListView)**

  Karena kami mempunyai akses ke `Publisher` yang bukunya kami ingin daftar, kami cukup menimpa `get_queryset()` dan menggunakan [reverse foreign key manager](/id/2.0/topics/db/queries/#backwards-related-objects) `Publisher`.

**Queryset `Publisher` untuk digunakan di [`get_object()`](/id/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin.get_object)**

  Kami akan bergantung pada penerapan awalan dari `get_object()` untuk mengambil obyek `Publisher` benar. Bagaimanapun, kami butuh jelas melewatkan sebuah argumen `queryset` karena jika tidak penerapan awalan dari `get_object()` akan memanggil `get_queryset()` yang kami telah timpa untuk mengembalikan obyek `Book` daripada `Publisher`.

> **Note**
>
> Kami harus berpikir hati-hati tentang `get_context_data()`. Sejak kedua [`SingleObjectMixin`](/id/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin) dan [`ListView`](/id/2.0/ref/class-based-views/flattened-index/#ListView) akan menaruh hal-hal dalam data konteks dibawah nilai dari `context_object_name` jika itu disetel, kami akan jelas memastikan `Publisher` adalah dalam data konteks. [`ListView`](/id/2.0/ref/class-based-views/flattened-index/#ListView) akan menambah dalam `page_obj` dan `paginator` cocok untuk kami menyediakan kami ingat memanggil `super()`.

Sekarang kami dapat menulis `PublisherDetail` baru:

```
from django.views.generic import ListView
from django.views.generic.detail import SingleObjectMixin
from books.models import Publisher

class PublisherDetail(SingleObjectMixin, ListView):
    paginate_by = 2
    template_name = "books/publisher_detail.html"

    def get(self, request, *args, **kwargs):
        self.object = self.get_object(queryset=Publisher.objects.all())
        return super().get(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['publisher'] = self.object
        return context

    def get_queryset(self):
        return self.object.book_set.all()
```

Perhatikan bagaimana kami menyetel `self.object` dalam `get()` jadi kami dapat menggunakan itu kembali kemudian dalam `get_context_data()` dan `get_queryset()`. Jika anda tidak menyetel `template_name`, cetakan akan awalan menjadi pilihan [`ListView`](/id/2.0/ref/class-based-views/flattened-index/#ListView) biasa, yang dalam kasus ini akan menjadi `"books/book_list.html"` karena itu adalah daftar dari buku-buku; [`ListView`](/id/2.0/ref/class-based-views/flattened-index/#ListView) tidak mengetahui apapun tentang [`SingleObjectMixin`](/id/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin), jadi itu tidak mempunyai petunjuk tampilan ini adalah hubungannya dengan `Publisher`.

`paginate_by` sengaja kecil dalam contoh sehingga anda tidak perlu membuat banyak buku untuk melihat penomoran halaman bekerja! Ini adalah cetakan anda ingin gunakan:

```html+django
{% extends "base.html" %}

{% block content %}
    <h2>Publisher {{ publisher.name }}</h2>

    <ol>
      {% for book in page_obj %}
        <li>{{ book.title }}</li>
      {% endfor %}
    </ol>

    <div class="pagination">
        <span class="step-links">
            {% if page_obj.has_previous %}
                <a href="?page={{ page_obj.previous_page_number }}">previous</a>
            {% endif %}

            <span class="current">
                Page {{ page_obj.number }} of {{ paginator.num_pages }}.
            </span>

            {% if page_obj.has_next %}
                <a href="?page={{ page_obj.next_page_number }}">next</a>
            {% endif %}
        </span>
    </div>
{% endblock %}
```

## Hindari apapun lebih rumit

Umumnya anda dapat gunakan [`TemplateResponseMixin`](/id/2.0/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin) dan [`SingleObjectMixin`](/id/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin) ketika anda butuh fungsionalitas mereka. Seperti ditunjukkan diatas, dengan sedikit perawatan anda dapat bahkan memadukan `SingleObjectMixin` dengan [`ListView`](/id/2.0/ref/class-based-views/generic-display/#django.views.generic.list.ListView). Bagaimanapun hal-hal meningkat semakin rumit ketika anda mencoba melakukannya, dan aturan bagus dari ibu jari adalah:

> **Hint**
>
> Setiap tampilan anda harus menggunakan hanya mixin atau tampilan dari saru dari kelompok dari tampilan berdasarkan-kelas umum: [detail, list](/id/2.0/topics/class-based-views/generic-display/), [editing](/id/2.0/topics/class-based-views/generic-editing/) dan tanggal. Sebagai contoh itu adalah baik memadukan [`TemplateView`](/id/2.0/ref/class-based-views/flattened-index/#TemplateView) (tampilan siap pakai) dengan [`MultipleObjectMixin`](/id/2.0/ref/class-based-views/mixins-multiple-object/#django.views.generic.list.MultipleObjectMixin) (daftar umum), tetapi anda mungkin memiliki masalah memadukan `SingleObjectMixin` (rincian umum) dengan `MultipleObjectMixin` (daftar umum).

Untuk menunjukkan apa yang terjadi ketika anda mencoba mendapatkan lebih mutakhir, kami menunjukkan sebuah contoh yang mengorbankan kesiapan dan rawatan ketika ada pemecahan termudah. Pertama, mari kita lihat usaha naif untuk memadukan [`DetailView`](/id/2.0/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView) dengan [`FormMixin`](/id/2.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin) untuk mengadakan kami pada `POST` sebuah [`Form`](/id/2.0/ref/forms/api/#django.forms.Form) Django ke URL sama ketika kami sedang memperlihatkan sebuah obyek menggunakan [`DetailView`](/id/2.0/ref/class-based-views/flattened-index/#DetailView).

### Menggunakan `FormMixin` dengan `DetailView`

Berpikir kembali ke contoh paling awal dari menggunakan [`View`](/id/2.0/ref/class-based-views/flattened-index/#View) dan [`SingleObjectMixin`](/id/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin) bersama-sama. Kami sedang merekam sebuah minat pengguna dalam penulis tertentu; katakan sekarang yang kami ingin membiarkan mereka meninggalkan pesan mengatakan mengapa mereka menyukainya. Kembali, mari kita anggap tidak menyimpan ini dalam basisdata hubungan tetapi sebagai gantinya di lebih esoterik yang kami tidak akan khawatir disini.

Pada titik ini itu adalah alamiah mencapai untuk [`Form`](/id/2.0/ref/forms/api/#django.forms.Form) untuk mengenkapsulasi informasi dikirim dari peramban pengguna pada Django. Katakan juga bahwa kami melakukan investasi di [REST](https://en.wikipedia.org/wiki/Representational_state_transfer), jadi kami ingin menggunakan URL sama untuk memperlihatkan penulis sebagai untuk menangkap pesan dar pengguna. Mari kita menulis kembali `AuthorDetailView` kami untuk melakukan itu.

Kami akan menjaga penanganan `GET` dari [`DetailView`](/id/2.0/ref/class-based-views/flattened-index/#DetailView), meskipun kami akan harus menambah [`Form`](/id/2.0/ref/forms/api/#django.forms.Form) kedalam data konteks jadi kami dapat mengirim itu dalam cetakan. Kami akan juga ingin menarik dalam pengolahan formulir [`FormMixin`](/id/2.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin), dan menulis sedikit kode sehingga pada `POST` formulir mendapatkan panggilan yang sesuai.

> **Note**
>
> Kami menggunakan [`FormMixin`](/id/2.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin) dan menerapkan `post()` kami sendiri daripada mencoba mencampur [`DetailView`](/id/2.0/ref/class-based-views/flattened-index/#DetailView) dengan [`FormView`](/id/2.0/ref/class-based-views/flattened-index/#FormView) (yang menyediakan sudah `post()` cocok) karena kedua dari tampilan menerapkan `get()`, dan hal-hal akan menjadi lebih membingungkan.

`AuthorDetail` baru kami seperti ini:

```
# CAUTION: you almost certainly do not want to do this.
# It is provided as part of a discussion of problems you can
# run into when combining different generic class-based view
# functionality that is not designed to be used together.

from django import forms
from django.http import HttpResponseForbidden
from django.urls import reverse
from django.views.generic import DetailView
from django.views.generic.edit import FormMixin
from books.models import Author

class AuthorInterestForm(forms.Form):
    message = forms.CharField()

class AuthorDetail(FormMixin, DetailView):
    model = Author
    form_class = AuthorInterestForm

    def get_success_url(self):
        return reverse('author-detail', kwargs={'pk': self.object.pk})

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['form'] = self.get_form()
        return context

    def post(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return HttpResponseForbidden()
        self.object = self.get_object()
        form = self.get_form()
        if form.is_valid():
            return self.form_valid(form)
        else:
            return self.form_invalid(form)

    def form_valid(self, form):
        # Here, we would record the user's interest using the message
        # passed in form.cleaned_data['message']
        return super().form_valid(form)
```

`get_success_url()` hanya menyediakan entah dimana untuk mengalihkan, yang akan digunakan dalam penerapan awalan dari `form_valid()`. Kami harus menyediakan `post()` kami sendiri seperti dicatat terdahulu, dan menimpa `get_context_data()` utuk membuat [`Form`](/id/2.0/ref/forms/api/#django.forms.Form) tersedia dalam data konteks.

### Pemecahan terbaik

Itu harus jelas bahwa nomor dari interaksi halus diantara [`FormMixin`](/id/2.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin) dan [`DetailView`](/id/2.0/ref/class-based-views/flattened-index/#DetailView) sudah mencoba kemampuan kami untuk mengelola hal-hal. Itu tidak sepertinya anda ingin menulis hal ini dari kelas anda sendiri.

Dalam kasus ini, itu akan sangat mudah hanya menulis metode `post()` anda sendiri, menjaga [`DetailView`](/id/2.0/ref/class-based-views/flattened-index/#DetailView) seperti fungsionalitas umum, meskipun menulis [`Form`](/id/2.0/ref/forms/api/#django.forms.Form) penanganan kode melibatkan banyak penggandaan.

Cara lain, itu akan masih lebih mudah daripada pendekatan diatas untuk memiliki tampilan terpisah untuk pengolahan formulir, yang dapat menggunakan [`FormView`](/id/2.0/ref/class-based-views/generic-editing/#django.views.generic.edit.FormView) berbeda dari [`DetailView`](/id/2.0/ref/class-based-views/flattened-index/#DetailView) tanpa kepentingan.

### Sebuah pilihan lain pemecahan terbaik

Apa kami sedang coba lakukan disini adalah menggunakan dua kelas bebeda berdasarkan tampilan dari URL sama. Jadi mengapa tidak lakukan hal itu? Kami mempunyai pembagian sangat jelas disini: permintaan `GET` harus mendapatkan [`DetailView`](/id/2.0/ref/class-based-views/flattened-index/#DetailView) (dengan [`Form`](/id/2.0/ref/forms/api/#django.forms.Form) ditambahkan ke data konteks), dan permintaan `POST` harus mendapatkan [`FormView`](/id/2.0/ref/class-based-views/flattened-index/#FormView). Mari kita menyetek tampilan tersebut dahulu.

Tampilan `AuthorDisplay` hampir sama seperti [when we first introduced AuthorDetail](/id/2.0/topics/class-based-views/generic-display/#generic-views-extra-work); kami harus menulis `get_context_data()` kami sendiri untuk membuat `AuthorInterestForm` tersedia pada cetakan. Kami akan melewati `get_object()` menimpa dari sebelumnya untuk kejelasan:

```
from django import forms
from django.views.generic import DetailView
from books.models import Author

class AuthorInterestForm(forms.Form):
    message = forms.CharField()

class AuthorDisplay(DetailView):
    model = Author

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['form'] = AuthorInterestForm()
        return context
```

Kemudian `AuthorInterest` adalah [`FormView`](/id/2.0/ref/class-based-views/flattened-index/#FormView) sederhana, tetapi kami harus membawa kedalam [`SingleObjectMixin`](/id/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin) sehingga kami dapat menemukan penulis kami sedang bicarakan, dan kami harus mengingat menyetel `template_name` memastikan bahwa kesalahan formulir akan membangun cetakan sama seperti `AuthorDisplay` sedang gunakan pada `GET`:

```
from django.http import HttpResponseForbidden
from django.urls import reverse
from django.views.generic import FormView
from django.views.generic.detail import SingleObjectMixin

class AuthorInterest(SingleObjectMixin, FormView):
    template_name = 'books/author_detail.html'
    form_class = AuthorInterestForm
    model = Author

    def post(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return HttpResponseForbidden()
        self.object = self.get_object()
        return super().post(request, *args, **kwargs)

    def get_success_url(self):
        return reverse('author-detail', kwargs={'pk': self.object.pk})
```

Akhirnya kami membawa ini bersama-sama dalam sebuah tampilan `AuthorDetail` baru. Kami sudah mengetahui bahwa memanggil [`as_view()`](/id/2.0/ref/class-based-views/base/#django.views.generic.base.View.as_view) pada sebuah tampilan berdasarkan-kelas memberikan kami sesuatu yang berperilaku persis seperti sebuah tampilan berdasarkan fungsi, jadi kami dapat melakukan itu pada titik kami pilih diantara dua sub tampilan.

Anda dapat melewatkan perjalanan melalui argumen kata kunci pada [`as_view()`](/id/2.0/ref/class-based-views/base/#django.views.generic.base.View.as_view) dalam cara sama anda akan dalam URLconf anda, seperti jika anda ingin perilaku `AuthorInterest` untuk juga muncul pada URL lain tetapi menggunakan cetakan berbeda:

```
from django.views import View

class AuthorDetail(View):

    def get(self, request, *args, **kwargs):
        view = AuthorDisplay.as_view()
        return view(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        view = AuthorInterest.as_view()
        return view(request, *args, **kwargs)
```

Pendekatan ini dapat juga digunakan dengan tampilan berdasarkan-kelas umum lainnya diwarisi langsung dari [`View`](/id/2.0/ref/class-based-views/flattened-index/#View) or [`TemplateView`](/id/2.0/ref/class-based-views/flattened-index/#TemplateView), ketika itu menjaga tampilan berbeda sebagai terpisah mungkin.

## Lebih dari hanya HTML

Dimana bersinar tampilan berdasarkan-kelas adalah ketika anda ingin melakukan hal sama sebanyak kali. Kiranya anda sedang menulis sebuah API, dan setiap tampilan harus mengembalikan JSON daripada membangun HTML.

Kami dapat membuat sebuah kelas mixin untuk digunakan di semua dari tampilan kami, menangani perubahan pada JSON sekali.

Sebagai contoh, mixin JSON sederhana mungkin terlihat seperti ini:

```
from django.http import JsonResponse

class JSONResponseMixin:
    """
    A mixin that can be used to render a JSON response.
    """
    def render_to_json_response(self, context, **response_kwargs):
        """
        Returns a JSON response, transforming 'context' to make the payload.
        """
        return JsonResponse(
            self.get_data(context),
            **response_kwargs
        )

    def get_data(self, context):
        """
        Returns an object that will be serialized as JSON by json.dumps().
        """
        # Note: This is *EXTREMELY* naive; in reality, you'll need
        # to do much more complex handling to ensure that arbitrary
        # objects -- such as Django model instances or querysets
        # -- can be serialized as JSON.
        return context
```

> **Note**
>
> Periksa dokumentasi [Serializing Django objects](/id/2.0/topics/serialization/) untuk informasi lebih pada bagaimana dengan benar merubah model Django dan queryset menjadi JSON.

Mixin ini menyediakan sebuah metode `render_to_json_response()` dengan tanda tangan sama seperti [`render_to_response()`](/id/2.0/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin.render_to_response). Untuk menggunakan itu, kami cukup butuh mencampur itu kedalam sebuah `TemplateView` sebagai contoh, dan menimpa `render_to_response()` untuk memanggil `render_to_json_response()` sebagai gantinya:

```
from django.views.generic import TemplateView

class JSONView(JSONResponseMixin, TemplateView):
    def render_to_response(self, context, **response_kwargs):
        return self.render_to_json_response(context, **response_kwargs)
```

Sama kami dapat menggunakan mixin kami dengan satu dari tampilan umum. Kami dapat membuat versi kami sendiri dari [`DetailView`](/id/2.0/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView) dengan mencampur `JSONResponseMixin` dengan `django.views.generic.detail.BaseDetailView` -- ([`DetailView`](/id/2.0/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView) sebelum perilaku membangun cetakan telah dicampur):

```
from django.views.generic.detail import BaseDetailView

class JSONDetailView(JSONResponseMixin, BaseDetailView):
    def render_to_response(self, context, **response_kwargs):
        return self.render_to_json_response(context, **response_kwargs)
```

Tampilan ini dapat kemudian disebarkan dalam cara sama seperti lainnya [`DetailView`](/id/2.0/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView), dengan persi perilaku sama -- kecuali untuk bentuk dari tanggapan.

Jika anda ingin harus benar-benar berpetulangan, anda dapat bahkan mencampur subkelas [`DetailView`](/id/2.0/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView) yang dapat megnembalikan *kedua* isi HTML dan JSON, bergantung pada beberapa sifat dari permintaan HTTP, seperti sebuah argumen permintaan atau kepala HTTP. Hanya mencampur dalam kedua `JSONResponseMixin` dan sebuah [`SingleObjectTemplateResponseMixin`](/id/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectTemplateResponseMixin), dan menimpa penerapan dari [`render_to_response()`](/id/2.0/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin.render_to_response) ke metode pembangunan sesuai tergantung pada jenis dari tanggapan yang pengguna minta:

```
from django.views.generic.detail import SingleObjectTemplateResponseMixin

class HybridDetailView(JSONResponseMixin, SingleObjectTemplateResponseMixin, BaseDetailView):
    def render_to_response(self, context):
        # Look for a 'format=json' GET argument
        if self.request.GET.get('format') == 'json':
            return self.render_to_json_response(context)
        else:
            return super().render_to_response(context)
```

Karena cara bahwa Python menyelesaikan metode melebihi batas, panggilan pada `super().render_to_response(context)` mengakhiri panggilan penerapan [`render_to_response()`](/id/2.0/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin.render_to_response) dari [`TemplateResponseMixin`](/id/2.0/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin).
