---
title: "Menulis aplikasi Django kedua anda, bagian 7"
version: 1.10
locale: id
source: https://docs.djangoproject.com/id/1.10/intro/tutorial07/
canonical: https://djangodocs.dev/id/1.10/intro/tutorial07/
---
# Menulis aplikasi Django kedua anda, bagian 7

Tutorial ini mulai dimana [Tutorial 6](/id/1.10/intro/tutorial06/) ditinggalkan. Kami melanjutkan aplikasi jejak pendapat Jaringan dan akan fokus pada menyesuaikan situs admin dibangkitkan-otomatis Django yang kami pertama jelajahi di [Tutorial 2](/id/1.10/intro/tutorial02/).

## Sesuaikan bentuk admin

Dengan mendaftarkan model `Question` dengan `admin.site.register(Question)`, Django dapat membangun bentuk perwakilan awal. Sering, anda akan menginginkan menyesuaikan bagaimana bentuk admin kelihatan dan bekerja. Anda akan melakukan ini dengan memberitahu Django pilihan anda ingin ketika anda mendaftar obyek.

Mari kita lihat bagaimana ini bekerja dengan mengurutkan kembali bidang di formulir sunting. Ganti baris `admin.site.register(Question)` dengan:

*polls/admin.py*

```
from django.contrib import admin

from .models import Question

class QuestionAdmin(admin.ModelAdmin):
    fields = ['pub_date', 'question_text']

admin.site.register(Question, QuestionAdmin)
```

Anda akan mengikuti corak ini -- buat sebuah kelas admin model, kemudian lewati dia sebagai argumen kedua ke `admin.site.register()` -- setiap saat anda butuh merubah pilihan admin untuk sebuah model.

Perubahan khusus ini diatas membuat "Tanggal penerbitan" datang sebelum bidang "Pertanyaan" :

![Fields have been reordered](intro/_images/admin07.png)

Ini tidak hebat dengan hanya dua bidang, tetapi untuk bentuk admin dengan lusinan bidang, memilih urutan intuitif adalah rincian kegunaan penting.

Dan berbicara formulir dengan lusinan bidang, anda mungkin ingin memisahkan formulir menjadi kumpulan bidang:

*polls/admin.py*

```
from django.contrib import admin

from .models import Question

class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question_text']}),
        ('Date information', {'fields': ['pub_date']}),
    ]

admin.site.register(Question, QuestionAdmin)
```

Unsur pertama dari setiap tuple di [`fieldsets`](/id/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.fieldsets) adalah judul dari fieldset. Ini adalah apa formulir kami kelihatan seperti sekarang:

![Form has fieldsets now](intro/_images/admin08t.png)

## Menambahkan obyek terhubung

OKE, kami mempunyai halaman admin Pertanyaan, tetapi `Question` mempunyai banyak `Choice`, dan halaman admin tidak menampilkan pilihan.

Masih.

Terdapat dua cara mengatasi masalah ini. Pertama mendaftar `Choice` dengan admin seperti kita lakikan dengan `Question` . Itu mudah:

*polls/admin.py*

```
from django.contrib import admin

from .models import Choice, Question
# ...
admin.site.register(Choice)
```

Sekarang "Pilihan" adalah pilihan tersedia di admin Django. Bentuk "Tambah pilihan" kelihatan seperti ini:

![Choice admin page](intro/_images/admin09.png)

