# dokumentasi Django 2.2.9.dev20191202104323

# Tampilan umum berdasarkan kelas siap-pakai

Menulis aplikasi Jaringan dapat menjadi membosankan, karena kami mengulangi pola tertentu lagi dan lagi. Django mencoba mengambil beberapa dari kebosanan pada model dan lapisan cetakan, tetapi pengembang Jaringan juga mengalami kebosanan ini pada tingkat tampilan.

tampilan umum Django dikembangkan untuk memudahkan sakit itu. Mereka mengambil dialek umum tertentu dan pola ditemukan di pengembangan tampilan dan meringkaskan mereka sehingga anda dapat dengan cepat menulis tampilan umum dari data tanpa harus menulis kode terlalu banyak.

Kami dapat mengenali tugas-tugas umum, seperti memperlihatkan daftar dari obyek, dan menulis kode yang memperlihatkan daftar dari obyek apapun. Kemudian model di pertanyaan dapat dilewatkan sebagai sebuah argumen tambahan pada URLconf.

Django dibungkus dengan tampilan umum untuk melakukan berikut:

- Memperlihatkan daftar dan halaman rincian untuk obyek tunggal. Jika kami sedang membuat sebuah aplikasi untuk mengelola pertemuan kemudian `TalkListView` dan `RegisteredUserListView` akan menjadi contoh dari daftar tampilan. Halaman percakapan tunggal adalah sebuah contoh dari apa kami sebut tampilan "detail".
- Obyek berdasarkan-tanggal sekarang di halaman arsip tahun/bulan/hari, rincian terkait, dan halaman "latest".
- Mengizinkan untuk membuat, memperbaharui, dan menghapus obyek -- dengan atau tanpa otorisasi.

Diambil bersama-sama, tampilan ini menyediakan antarmuka mudah untuk melakukan tugas-tugas paling umum pengembang hadapi.

## Memperpanjang tampilan umum

Tidak ada pertanyaan yang menggunakan tampilan umum yang dapat mempercepat pengembangan besar. Dalam kebanyakan proyek, bagaimanapun, ada datang saat ketika tampilan umum tidak lagi cukup. Memang, pertanyaan paling umum ditanyakan oleh pengembang Django baru adalah bagaimana membuat tampilan umum menangangi larik lebih lebar dari keadaan.

Ini adalah satu dari alasan umtum tampilan dirancang kembali untuk terbitan 1.3 - sebelumnya, mereka hanya fungsi tampilan dengan membingungkan dari pilihan; sekarang daripada melewatkan di sejumlah besar konfigurasi di URLconf, cara dianjurkan untuk memperpanjang tampilan umum adalah dengan mensubkelaskan mereka, dan menimpa atribut dan metodenya.

Itu dikatakan, tampilan umum akan mempunyai sebuah batasan. Jika anda menemukan anda sedang berjuang menerapkan tampilan anda sebagai sebuah subkelas dari tampilan umum, kemudian anda mungkin menemukan itu lebih efektif untuk menulis hanya kode anda butuhkan, menggunakan berdasarkan-kelas anda sendiri atau tampilan kegunaan.

Contoh-contoh lebih dari tampilan umum tersedia di beberapa aplikasi pihak ketiga, atau anda dapat menulis anda sendiri sesuai kebutuhan.

## Tampilan umum dari obyek

`TemplateView` pasti sangat berguna, tetapi tampilan umum Django sangat bersinar ketika itu datang untuk membawakan tampilan dari isi basisdata anda. Karena itu adalah tugas umum, Django datang dengan sejumlah tampilan umum siap-pakai yang membuat membangkitkan daftar dan rincian tampilan dari obyek sangat mudah.

Mari kita mulai dengan mencari beberapa contoh dari menunjukkan daftar dari obyek atau obyek tersendiri.

Kami akan menggunakan model ini

    # models.py
    from django.db import models

    class Publisher(models.Model):
        name = models.CharField(max_length=30)
        address = models.CharField(max_length=50)
        city = models.CharField(max_length=60)
        state_province = models.CharField(max_length=30)
        country = models.CharField(max_length=50)
        website = models.URLField()

        class Meta:
            ordering = ["-name"]

        def __str__(self):
            return self.name

    class Author(models.Model):
        salutation = models.CharField(max_length=10)
        name = models.CharField(max_length=200)
        email = models.EmailField()
        headshot = models.ImageField(upload_to='author_headshots')

        def __str__(self):
            return self.name

    class Book(models.Model):
        title = models.CharField(max_length=100)
        authors = models.ManyToManyField('Author')
        publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
        publication_date = models.DateField()

