[ English | 中文 (简体, 中国) | русский | português (Brasil) | नेपाली | 한국어 (대한민국) | Indonesia | français | español | esperanto | English (United Kingdom) | Deutsch ]

Panduan Topik DataTables

Horizon menyediakan modul :mod: horizon.tables untuk menyediakan API yang nyaman dan dapat digunakan kembali untuk membangun tampilan dan antarmuka berbasis data. Komponen inti dari API ini terbagi dalam tiga kategori: DataTables, Actions, dan Class-based Views.

Lihat juga

Untuk informasi API terperinci, periksa Horizon DataTables.

Tables

Mayoritas antarmuka dalam antarmuka dashboard-style akhirnya menjadi tampilan tabular dari berbagai sumber daya yang berinteraksi dengan dasbor. Kelas DataTable ada sehingga Anda tidak perlu menemukan kembali roda (wheel) setiap kali.

Membuat tabel Anda sendiri

Membuat tabel cukup sederhana:

  1. Buat subkelas dari DataTable.

  2. Tentukan kolom di atasnya menggunakan Column.

  3. Buat kelas inner Meta untuk memuat opsi-opsi khusus untuk tabel ini.

  4. Tentukan tindakan apa pun untuk tabel, dan tambahkan ke table_actions atau row_actions.

Contoh dari ini dapat ditemukan di modul tables.py yang termasuk dalam modul referensi di bawah horizon.dashboards.

Menghubungkan tabel ke tampilan

Setelah table Anda diatur sesuai keinginan Anda, langkah selanjutnya adalah menghubungkannya ke tampilan. Untuk membuat ini semudah mungkin, Horizon menyediakan DataTableView tampilan berbasis kelas yang dapat disubklasifikasikan untuk menampilkan tabel Anda hanya dengan beberapa baris kode. Paling sederhana, terlihat seperti ini

from horizon import tables
from .tables import MyTable


class MyTableView(tables.DataTableView):
    table_class = MyTable
    template_name = "my_app/my_table_view.html"

    def get_data(self):
        return my_api.objects.list()

Dalam templat Anda hanya perlu menyertakan hal berikut untuk membuat (render) tabel:

{{ table.render }}

Itu dia! Mudah kan?

Actions

Tindakan terdiri dari manipulasi yang mungkin terjadi pada data dalam tabel atau tabel itu sendiri. Sebagai contoh, ini mungkin objek CRUD standar, menghubungkan ke tampilan terkait berdasarkan id objek, memfilter data dalam tabel, atau mengambil data yang diperbarui bila perlu.

Ketika tindakan dijalankan

Ada dua poin dalam siklus request-response di mana tindakan dapat terjadi; sebelum data dimuat ke dalam tabel, dan setelah data dimuat. Saat Anda menggunakan salah satu tampilan berbasis kelas pre-built untuk bekerja dengan tabel Anda, pseudo-workflow terlihat seperti ini:

  1. Permintaan memasuki tampilan.

  2. Kelas tabel dipakai tanpa data.

  3. Semua tindakan "preemptive" diperiksa untuk melihat apakah tindakan tersebut harus dijalankan.

  4. Data diambil dan dimuat ke dalam tabel.

  5. Semua tindakan lain diperiksa untuk melihat apakah tindakan tersebut harus dijalankan.

  6. Jika tanpa tindakan menyebabkan keluar awal dari tampilan, respons standar dari tampilan dikembalikan (biasanya tabel yang rendered).

Manfaat dari instantiation tabel multi-step adalah bahwa Anda dapat menggunakan tindakan pencegahan yang tidak memerlukan akses ke seluruh kumpulan data untuk menyelamatkan diri Anda dari pemrosesan overhead, panggilan API, dll.

Tindakan dasar

Paling sederhana, ada tiga jenis tindakan: tindakan yang bertindak atas data dalam tabel, tindakan yang menautkan ke sumber daya terkait, dan tindakan yang mengubah data mana yang ditampilkan. Ini sesuai dengan Action, LinkAction, dan FilterAction.

Menulis tindakan Anda sendiri biasanya dimulai dengan mensubklasifikasikan salah satu kelas tindakan tersebut dan menyesuaikan atribut dan metode yang ditunjuk.

Tindakan pintas

Ada beberapa tugas umum yang Horizon menyediakan kelas pintas yang sudah dibangun sebelumnya. Ini termasuk BatchAction, and DeleteAction. Masing-masing abstrak ini menghilangkan hampir semua boilerplate yang terkait dengan penulisan jenis tindakan ini dan memberikan penanganan kesalahan yang konsisten, pencatatan, dan interaksi yang dihadapi pengguna.