Di bentuk itu, bidang "Pertanyaan" adalah kotak pilih mengandung setiap pertanyaan di basisdata. Django mengetahui bahwa [`ForeignKey`](/id/1.10/ref/models/fields/#django.db.models.ForeignKey) harus diwakilkan di admin sebagai kotal `<select>`. Di kasus kami, hanya satu pertanyaan ada di titik ini.

Juga catat tautan "Tambah lainnya" dekat ke "Pertanyaan". Setiap obyek dengan hubungan `ForeignKey`  ke lainnya mendapatkan ini untuk bebas. Ketika anda klik "Tambah Lainnya", anda akan mendapatkan jendela popup dengan bentuk "Tambah pertanyaan". Jika anda menambah pertanyaan di jendela itu dan klik "Simpan", Django akan menyimpan pertanyaan di basisdata dan secara dinamis menambahkannya sebagai pilihan terpilih pada bentuk "Tambah Pilihan" yang anda cari.

Tetapi, sungguh, ini bukan cara efisien dari menambahkan obyek `Choice` ke sistem. Akan lebih baik jika anda dapat menambahkan sekumpulan Pilihan langsung ketika anda membuat obyek `Question`. Mari kita membuatnya terjadi.

Pindahkan pemanggilan `register()` untuk model `Choice`. Lalu, sunting kode pendaftaran `Question` untuk dibaca:

*polls/admin.py*

```
from django.contrib import admin

from .models import Choice, Question

class ChoiceInline(admin.StackedInline):
    model = Choice
    extra = 3

class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question_text']}),
        ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
    ]
    inlines = [ChoiceInline]

admin.site.register(Question, QuestionAdmin)
```

Ini memberitahu Django: "obyek `Choice` sedang disunting pada halaman admin `Question`. Secara awal, cukup menyediakan bidang untuk 3 pilihan."

Muat halaman "Tambahan pertanyaan" untuk melihat bagaimana kelihatannya:

![Add question page now has choices on it](intro/_images/admin10t.png)

Dia bekerja seperti ini: Terdapat tiga bagian untuk Pilihan terhubung -- sesuai ditentukan oleh `extra` -- dan setiap waktu anda kembali ke halaman "Rubah" untuk obyek sudah-sibuat, anda mendapatkan tiga ekstra bagian lain.

Pada akhir tiga bagian saat ini anda akan menemukan sebuah tautan "Tambah Pilihan lain". Jika anda mengklik itu, bagian baru akan ditambahkan. Jika anda ingin memindahkan bagian ditambahkan, anda dapat mengklik pada X di atas kanan dari bagian ditambahkan. Catat bahwa anda tidak dapat memindahkan tiga bagian asli. Gambar ini menunjukkan sebuah bagian ditambahkan:

![Additional slot added dynamically](intro/_images/admin14t.png)

Satu masalah kecil, meskipun. Itu mengambil banyak lahan layar untuk menampilkan semua bidang untuk memasukkan obyek `Choice` terhubung. Untuk alasan itu, Django menawarkan cara disusun dalam tabel dari obyek terhubung berderet; anda hanya butuh merubah pernyataan `ChoiceInline` untuk membaca:

*polls/admin.py*

```
class ChoiceInline(admin.TabularInline):
    #...
```

Dengan `TabularInline` (daripada `StackedInline`), obyek terhubung ditampilkan lebih rapat, bentuk berbasiskan-tabel:

![Add question page now has more compact choices](intro/_images/admin11t.png)

Catat bahwa terdapat kolom "Hapus?" tambahan yang mengizinkan memindahkan baris ditambahkan menggunakan tombol "Tambah Pilihan Lain" dan baris telah disimpan.

## Sesuaiakan daftar perubahan admin

Sekarang bahwa halaman admin Question kelihatan bagus, mari kita membuat beberapa perubahan untuk "daftar rubah" halaman -- satu yang menampilkan semua pertanyaan di sistem.

Inilah yang terlihat seperti pada saat ini:

![Polls change list page](intro/_images/admin04t.png)

Secara awal, Django menampilkan `str()` dari setiap obyek. Tetapi terkadang itu akan lebih membantu jika kami dapat menampilkan bidang secara masing-masing. untuk melakukannya, gunakan pilihan admin [`list_display`](/id/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display), yang merupakan tuple dari nama bidang untuk ditampilkan, sebagai kolom, pada halaman daftar perubahan untuk obyek:

*polls/admin.py*

```
class QuestionAdmin(admin.ModelAdmin):
    # ...
    list_display = ('question_text', 'pub_date')
```

Hanya untuk ukuran bagus, mari kita juga sertakan cara `was_published_recently()` dari [Tutorial 2](/id/1.10/intro/tutorial02/):

*polls/admin.py*

```
class QuestionAdmin(admin.ModelAdmin):
    # ...
    list_display = ('question_text', 'pub_date', 'was_published_recently')
```

Sekarang pertanyaan halaman daftar perubahan kelihatan seperti ini:

![Polls change list page, updated](intro/_images/admin12t.png)

Anda dapat meng klik di kepala kolom untuk mengurutkan nilai tersebut -- kecuali di kasus kepala `was_published_recently`, karena mengurutkan berdasarkan keluaran dari cara sewenang-wenang tidak didukung. Juga catat bahwa kepala kolom untuk `was_published_recently` adalah, secara awal, nama dari cara (dengan garis bawah ditandai dengan spasi), dan setiap baris mengandung string mewakili dari keluaran.

Anda dapat memperbaiki itu dengan memberikan cara itu (di `polls/models.py`) sedikit atribut, seperti berikut:

*polls/models.py*

```
class Question(models.Model):
    # ...
    def was_published_recently(self):
        now = timezone.now()
        return now - datetime.timedelta(days=1) <= self.pub_date <= now
    was_published_recently.admin_order_field = 'pub_date'
    was_published_recently.boolean = True
    was_published_recently.short_description = 'Published recently?'
```

Untuk informasi lebih di properti cara ini, lihat [`list_display`](/id/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display).

Sunting berkas `polls/admin.py` anda kembali dan tambah perbaikan ke halaman daftar perubahan `Question` : saringan menggunakan [`list_filter`](/id/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter). Tambah baris berikut ke `QuestionAdmin`:

```
list_filter = ['pub_date']
```

Itu menambahkan batang sisi "Saringan" yang membiarkan orang menyaring daftar perubahan dengan bidang `pub_date`:

![Polls change list page, updated](intro/_images/admin13t.png)

Jenis dari saringan ditampilkan tergantung pada jenis dari bidang anda saringkan. karena `pub_date` adalah sebuah [`DateTimeField`](/id/1.10/ref/models/fields/#django.db.models.DateTimeField), Django mengetahui untuk memberikan pilihan saringan sesuai: "Tanggal kapanpun", "7 hari terakhir"," Bulan ini", "Tahun ini".

Ini adalah pembentukan baik. Mari kita menambahkan beberapa kemampuan pencarian

```
search_fields = ['question_text']
```

Itu menambah kotak pencarian di bagian atas dari daftar rubah. Ketika seseorang memasukkan istilah pencarian, Django akan mencari bidang `question_text`. Anda dapat menggunakan sebanyak bidang anda suka -- meskipun karena itu menggunakan query `LIKE` dibelakang layar, membatasi angka bidan gpencarian untuk angka yang beralasan akan membuatnya mudah bagi basisdata anda melakukan pencarian.

Sekarang juga waktu bagus untuk mencatat bahwa daftar perubahan diberikan ke anda bebas halaman Awalnya adalah menampilkan 100 barang per halaman. [`Change list pagination`](/id/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_per_page), [`search boxes`](/id/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.search_fields), [`filters`](/id/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter), [`date-hierarchies`](/id/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.date_hierarchy), dan [`column-header-ordering`](/id/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display) semua kerja bersama seperti anda berpikir mereka seharusnya.

## Sesuaikan admin lihat dan rasakan

Jelas, mempunyai "Administrasi Django" pada atas dari setiap halaman admin adalah menggelikan. Itu adalah hanya teks placeholder.

Itu mudah dirubah, meskipun, menggunakan sistem cetakan Django. Admin Django di ditenagai oleh Django itu sendiri, dan antarmukanya menggunakan sistem cetakan Django sendiri.

### Menyesuaikan cetakan *proyek* anda

Buat sebuah direktori `templates` di proyek direktori anda (satu yang mengandung `manage.py`). Cetakan dapat berada di mana saja di sistem berkas anda yang Django dapat akses. (Django berjalan saat pengguna apapun peladen anda berjalan.) Bagaimanapun, menjaga cetakan dalam proyek adalah kebiasaan bagus untuk diikuti.

Buka berkas pengaturan anda (`mysite/settings.py`, ingat) dan tambah pilihan [`DIRS`](/id/1.10/ref/settings/#std-setting-TEMPLATES-DIRS) di pengaturan [`TEMPLATES`](/id/1.10/ref/settings/#std-setting-TEMPLATES) :

*mysite/settings.py*

```
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
```

[`DIRS`](/id/1.10/ref/settings/#std-setting-TEMPLATES-DIRS) adalah daftar dari direktori sistem berkas untuk memeriksa ketika memuat cetakan Django; dia adalah jalur pencarian.

> **Mengatur cetakan**
>
> Seperti berkas-berkas tetap, kami *dapat* mempunyai semua cetakan kami bersama-sama, dalam satu pelipat cetakan besar, dan itu bekerja dengan baik. Bagaimanapun, cetakan-cetakan yang milik aplikasi tertentu harus ditempatkan di pelipat cetakan aplikasi itu (sebagai contoh `polls/templates`) daripada (`templates`) proyek. Kami akan mengobrol lebih rinci di [reusable apps tutorial](/id/1.10/intro/reusable-apps/) *mengapa* kami melakukan ini.

Sekarang buat sebuah direktori disebut `admin` didalam `templates`, dan salin cetakan `admin/base_site.html` dari dalam direktori cetakan admin Django awal di kode sumber dari Django itu sendiri (`django/contrib/admin/templates`) kedalam direktori itu.

> **Dimana berkas sumber Django?**
>
> Jika anda mempunyai kesulitan dimana berkas sumber Django ditempatkan di sistem anda, jalankan perintah berikut:
>
> ```console
> $ python -c "import django; print(django.__path__)"
> ```

Kemudian, hanya sunting berkas dan ganti `{{ site_header|default:_('Django administration') }}` (termasuk kurung kurawal) dengan nama situs anda sendiri seperti kelihatan pas. Anda harus akhiri dengan bagian dari kode seperti:

```html+django
{% block branding %}
<h1 id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a></h1>
{% endblock %}
```

Kami menggunakan pendekatan ini untuk mengajarkan anda bagaimana menimpa cetakan. Di proyek sesungguhnya, anda mungkin menggunakan atribut [`django.contrib.admin.AdminSite.site_header`](/id/1.10/ref/contrib/admin/#django.contrib.admin.AdminSite.site_header) untuk lebih mudah membuat penyesuaian tertentu.

Berkas cetakan ini mengandung banyak teks seperti `{% block branding %}` dan `{{ title }}`. Etiket `{%` dan `{{` adalah bagian dari bahasa cetakan Django. Ketika Django membangun `admin/base_site.html`, bahasa cetakan akan menilai untuk menghasilkan halaman HTML akhir, sama seeprti kami lihat di [Tutorial 3](/id/1.10/intro/tutorial03/).

Catat bahwa apapun dari cetakan admin awal Django dapat ditimpa. Untuk menimpa cetakan, hanya lakukan hal sama anda lakukan dengan `base_site.html` -- salin itu dari direktori awal ke dalam direktori penyesuaian anda, dan buat perubahan.

### Menyesuaikan cetakan *aplikasi* anda

Pembaca cerdik akan bertanya: Tetapi jika [`DIRS`](/id/1.10/ref/settings/#std-setting-TEMPLATES-DIRS) kosong secara awal, bagaimana Django menemukan cetakan admin awal? Jawabannya adalah, sejak [`APP_DIRS`](/id/1.10/ref/settings/#std-setting-TEMPLATES-APP_DIRS) disetel ke `True`, Django otomatis mencari subdirektori `templates/` dalam setiap paket aplikasi, untuk digunakan sebagai kembali (jangan lupa bahwa `django.contrib.admin` adalah sebuah aplikasi).

Aplikasi jejak pendapat kami tidak sangat rumit dan tidak butuh penyesuaian cetakan admin. Tetapi jika itu tumbuh lebih mutkahir dan membutuhkan perubahan dari cetakan admin standar Django untuk beberapa fungsinya, itu akan lebih bijaksana untuk merubah cetakan *aplikasi*, daripada itu di *proyek*. Lewat situ, anda dapat menyertakan aplikasi jejak pendapat di proyek baru apapun dan terjamin bahwa dia akan menemukan cetakan penyesuaian dia butuhkan.

Lihat [dokumentasi memuat cetakan](/id/1.10/topics/templates/#template-loading) untuk informasi lebih tentang bagaimana Django menemukan cetakannya.

## Sesuaikan halaman index admin

Pada catatan sama, anda mungkin ingin menyesuaikan penampilan dan rasa dari halaman index admin Django.

Secara awal, dia menampilkan semua aplikasi di [`INSTALLED_APPS`](/id/1.10/ref/settings/#std-setting-INSTALLED_APPS) yang telah didaftarkan dengan aplikasi admin, dalam urutan alfabet. Anda mungkin ingin membuat perubahan signifikan pada tata letak. Lagi pula, index mungkin halaman paling penting dari admin, dan dia harus mudah digunakan.

Cetakan untuk menyesuaian adalah `admin/index.html`. (Lakukan sama dengan `admin/base_site.html` di bagian sebelumnya --  salin dia dari direktori awal ke direktori cetakan penyesuaian anda). Sunting berkas, dan anda akan melihatnya menggunakan ceriabel cetakan dipanggil `app_list`. Variabel itu mengandung setiap aplikasi Django terpasang. Dari pada menggunakan itu, anda dapat kode-keras tautan ke halaman admin di jalan apapun anda pikir terbaik.

## Apa Selanjutnya?

Tutorial pemula berakhir disini. Sementara itu, anda mungkin ingin memeriksa beberapa titik di [kemana pergi dari sini](/id/1.10/intro/whatsnext/).

Jika anda akrab dengan pemaketan Phyton dan tertarik dalam belajar bagaimana mengubah jejak pendapat menjadi "aplikasi digunakan kembali", periksa  [Tutorial Lanjut: Bagaimana menulis aplikasi digunakan kembali](/id/1.10/intro/reusable-apps/).