Sekarang kami butuh menentukan sebuah tampilan:

    # views.py
    from django.views.generic import ListView
    from books.models import Publisher

    class PublisherList(ListView):
        model = Publisher

Akhirnya kaitkan tampilan itu kedalam url anda

    # urls.py
    from django.urls import path
    from books.views import PublisherList

    urlpatterns = [
        path('publishers/', PublisherList.as_view()),
    ]

Itu saja semua kode Python kami butuh tulis. Kami masih butuh menulis sebuah cetakan, bagaimanapun. Kami dapat dengan jelas memberitahu tampilan cetakan mana untuk digunakan dengan menambahkan atribut `template_name`, tetapi di kehadiran dari Django cetakan jelas akan mengambil kesimpulan satu dari nama obyek. Dalam kasus ini, cetakan kesimpulan akan menjadi `"books/publisher_list.html"` -- bagian "books" berasal dari nama dari aplikasi yang menentukan model, selagi sedikit "publisher" hanya versi huruf kecil dari nama model.

Catatan

Dengan demikian, ketika (sebagai contoh) pilihan `APP_DIRS` dari backend `DjangoTemplates` disetel menjadi True di `TEMPLATES`, tempat cetakan dapat berupa: /path/to/project/books/templates/books/publisher_list.html

Cetakan ini akan dibangun terhadap konteks mengandung sebuah variabel disebut `object_list` yang mengandung semua obyek penerbit. Cetakan sangat sederhana mungkin terlihat seperti berikut:

    {% extends "base.html" %}

    {% block content %}
        <h2>Publishers</h2>
        <ul>
            {% for publisher in object_list %}
                <li>{{ publisher.name }}</li>
            {% endfor %}
        </ul>
    {% endblock %}

Itu semua benar-benar ada adalah pada itu. Semua fitur-fitur keren dari tampilan umum datang dari merubah atribut disetel pada tampilan umum. generic views reference mendokumentasikan semua tampilan umum dan pilihan mereka di rincian; sisa dari dokumen ini akan dianggap beberapa dari cara umum anda mungkin menyesuaikan dan memperpanjang tampilan umum.

### Membuat konteks cetakan "friendly"

Anda mungkin telah memperhatikan bahwa contoh cetakan daftar penerbit kami menyimpan semua penerbit dalam sebuah variabel bernama `object_list`. Selagi ini bekerja baik, itu tidak semua yang "friendly" pada cetakan penulis: mereka harus "just know" bahwa mereka sedang berurusan dengan penerbit disini.

Well, if you're dealing with a model object, this is already done for you. When you are dealing with an object or queryset, Django is able to populate the context using the lowercased version of the model class' name. This is provided in addition to the default `object_list` entry, but contains exactly the same data, i.e. `publisher_list`.

Jika ini masih tidak kecocokan baik, anda dapat manual menyetel nama dari variabel konteks. Atribut `context_object_name` pada tampilan umum menentukan variabel konteks untuk digunakan:

    # views.py
    from django.views.generic import ListView
    from books.models import Publisher

    class PublisherList(ListView):
        model = Publisher
        context_object_name = 'my_favorite_publishers'

Menyediakan sebuah `context_object_name` berguna selalu ide bagus. Rekan kerja anda yang merancang cetakan akan berterima kasih.

### Menambahkan konteks tambahan

Sering anda cukup butuh menghadirkan beberapa informasi tambahan yang disediakan oleh tampilan umum. Sebagai contoh, berpikir dari menunjukkan daftar semua buku pada setiap halaman rincian penerbit. Tampilan umum `DetailView` menyediakan penerbit ke konteks, tetapi bagaimana kami mendapatkan informasi tambahan di cetakan itu?

Jawabannya adalah untuk mensubkelaskan `DetailView` dan menyediakan penerapan milik anda sendiri dari metode `get_context_data`. Penerapan awalan cukup menambahkan obyek sedang ditampilkan pada cetakan, tetapi anda dapat menimpanya untuk mengirim lagi:

    from django.views.generic import DetailView
    from books.models import Book, Publisher

    class PublisherDetail(DetailView):

        model = Publisher

        def get_context_data(self, **kwargs):
            # Call the base implementation first to get a context
            context = super().get_context_data(**kwargs)
            # Add in a QuerySet of all the books
            context['book_list'] = Book.objects.all()
            return context