Perlu dicatat bahwa BatchAction dan `` DeleteAction`` adalah ekstensi dari kelas Action standar. Beberapa kelas BatchAction atau DeleteAction dapat menyebabkan beberapa hasil yang tidak dapat dipulihkan, seperti image yang dihapus atau instance yang tidak dapat dipulihkan. Mungkin bermanfaat untuk menentukan help_text spesifik untuk menjelaskan masalah kepada pengguna, seperti "Deleted images are not recoverable".

Tindakan pencegahan

Kelas tindakan yang memiliki atribut preempt yang disetel ke True akan dievaluasi sebelum data dimasukkan ke dalam tabel. Karena itu, Anda harus berhati-hati untuk tidak bergantung pada metode tabel apa pun yang memerlukan data, seperti get_object_display() atau get_object_by_id(). Keuntungan dari tindakan pencegahan adalah bahwa Anda dapat menghindari keharusan melakukan semua pemrosesan, panggilan API, dll. yang terkait dengan memuat data ke dalam tabel untuk tindakan yang tidak memerlukan akses ke informasi itu.

Kebijakan memeriksa tindakan

Atribut :attr: ~ horizon.tables.Action.policy_rules, ketika disetel, akan memvalidasi akses ke tindakan menggunakan aturan kebijakan yang ditentukan. Atribut adalah daftar pasangan ruang lingkup/aturan (scope/rule pairs). Di mana ruang lingkup adalah jenis layanan yang mendefinisikan aturan dan aturan adalah aturan dari file policy.json layanan yang sesuai. Format :attr: horizon.tables.Action.policy_rules terlihat seperti:

(("identity", "identity:get_user"),)

Beberapa pemeriksaan dapat dilakukan untuk tindakan yang sama hanya dengan menambahkan lebih banyak tuple ke daftar. Pemeriksaan kebijakan akan menggunakan informasi yang disimpan dalam sesi tentang pengguna dan hasil dari get_policy_target() (yang dapat ditimpa dalam kelas tindakan yang diturunkan) untuk menentukan apakah pengguna dapat melakukan tindakan. Jika pengguna tidak memiliki akses ke tindakan, tindakan itu tidak ditambahkan ke tabel.

Jika :attr: ~ horizon.tables.Action.policy_rules tidak disetel, tidak ada pemeriksaan kebijakan yang akan dilakukan untuk menentukan apakah tindakan tersebut akan terlihat dan akan ditampilkan hanya berdasarkan hasil dari allowed().

Untuk informasi lebih lanjut tentang Role Based Access Control berdasarkan kebijakan, lihat Horizon Policy Enforcement (RBAC: Role Based Access Control).

Filter Sel Table (dekorator)

DataTable menampilkan daftar objek dalam baris dan atribut objek dalam sel. Bagaimana seharusnya kita melanjutkan, jika kita ingin menghias beberapa kolom, misal jika kita memiliki kolom memory yang mengembalikan angka misal 1024, dan kami ingin menampilkan sekitar 1024.00 GB di dalam tabel?

Pola dekorator

Anti-pola yang jelas mendefinisikan atribut baru pada objek seperti ram_float_format_2_gb atau untuk mengubah DataTable dengan cara apa pun untuk menampilkan tujuan.

Cara terbersih adalah dengan menggunakan filter. Filter adalah dekorator, mengikuti GOF Decorator pattern. Dengan cara ini DataTable logic dan displayed object logic dipisahkan dengan benar dari presentation logic dari objek di dalam berbagai tabel. Dan karenanya filter dapat digunakan kembali di semua tabel.

Fungsi filter

Horizon DatablesTable mengambil tuple pointer untuk memfilter fungsi atau fungsi lambda anonim. Saat menampilkan Cell, DataTable mengambil fungsi filter Column dari kiri ke kanan, menggunakan nilai yang dikembalikan dari fungsi sebelumnya sebagai parameter dari fungsi berikut. Kemudian menampilkan nilai yang dikembalikan dari fungsi filter terakhir.

Fungsi filter yang valid mengambil satu parameter dan mengembalikan nilai yang didekorasi. Misal, ini adalah fungsi filter yang valid

# Filter function.
def add_unit(v):
  return str(v) + " GB"

# Or filter lambda function.
lambda v: str(v) + " GB"

# This is also a valid definition of course, although for the change of the
# unit parameter, function has to be wrapped by lambda
# (e.g. floatformat function example below).
def add_unit(v, unit="GB"):
  return str(v) + " " + unit