Catatan

Umumnya, `get_context_data` akan menggabungkan data konteks dari semua induk kelas dengan mereka dari kelas saat ini. Untuk mempertahankan kebiasaan ini di kelas milik anda sendiri dimana anda ingin merubah konteks, anda harus pasti memanggil `get_context_data` pada super kelas. Ketika tidak ada dua kelas mencoba menentukan kunci yang sama, ini akan memberikan hasil yang diharapkan. Bagaimanapun jika tiap kelas mencoba menimpa kunci setelah kelas induk menyetelnya (setelah panggilan pada super), tiap anak dari kelas akan juga butuh secara eksplisit menyetelnya setelah super jika mereka ingin memastikan untuk menimpa semua induk. Jika anda mempunyai masalah, tinjau kembali urutan pemecahan metode dari tampilan anda.

Pertimbangan lain adalah bahwa data konteks dari tampilan umum berdasarkan-kelas akan menimpa data disediakan oleh pengolah konteks; lihat `get_context_data()` untuk sebuah contoh.

### Menampilkan subkumpulan dari obyek

Sekarang mari kita lebih dekat melihat pada argumen `model` kami telah sepanjang gunakan. Argumen `model`, yang menentukan model basisdata yang tampilan akan beroperasi, tersedia pada seua tampilan umum yang beroperasi pada obyek tunggal atau kumpulan dari obyek. Bagaimanapun, argumen `model` tidak hanya cara untuk menentukan obyek yang tampilan akan beroperasi -- anda dapat juga menentukan daftar dari obyek menggunakan argumen `queryset`:

    from django.views.generic import DetailView
    from books.models import Publisher

    class PublisherDetail(DetailView):

        context_object_name = 'publisher'
        queryset = Publisher.objects.all()

Menentukan model = Publisher` adalah hanya tulisan cepat untuk mengatakan `queryset = Publisher.objects.all()`. Bagaimanapun, dengan menggunakan `queryset` untuk menentukan daftar disaring dari obyek anda dapat lebih khususkan tentang obyek yang akan muncul di tampilan (lihat Membuat query untuk informasi lebih tentang obyek `QuerySet`, dan lihat class-based views reference untuk rincian lengkap).

Untuk mengambil sebuah contoh sederhana, kami mungkin ingin mengurutkan daftar dari buku-buku dari tanggal terbit, dengan pertama paling terbaru:

    from django.views.generic import ListView
    from books.models import Book

    class BookList(ListView):
        queryset = Book.objects.order_by('-publication_date')
        context_object_name = 'book_list'

Itu adalah contoh sederhana cantik, tetapi itu menggambarkan ide sangat bagus. Tentu saja, anda akan biasanya ingin melakukan lebih daripada mengurutkan kembali obyek. Jika anda ingin menghadirkan daftar buku oleh penerbit tertentu, anda dapat menggunakan teknis sama:

    from django.views.generic import ListView
    from books.models import Book

    class AcmeBookList(ListView):

        context_object_name = 'book_list'
        queryset = Book.objects.filter(publisher__name='ACME Publishing')
        template_name = 'books/acme_list.html'

ikan bahwa selama dengan `queryset` disaring, kami juga menggunakan nama cetakan penyesuaian. Jika kami tidak, tampilan umum akan menggunakan cetakan sama seperti daftar obyek "vanilla", yang mungkin tidak kita inginkan.

Juga perharikan bahwa ini bukan cara sangat elegan dari melakukan buku khusus-penerbit. Jika kami ingin menambah halaman penerbit lain, kami butuh bantuan lain dari baris di URLconf, dan lebih dari sedikit penerbit akan mendapatkan alasan tidak masuk akal. Kami akan berurusan dengan masalah ini di bagian selanjutnya.

Catatan

Jika anda mendapatkan sebuah 404 ketika meminta `/books/acme/`, periksa untuk memastikan anda sebenarnya mempunyai sebuah Publisher dengan nama 'ACME Publishing'. Tampilan umum mempunyai sebuah parameter `allow_empty` untuk kasus ini. Lihat class-based-views reference untuk rincian.

### Menyaring dinamis

Kebutuhan umum lain adalah menyaring kebawah obyek yang diberikan di halaman daftar dengan beberapa kunci di URL. Awalnya kami mengkode-keraskan nama penerbit di URLconf, tetapi apa jika kami ingin menulis sebuah tampilan yang menampilkan semua buku oleh beberapa penerbit berubah-ubah?

Dengan mudah, `ListView` mempunyai sebuah metode `get_queryset()` kami dapat timpa. Sebelumnya, itu telah mengembalikan nilai dari atribut `queryset`, tetapi sekarang kami dapat menambah lebih logika.

Bagian kunci membiat ini bekerja adalah bahwa ketika tampilan berdasarkan-kelas dipanggil, beragam hal-hal berguna disimpan di `self`; sama halnya permintaan (`self.request`) ini menyertakan penempatan (`self.args`) dan argumen (`self.kwargs`) berdasarkan-nama menurut URLconf.

Disini, kami mempunyai URLconf dengan kelompok ditangkap tunggal:

    # urls.py
    from django.urls import path
    from books.views import PublisherBookList

    urlpatterns = [
        path('books/<publisher>/', PublisherBookList.as_view()),
    ]

Selanjutnya, kami akan menulis tampilan `PublisherBookList` sendiri:

    # views.py
    from django.shortcuts import get_object_or_404
    from django.views.generic import ListView
    from books.models import Book, Publisher

    class PublisherBookList(ListView):

        template_name = 'books/books_by_publisher.html'

        def get_queryset(self):
            self.publisher = get_object_or_404(Publisher, name=self.kwargs['publisher'])
            return Book.objects.filter(publisher=self.publisher)

Seperti anda dapat lihat, itu adalah sangat mudah menambah logika lebih pada pemilihan queryset; jika kami ingin, kami dapat menggunakan `self.request.user` pada penyaring menggunakan pengguna saat ini, atau lebih logika rumit lain.

Kami dapat juga menambahkan penerbit kedalam konteks pada waktu bersamaan, jadi kami dapat menggunakannya di cetakan:

    # ...

    def get_context_data(self, **kwargs):
        # Call the base implementation first to get a context
        context = super().get_context_data(**kwargs)
        # Add in the publisher
        context['publisher'] = self.publisher
        return context

### Melakukan pekerjaan tambahan

Pola umum terakhir kami akan lihat pada melibatkan melakukan beberapa pekerjaan tambahan sebelum atau sesudah memanggil tampilan umum.

Bayangkan kami mempunyai sebuah bidang last_accessed` di model Author` kami yang kami sedang gunakanuntuk menjaga lintas dari waktu terakhir siapapun mencari penulis itu:

    # models.py
    from django.db import models

    class Author(models.Model):
        salutation = models.CharField(max_length=10)
        name = models.CharField(max_length=200)
        email = models.EmailField()
        headshot = models.ImageField(upload_to='author_headshots')
        last_accessed = models.DateTimeField()

Kelas `DetailView` umum, tentu saja, kami tidak akan mengetahui apapun tentang bidang ini, tetapi sekali lagi kami dapat dengan menudah menulis tampilan penyesuaian untuk menjaga bidang itu terperbaharui.

Pertama, kami butuh menambah rincian seorang penulis sedikit dalam URLconf untuk menunjuk pada tampilan penyesuaian:

    from django.urls import path
    from books.views import AuthorDetailView

    urlpatterns = [
        #...
        path('authors/<int:pk>/', AuthorDetailView.as_view(), name='author-detail'),
    ]

Kemudian kami akan menulis tampilan baru kami -- `get_object` adalah metode yang mengambil obyek -- jadi kami cukup menimpanya dan membungkus panggilan:

    from django.utils import timezone
    from django.views.generic import DetailView
    from books.models import Author

    class AuthorDetailView(DetailView):

        queryset = Author.objects.all()

        def get_object(self):
            obj = super().get_object()
            # Record the last accessed date
            obj.last_accessed = timezone.now()
            obj.save()
            return obj

Catatan

URLconf disini menggunakan kelompok bernama `pk` - nama ini adalah nama awalan yang `DetailView` menggunakan untuk menemukan nilai dari primary key digunakan untuk menyaring queryset.

Jika anda ingin memanggil kelompok sesuatu lain, anda dapat menyetel `pk_url_kwarg` pada tampilan. Rincian lebih dapat ditemukan di acuan untuk `DetailView`