Menggunakan filter di kolom DataTable

DataTable mengambil tuple fungsi filter, misal ini adalah dekorasi nilai yang valid dengan format float dan dengan unit

ram = tables.Column(
    "ram",
    verbose_name=_('Memory'),
    filters=(lambda v: floatformat(v, 2),
             add_unit))

Itu selalu membutuhkan tuple, jadi hanya menggunakan satu filter akan terlihat seperti ini

filters=(lambda v: floatformat(v, 2),)

Parameter yang didekorasi tidak harus berupa string atau angka, itu bisa berupa apa saja, misal daftar atau objek. Jadi dekorasi objek, yang memiliki nilai atribut dan unit akan terlihat seperti ini

ram = tables.Column(
        "ram",
        verbose_name=_('Memory'),
        filters=(lambda x: getattr(x, 'value', '') +
                 " " + getattr(x, 'unit', ''),))

Filter yang tersedia

Ada banyak filter, yang dapat digunakan, sudah didefinisikan dalam Django: https://github.com/django/django/blob/master/django/template/defaultfilters.py

Jadi cukup mengimpor dan menggunakannya saja, misal

from django.template import defaultfilters as filters

# code omitted
filters=(filters.yesno, filters.capfirst)


from django.template.defaultfilters import timesince
from django.template.defaultfilters import title

# code omitted
filters=(parse_isotime, timesince)

Pengeditan sebaris

Sel tabel dapat dengan mudah ditingkatkan dengan mengedit in-line. Dengan menggunakan django.form.Field, kami dapat menjalankan validasi bidang dan mem-parsing data dengan benar. Proses pembaruan sepenuhnya dienkapsulasi ke dalam fungsi tabel, komunikasi dengan server melewati AJAX dalam format JSON. Pembungkus javascript untuk pengeditan in-line memungkinkan setiap sel tabel yang memiliki pengeditan in-line tersedia untuk:

  1. Refresh sendiri dengan data baru dari server.

  2. Tampilan dalam mode edit.

  3. Kirim data yang diubah ke server.

  4. Menampilkan kesalahan validasi.

Pada dasarnya ada 3 hal yang perlu didefinisikan dalam tabel untuk memungkinkan pengeditan in-line.

Mengambil data baris (row data)

Mendefinisikan metode get_data di kelas yang diwarisi dari tables.Row. Metode ini menangani pengambilan data baris. Kelas ini kemudian harus didefinisikan dalam tabel kelas Meta sebagai row_class = UpdateRow.

Contoh:

class UpdateRow(tables.Row):
    # this method is also used for automatic update of the row
    ajax = True

    def get_data(self, request, project_id):
        # getting all data of all row cells
        project_info = api.keystone.tenant_get(request, project_id,
                                               admin=True)
        return project_info

Menentukan form_field untuk setiap Column yang ingin diedit sebaris.

Bidang formulir harus berupa django.form.Field, jadi kita dapat menggunakan validasi django dan mem-parsing nilai yang dikirim oleh POST (misalnya validasi required=True dan penguraian yang benar dari nilai kotak centang dari POST data).

Form field juga bisa menjadi kelas django.form.Widget, jika kita hanya perlu menampilkan widget formulir di tabel dan kita tidak memerlukan fungsionalitas Field.

Kemudian menghubungkan kelas UpdateRow dan UpdateCell ke tabel.

Contoh:

class TenantsTable(tables.DataTable):
    # Adding html text input for inline editing, with required validation.
    # HTML form input will have a class attribute tenant-name-input, we
    # can define here any HTML attribute we need.
    name = tables.Column('name', verbose_name=_('Name'),
                         form_field=forms.CharField(),
                         form_field_attributes={'class':'tenant-name-input'},
                         update_action=UpdateCell)

    # Adding html textarea without required validation.
    description = tables.Column(lambda obj: getattr(obj, 'description', None),
                                verbose_name=_('Description'),
                                form_field=forms.CharField(
                                    widget=forms.Textarea(),
                                    required=False),
                                update_action=UpdateCell)

    # Id will not be inline edited.
    id = tables.Column('id', verbose_name=_('Project ID'))

    # Adding html checkbox, that will be shown inside of the table cell with
    # label
    enabled = tables.Column('enabled', verbose_name=_('Enabled'), status=True,
                            form_field=forms.BooleanField(
                                label=_('Enabled'),
                                required=False),
                            update_action=UpdateCell)

    class Meta(object):
        name = "tenants"
        verbose_name = _("Projects")
        # Connection to UpdateRow, so table can fetch row data based on
        # their primary key.
        row_class = UpdateRow