# Dokumentasi Django 4.2.9.dev20231204082947

# Bagaimana membuat bidang model disesuaikan

## Kata Pengantar

Dokumentasi model reference menjelaskan bagaimana menggunakan kelas-kelas bidang standar Django -- `CharField`, `DateField`, dll. Untuk banyak tujuan, kelas-kelas tersebut adalah yang anda akan butuhkan. Terkadang, meskipun, versi Django tidak akan bertemu persyaratan tepat anda, atau anda akan menggunakan sebuah bidang yang seluruhnya berbeda dari yang dikemas dengan Django.

Jenis bidang siap pakai Django tidak mencangkup setiap jenis kolom basisdata yang mungkin -- hanya jenis umum, seperti `VARCHAR` dan `INTEGER`. Untuk lebih mengaburkan jenis kolom, seperti poligon geografis atau bahkan jenis dibuat-pengguna seperti PostgreSQL custom types, anda dapat menentukan subkelas-subkelas `Field` Django and sendiri.

Jalan lain, anda mungkin mempunyai obyek Python rumit yang dapat entah bagaimana disambungkan untuk cocok kedalam jenis kolom basisdata standar. Ini adalah kasus lain dimana sebuah subkelas `Field` akan membantu anda menggunakan obyek anda dengan model anda.

### Obyek contoh kami

Membuat penyesuaian bidang membuatuhkan sedikit perhatian ke rincian. Untuk membuat hal-hal lebih mudah untuk diikuti, kami akan menggunakan contoh tetap melalui dokumen ini: membungkus sebuah obyek Python mewakili persetujuan dari kartu-kartu dalam sebuah tangan dari Bridge. Jangan khawatir, anda tidak perlu mengetahui bagaimana bermain Bridge untuk mengikuti contoh ini. Anda hanya perlu mengetahui bahwa 52 kartu dibagikan sama ke empat pemain, yang secara tradisional dipanggil utara, timur, selatan dan barat. Kelas kami kelihatan seperti ini:

    class Hand:
        """A hand of cards (bridge style)"""

        def __init__(self, north, east, south, west):
            # Input parameters are lists of cards ('Ah', '9s', etc.)
            self.north = north
            self.east = east
            self.south = south
            self.west = west

        # ... (other possibly useful methods omitted) ...

Ini adalah kelas Python asli, dengan tidak ada Django-spesifik tentang itu. Kami ingin dapat melakukan hal-hal seperti ini dalam model kami (kami beranggapan atribut `hand` pada model adalah sebuah instance `Hand`):

    example = MyModel.objects.get(pk=1)
    print(example.hand.north)

    new_hand = Hand(north, east, south, west)
    example.hand = new_hand
    example.save()

Kami memberikan dan mengambil dari atribut `hand` dalam model kami seperti kelas Python lainnya. Tipuannya adalah mengatakan Django bagaimana menangani penyimpanan dan memuat sebuah obyek seperti itu.

Agar menggunakan kelas `Hand` di model kami, kami tidak harus merubah kelas ini sama sekali. Ini adalah cocok, karena dia berarti anda dapat dengan mudah menulis model mendukung kelas-kelas yang ada dimana anda tidak dapat merubah sumber kode.

Catatan

Anda mungkin hanya menginginkan untuk mengambil keuntungan dari penyesuaian jenis kolom basisdata dan berhubungan dengan data sebagai jenis Python standar dalam model anda; string, atau float, sebagai contoh. Kasus ini mirip pada contoh `hand` kami dan kami akan mencatat perbedaan ketika kita pergi bersama.

## Latar belakang teori

### Penyimpanan basisdata

Mari mulai dengan bidang model. Jika anda memecahnya, sebuah bidang model menyediakan cara untuk mengambil objek Python biasa -- string, boolean, `datetime`, atau sesuatu lebih rumit seperti `Hand` -- dan merubahnya dan dari bentuk tersebut yang berguna ketika berhubungan dengan basisdata. (Bentuk tersebut juga berguna untuk serialisasi, tapi seperti yang akan kita lihat nanti, bahwa itu lebih mudah sekali anda memiliki sisi basisdata dibawah kendali).

Bidang dalam sebuah model harus bagaimanapun dipindahkan untuk cocok kedalam jenis kolom basisdata yang ada. Basisdata yang berbeda menyediakan kumpulan berbeda dari jenis kolom sah, tetapi aturan masih sama: yaitu hanya jenis anda harus bekerja dengannya. Apapun anda ingin simpan dalam basisdata harus cocok kedalam satu dari jenis itu.

Umumnya, anda apakah menulis bidang Django untuk mencocokkan bagian jenis kolom basisdata, atau anda akan butuh merubah data anda, katakan, string.

Untuk contoh kami `Hand`, kami dapat merubah data kartu menjadi sebuah string 104 karakter dengan menambahkan semua kartu bersama-sama dalam urutan ditentukan sebelumnya -- katakan, pertama semua kartu north, kemudian kartu east, south dan west. Jadi obyek `Hand` dapat disimpan ke kolom teks atau karakter di basisdata.

### Apakah yang kelas bidang lakukan?

Semua bidang Django (dan ketika kami katakan bidang dalam dokumen ini, kami selalu berarti bidang model dan bukan form fields) adalah subkelas dari `django.db.models.Field`. Kebanyakan informasi yang Django rekam mengenai sebuah bidang adalah umum bagi semua teman -- nama, bantuan, teks, keunikan dan sebagainya. Menyimpan semua informasi itu yang ditangani oleh `Field`. Kami akan memasuki rincian tepat dari `Field` apa yang dapat dilakukan kemudian; untuk sekarang, cukuplah untuk mengatakan bahwa segala sesuatu turun dari `Field` dan kemudian menyesuaian potongan kunci dari kebiasaan kelas.

Adalah penting untuk menyadari bahwa sebuah kelas bidang Django bukan apa yang disimpan dalam atribut model anda. Pengaturan model mengandung obyek Python biasa. Kelas-kelas bidang yang anda tentukan dalam sebuah model sebenarnya disimpan dalam kelas `Meta` ketika kelas model dibuat (rincian tepatnya bagaimana ini dilakukan adalah tidak penting disini). Ini karena kelas-kelas bidang tidak perlu ketika anda hanya membuat dan merubah atribut. Sebagai gantinya, mereka menyediakan mesin-mesin untuk merubah diantara nilai atribut dan apa yang disimpan dalam basisdata atau dikirim ke serializer.

Ingatlah ini ketika membuat penyesuaian bidang sendiri. Subkelas `Field` Django anda tulis menyediakan mesin-mesin untuk merubah diantara contoh Python anda dan nilai database/serializer dalam beragam cara (ada perbedaan diantara menyimpan sebuah nilai dan menggunakan sebuah nilai untuk pencarian, sebagai contoh). Jika ini terdengar sedikit rumit, jangan khawatir -- dia akan menjadi lebih jelas dalam contoh dibawah ini. Ingatlah bahwa anda akan sering membuat dua kelas ketika anda ingin penyesuaian bidang:

- Kelas pertama adalah obyek Python dimana pengguna anda akan merubah. Mereka akan menetapkannya ke atribut model, mereka akan membaca darinya untuk menampilkan tujuan, hal-hal seperti itu. ini adalah kelas `hand` dalam contoh kami.
- Kelas kedua adalah subkelas `Field`. Ini adalah kelas yang diketahui bagaimana merubah kelas pertama anda ke belakang dan seterusnya diantara bentuk penyimpanan tetap dan bentuk Python.

## Menulis sebuah subkelas bidang

Ketika merencanakan subkelas `Field` anda, pertama berikan beberapa diduga yang mana ada kelas `Field` bidang baru anda yang paling mirip. Dapatkah anda mensubkelaskan bidang Django yang ada dan menyimpan diri anda beberapa pekerjaan? Jika tidak, anda harus mensubkelaskan kelas `Field`, yang semuanya turun.

Inisialisasi bidang baru anda adalah sebuah masalah dari memisahkan argumen apapun yang khusus pada kasus anda dari argumen umum dan melewatkannya ke cara __init__()` dari `Field` (atau kelas induk anda).

Dalam contoh kami, kami akan memanggil bidang `HandField`. (Adalah ide bagus untuk memanggil subkelas `Field` anda `<Something>Field`, sehingga sangat mudah dicirikan sebagai sebuah subkelas `Field`.) Dia tidak berperilaku seperti bidang lainnya yang ada, jadi kami akan mensubkelaskan secara langsung dari `Field`:

    from django.db import models

    class HandField(models.Field):
        description = "A hand of cards (bridge style)"

        def __init__(self, *args, **kwargs):
            kwargs["max_length"] = 104
            super().__init__(*args, **kwargs)

`HandField` kami menerima kebanyakan pilihan bidang standar (lihat daftar dibawah ini), tetapi kami memastikan dia mempunyai panjang tetap, sejak dia hanya butuh menampung 52 nilai kartu ditambah pasangan mereka; 104 karakter jumlahnya.

Catatan

Banyak bidang model Django menerima pilihan bahwa mereka tidak melakukan apapun. Sebagai contoh, anda dapat melewatkan kedua `editable` dan `auto_now` pada `django.db.models.DateField` dan itu akan mengabaikan parameter `editable` (`auto_now` ditetapkan `editable=False`). Tidak ada kesalahan dimunculkan dalam kasus ini.

Perilaku ini menyederhanakan bidang kelas, karena mereka tidak butuh mencentang pilihan yang tidak dibutuhkan. Mereka melewati semua pilihan ke kelas induk dan mereka tidak menggunakan kemudian. Itu terserah anda apakah anda ingin bidang anda menjadi lebih ketat tentang pilihan mereka pilih, atau menggunakan perilaku lebih permisif dari bidang saat ini.

Cara `Field.__init__()` mengambil parameter berikut:

- `verbose_name`
- `nama`
- `primary_key`
- `max_length`
- `unique`
- `blank`
- `null`
- `db_index`
- `rel`: Digunakan untuk bidang terkait (seperti `ForeignKey`). Hanya untuk penggunaan lanjut.
- attr:~django.db.models.Field.default
- `editable`
- `serialize`: Jika `False`, bidang tidak akan didisambungkan ketika model dilewatkan ke serializers Django. Nilai awal ke `True`.
- `unique_for_date`
- `unique_for_month`
- `unique_for_year`
- `choices`
- `help_text`
- `db_column`
- `db_tablespace`: hanya untuk pembuatan indeks, jika dukungan backend tablespaces. Anda dapat biasanya mengabaikan pilihan ini.
- `auto_created`: `True` jika bidang otomatis telah dibuat, adapun `OneToOneField` digunakan oleh warisan model. Untuk penggunaan hanya tingkat lanjut.

Semua pilihan tanpa sebuah penjelasan dalam daftar diatas mempunyai arti yang sama mereka lakukan untuk bidang Django biasa. Lihat field documentation untuk contoh dan rincian.

### Membongkar bidang

Tandingan untuk menulis metode `__init__()` anda dalah menulis metode `deconstruct()`. Itu digunakan selama model migrations untuk memberitahu Django bgaimana mengambil sebuah instance dari bidang baru dan menguranginya pada formulir serial - khususnya, argumen apa yang dilewatkan ke `__init__()` untuk membuat ulang kembali.

Jika anda belum menambahkan pilihan tambahan pada bagian atas bidang anda warisi, lalu tidak perlu untuk menulis cara `deconstruct()` baru. Jika, bagaimanapun, anda sedang merubah argumen dilewati dalam `__init__()` (seperti kami dalam `HandField`), anda akan butuh tambahan nilai yang sedang dilewati.

`deconstruct()` mengembalikan sebuah tuple dari empat barang: nama atribut bidang, jalur penuh impor dari kelas bidang, argumen penempatan (sebagai sebuah list), dan argumen kata kunci (sebagai sebuah dict). Catat ini berbeda dari metode `deconstruct()`for custom classes yang mengembalikan sebuah tuple dari tiga hal.

Sebagai sebuah penyesuaian bidang penulis, anda tidak perlu memperhatikan tentang dua nilai pertama; kelas `Field` dasar mempunyai semua kode untuk bekerja nama atribut bidang dan mengimpor jalur. Anda, bagaimanapun, harus memperhatikan tentang penempatan dan katakunci argumen, seperti ini mirip hal-hal anda sedang rubah.

Sebagai contoh, dalam kelas `HandField` kami selalu memaksa menyetel max_length dalam `__init__()`. Cara `deconstruct()` dalam basis kelas `Field` akan melihat ini dan mencoba mengembalikannya dalam argumen katakunci; demikian, kami dapat membuangnya dari argumen katakunci untuk kesiapan:

    from django.db import models

    class HandField(models.Field):
        def __init__(self, *args, **kwargs):
            kwargs["max_length"] = 104
            super().__init__(*args, **kwargs)

        def deconstruct(self):
            name, path, args, kwargs = super().deconstruct()
            del kwargs["max_length"]
            return name, path, args, kwargs

Jika anda menambahkan sebuah argumen kata kunci, anda butuh menulis kode dalam `deconstruct()` yang menaruh nilainya kedalam `kwargs` anda sendiri. Anda harus juga menghilangkan nilai dari `kwargs` ketika itu tidak perlu dibangun kembali keadaan dari bidang, seperti ketika nilai awalan sedang digunakan:

    from django.db import models

    class CommaSepField(models.Field):
        "Implements comma-separated storage of lists"

        def __init__(self, separator=",", *args, **kwargs):
            self.separator = separator
            super().__init__(*args, **kwargs)

        def deconstruct(self):
            name, path, args, kwargs = super().deconstruct()
            # Only include kwarg if it's not the default
            if self.separator != ",":
                kwargs["separator"] = self.separator
            return name, path, args, kwargs

Contoh lebih rumit diluar cakupan dari dokumen ini, tetapi ingat - untuk konfigurasi apapun dari instance Field anda, `deconstruct()` harus mengembalikan argumen yang anda dapat lewati ke `__init__` untuk membangun kembali keadaan tersebut.

Beri perhatian lebih jika anda menyetel nilai baru awal untuk argumen dalam super kelas `Field`; anda ingin memastikan mereka selalu disertakan, daripada menghilang jika mereka mengambil nilai awal lama.

Tambahan, coba hindari mengembalikan nilai sebagai argumen penempatan; jika mungkin, mengembalikan nilai sebagai argumen kata kunci untuk maksimal kesesuaian masa depan. Jika anda merubah nama-nama dari hal-hal lebih sering dari posisi mereka dalam daftar argumen konstruktor, anda mungkin lebih suka penempatan, tapi ingatlah bahwa orang akan membangun kembali bidang anda dari versi terserialisasi cukup lama (mungkin tahunan), tergantung seberapa lama perpindahan anda hidup.

Anda dapat melihat hasil dari dekonstruksi dengan melihat dalam perpindahan yang menyertakan bidang, dan anda dapat mencoba dekonstruksi dalam satuan percobaan oleh dekonstruksi dan rekonstruksi bidang:

    name, path, args, kwargs = my_field_instance.deconstruct()
    new_instance = MyField(*args, **kwargs)
    self.assertEqual(my_field_instance.some_attribute, new_instance.some_attribute)

### Atribut bidang tidak mempengaruhi penentuan kolom basisdata

New in Django 4.1.

Anda dapat menimpa `Field.non_db_attrs` untuk menyesuaikan atribut dari bidang yang tidak berpengaruh penentuan kolom. Itu digunakan selama perpindahan model untuk mengenali tindakan tanpa-operasi `AlterField`.

Sebagai contoh:

    class CommaSepField(models.Field):
        @property
        def non_db_attrs(self):
            return super().non_db_attrs + ("separator",)

### Merubah penyesuaian kelas dasar bidang

Anda tidak dapat merubah kelas dasar dari penyesuaian bidang karena Django tidak akan mengenali perubahan dan buat perpindahan untuknya. Sebagai contoh, jika anda mulai dengan:

    class CustomCharField(models.CharField):
        ...

dan kemudian ditentukan bahwa anda ingin menggunakan `TextField` sebagai gantinya, anda tidak dapat merubah subkelas seperti ini:

    class CustomCharField(models.TextField):
        ...

Sebagai gantinya, anda harus membuat kelas bidang penyesuaian baru dan perbaharui model anda untuk mengacunya:

    class CustomCharField(models.CharField):
        ...

    class CustomTextField(models.TextField):
        ...

Seperti diobrolkan di removing fields, anda harus memelihara kelas `CustomCharField` asli selama anda mempunyai perpindahan yang mengacunya.

### Mendokumentasikan bidang penyesuaian anda

Seperti biasa, anda harus mendokumentasikan jenis bidang anda, sehingga pengguna mengetahui apa itu. Sebagai tambahan untuk menyediakan docstring untuknya, yang sangat berguna bagi pengembang, anda dapat juga mengizinkan pengguna dari aplikasi admin melihat keterangan ringkas dari jenis data melalui atribut kelas django.contrib.admindocs application. To do this provide descriptive text in a `description` dari bidang penyesuaian anda. Pada contoh diatas, gambaran ditampilkan oleh aplikasi `admindocs` untuk `HandField` berupa 'A hand of cards (bridge style)'.

Dalam tampilan `django.contrib.admindocs`, gambaran bidang ditambahkan dengan `field.__dict__` yang mengizinkan gambaran pada argumen yang digabungkan dari bidang. Sebagai contoh, gambaran untuk `CharField` adalah:

    description = _("String (up to %(max_length)s)")

### Cara berguna

Sekali anda telah membuat subkelas `Field` anda, anda boleh mempertimbangkan mengutamakan sedikit metode standar, tergantung pada perilaku bidang anda. Daftar dari cara dibawah ini adalah dalam lebih kurang menurun urutan dari kepentingan, jadi mulai dari atas.

#### Jenis basisdata penyesuaian

Katakan anda telah membuat jenis penyesuaian PostgreSQL dipanggil `mtype`. Anda dapat mensubkelaskan `Field` dan menerapkan cara `db_type()`, seperti begitu:

    from django.db import models

    class MytypeField(models.Field):
        def db_type(self, connection):
            return "mytype"

Sekali anda mempunyai `MytypeField`, anda dapat menggunakannya di model apapun, seperti jenis `Field` apapun lainnya

    class Person(models.Model):
        name = models.CharField(max_length=80)
        something_else = MytypeField()

Jika anda bertujuan membangun aplikasi basisdata-agnostik, anda harus memperhitungkan perbedaan dalam jenis kolom basisdata. Sebagai contoh, jenis data date/time di PostgreSQL disebut `timestamp`, sedangkan kolom yang sama di MySQL disebut `datetime`. Anda dapat menangani ini di metode a `db_type()` dengan memeriksa atribut `connection.vendor`. Nama-nama penjual siap-pakai saat ini adalah: `sqlite`, `postgresql`, `mysql`, dan `oracle`.

Sebagai contoh:

    class MyDateField(models.Field):
        def db_type(self, connection):
            if connection.vendor == "mysql":
                return "datetime"
            else:
                return "timestamp"

The `db_type()` and `rel_db_type()` methods are called by Django when the framework constructs the `CREATE TABLE` statements for your application -- that is, when you first create your tables. The methods are also called when constructing a `WHERE` clause that includes the model field -- that is, when you retrieve data using QuerySet methods like `get()`, `filter()`, and `exclude()` and have the model field as an argument.

Beberapa jenis kolom basisdata menerima parameter, seperti `CHAR(25)`, dimana parameter `25` mewakili panjang kolom maksimum. Dalam kasus seperti ini, dia lebih supel jika parameter ditentukan dalam model daripada menjadi kode-keras dalam cara `db_type()`. Sebagai contoh, dia tidak akan masuk akan untuk mempunyai `CharMaxlength25Field`, ditampilkan disini:

    # This is a silly example of hard-coded parameters.
    class CharMaxlength25Field(models.Field):
        def db_type(self, connection):
            return "char(25)"

    # In the model:
    class MyModel(models.Model):
        # ...
        my_field = CharMaxlength25Field()

Cara terbaik melakukan ini akan membuat parameter ditentukan pada saat dijalankan -- yaitu, ketika kelas diinstantiasikan. Untuk melakukan itu, terapkan `Field.__init__()`, seeprti itu:

    # This is a much more flexible example.
    class BetterCharField(models.Field):
        def __init__(self, max_length, *args, **kwargs):
            self.max_length = max_length
            super().__init__(*args, **kwargs)

        def db_type(self, connection):
            return "char(%s)" % self.max_length

    # In the model:
    class MyModel(models.Model):
        # ...
        my_field = BetterCharField(25)

Akhirnya, jika kolom anda benar-benar membutuhkan pengaturan SQL rumit, kembalikan `None` from `db_type()`. Ini akan menyebabkan kode pembuatan SQL Django dilewati terhadap bidang ini. Anda kemudian bertanggungjawab untuk membuat kolom di tabel yang benar dengan cara lain, tetapi ini memberikan anda cara memberitahu Django untuk keluar dari jalan.

Cara `rel_db_type()` dipanggil oleh bidang seperti `ForeignKey` and `OneToOneField` yang menunjuk ke bidang lain untuk menentukan jenis data kolom basisdata mereka. Sebagai contoh, jika anda mempunyai sebuah `UnsignedAutoField`, anda juga butuh foreign key yang menunjuk ke bidang itu untuk menggunakan jenis data yang sama:

    # MySQL unsigned integer (range 0 to 4294967295).
    class UnsignedAutoField(models.AutoField):
        def db_type(self, connection):
            return "integer UNSIGNED AUTO_INCREMENT"

        def rel_db_type(self, connection):
            return "integer UNSIGNED"

#### Mengubah nilai menjadi obyek Python

Jika penyesuaian kelas `Field` anda berhubungan dengan struktur dara yang lebih rumit daripada string, date, integer, atau float, kemudian anda butuh untuk menimpa `from_db_value()` dan `to_python()`.

Jika ada untuk bidang subkelas, `from_db_value()` akan dipanggil dalam semua keadaan ketika data dimuat dari basisdata, termasuk dalam keseluruhan dan panggilan `values()`.

`to_python()` dipanggil dengan memutuskan dan selama cara `clean()` digunakan dari formulir.

Sebagai aturan umum, `to_python()` harus berurusan secara anggun dengan salah satu dari argumen berikut:

- Sebuah contoh dari jenis yang benar (sebagai contoh, `Hand` dalam contoh kami yang sedang berjalan).
- Sebuah string
- `None` (jika bidang mengizinkan `null=True`)

Dalam kelas `HandField` kami, kami menyimpan data sebagai bidang `VARCHAR``di basisdata, jadi kita harus bisa mengolahnya strings dan ``None` dalam `from_db_value()`. Di `to_python()`, kami juga butuh menangani instance `Hand`:

    import re

    from django.core.exceptions import ValidationError
    from django.db import models
    from django.utils.translation import gettext_lazy as _

    def parse_hand(hand_string):
        """Takes a string of cards and splits into a full hand."""
        p1 = re.compile(".{26}")
        p2 = re.compile("..")
        args = [p2.findall(x) for x in p1.findall(hand_string)]
        if len(args) != 4:
            raise ValidationError(_("Invalid input for a Hand instance"))
        return Hand(*args)

    class HandField(models.Field):
        # ...

        def from_db_value(self, value, expression, connection):
            if value is None:
                return value
            return parse_hand(value)

        def to_python(self, value):
            if isinstance(value, Hand):
                return value

            if value is None:
                return value

            return parse_hand(value)

Perhatikan bahwa kami selalu mengembalikan sebuah instance `hand` dari cara ini. Itu adalah jenis obyek Python kami ingin simpan dalam atribut model.

Untuk `to_python()`, jika apapun berjalan salah selama perubahan nilai, anda harus memunculkan pengecualian `ValidationError`.

#### Mengubah obyek Python ke nilai pencarian

Sejak menggunakan basisdata membutuhkan perubahan dalam kedua cara, jika anda menimpa `from_db_value()` anda juga harus menimpa `get_prep_value()` untuk merubah obyek Pythonkembali ke nilai permintaan.

Sebagai contoh:

    class HandField(models.Field):
        # ...

        def get_prep_value(self, value):
            return "".join(
                ["".join(l) for l in (value.north, value.east, value.south, value.west)]
            )

Peringatan

Jika bidang penyesuaian anda menggunakan jenis `CHAR`, `VARCHAR` atau `TEXT` untuk MySQL, anda harus memastikan bahwa `get_prep_value()` selalu mengembalikan jenis string. MySQL melakukan luwas dan pencocokan tidak diharapkan ketika sebuah permintaan dilakukan pada jenis ini dan nilai yang disediakan adalah sebuah integer, yang dapat menyebabkan permintaan untuk menyertakan obyek tidak diharapkan dalam pencarian mereka. Masalah ini tidak dapat timbul jika anda selalu mengembalikan jenis string dari `get_prep_value()`.

#### Mengubah nilai pencarian ke nilai basisdata

Beberapa jenis data (sebagai contoh, tanggal) butuh dalam bentuk yang khusus sebelum mereka dapat digunakan oleh backend basisdata. `get_db_prep_value()` adalah cara dimana perubahan tersebut harus dibuat. Hubungan khusus yang akan digunakan untuk permintaan dilewati sebagai parameter `connection`. Ini mengizinkan anda menggunakan logika perubahan khusus-backend jika dia diwajibkan.

Sebagai contoh, Django menggunakan cara berikut untuk `BinaryField` nya:

    def get_db_prep_value(self, value, connection, prepared=False):
        value = super().get_db_prep_value(value, connection, prepared)
        if value is not None:
            return connection.Database.Binary(value)
        return value

Dalam kasus bidang penyesuaian anda butuh perubahan khusus ketika sedang disimpan yang tidak sama seperti perubahan digunakan untuk parameter permintaan biasa, anda dapat menimpa `get_db_prep_save()`.

#### Mengolah nilai sebelum menyimpan

Jika anda ingin prapengolahan nilai sebelum menyimpan, anda dapat menggunakan `pre_save()`. Sebagai contoh, `DateTimeField` Django menggunakan cara ini untuk menyetel atribut dengan benar dalam kasus dari `auto_now` atau `auto_now_add`.

Jika anda melakukan menimpa metode ini, anda harus mengembalikan nilai dari atribut di akhirnya. Anda harus juga memperbaharui atribut model jika anda membuat perubahan apapun ke nilai sehingga kode menahan acuan ke model akan selalu melihat nilai benar.

#### Menentukan bidang formulir untuk sebuah bidang model

Untuk menyesuaikan bidang formulir digunakan oleh `ModelForm`, anda dapat menimpa `formfield()`.

Kelas bidang formulir dapat ditentukan melalui argumen `form_class` dan `choices_form_class`; yang terakhir digunakan jika bidang mempunyai pilihan yang ditentukan, yang depan kebalikannya. Jika argumen ini tidak disediakan, `CharField` atau `TypedChoiceField` akan digunakan.

Semua kamus `kwargs` dilewatkan secara langsung ke formulir cara `__init__()` bidang. Biasanya, semua anda butuh lakukan adalah menyetel nilai awal bagus untuk `form_class` argumen (dan mungkin `choices_form_class`) dan kemudian mengutus penanganan lebih lanjut untuk kelas induk. Ini mungkin membutuhkan anda menulis bidang formulir penyesuaian (dan bahkan sebuah widget formulir). Lihat forms documentation untuk informasi tentang ini.

Melanjutkan contoh berlangsung kita, kami dapat menulis cara `formfield()` sebagai:

    class HandField(models.Field):
        # ...

        def formfield(self, **kwargs):
            # This is a fairly standard way to set up some defaults
            # while letting the caller override them.
            defaults = {"form_class": MyFormField}
            defaults.update(kwargs)
            return super().formfield(**defaults)

Ini menganggap kami telah mengimpor kelas bidang `MyFormField` (yang mempunyai widget awal sendiri). Dokumen ini tidak mencakup rincian dari penulisan bidang formulir penyesuaian.

#### Menyamai jenis bidang siap pakai

Jika anda telah membuat cara `db_type()`, anda tidak butuh khawatir tentang `get_internal_type()` -- dia tidak akan digunakan. Terkadang, meskipun, penyimpanan basisdata anda mirip dalam jenis pada beberapa bidang lain, jadi anda dapat menggunakan logika bidang lain itu untuk membuat kolum yang benar.

Sebagai contoh:

    class HandField(models.Field):
        # ...

        def get_internal_type(self):
            return "CharField"

Tidak penting backend basisdata anda kami gunakan, ini akan berarti bahwa `migrate` dan perintah SQL lainnya membuat jenis kolom benar untuk menyimpan sebuah deretan karakter.

Jika `get_internal_type()` megembalikan sebuah deretan karakter yang tidak diketahui ke Django untuk backend basisdata anda sedang gunakan -- yaitu, dia tidak muncul dalam `django.db.backends.<db_name>.base.DatabaseWrapper.data_types` -- deretan karakter akan masih digunakan oleh penyambung, tetapi cara `db_type()` awal akan mengembalikan `None`. Lihat dokumentasi dari `db_type()` untuk alasan mengapa ini mungkin berguna. menaruh sebuah gambaran deretan karakter kedalam sebagai jenis dari bidang untuk penyambung adalah ide berguna jika anda sedang akan menggunakan keluaran penyambung dalam beberapa tempat lainnya, diluar Django.

#### Mengubah data field untuk serialisasi

Untuk menyesuaikan bagaimana nilai diserialkan oleh penserial, anda dapat menimpa `value_to_string()`. menggunakan `value_from_object()` adalah jalan terbaik untuk mendapatkan nilai bidang sebelum serialisasi. Sebagai contoh, sejak `HandField` menggunakan string untuk penyimpanan data, kami dapat menggunakan kembali beberapa kode perubahan yang ada:

    class HandField(models.Field):
        # ...

        def value_to_string(self, obj):
            value = self.value_from_object(obj)
            return self.get_prep_value(value)

### Beberapa saran umum

Menulis sebuah bidang penyesuaian dapat menjadi pengolahan yang rumit, khususnya jika anda sedang melakukan perubahan rumit diantara jenis Python anda dan basisdata anda dan bentuk penyambungan. Ini adalah sepasang tip untuk membuat hal-hal berjalan lebih halus:

1. Look at the existing Django fields (in django/db/models/fields/__init__.py) for inspiration. Try to find a field that's similar to what you want and extend it a little bit, instead of creating an entirely new field from scratch.
2. Taruh sebuah metode `__str__()` pada kelas anda sedang bungkus sebagai sebuah bidang. Ada banyak tempat-tempat dimana perilaku awalan dari kode bidang adalah memanggil `str()` pada nilai. (Dalam contoh kami dalam dokumen ini, `value` akan berupa instance `handa`, bukan `handField`). Jadi jika metode `__str__()` anda secara otomatis merubah ke bentuk string dari obyek Python anda, anda dapat menyimpan anda sendiri banyak pekerjaan.

## Menulis subkelas `FileField`

Dalam tambahan pada cara diatas, bidang-bidang yang berurusan dengan berkas-berkas mempunyai sedikit persyaratan khusus lainnya yang harus diambil kedalam akun. Kebanyakan dari mekanisme disediakan oleh `FileField`, seperti mengendalikan penyimpanan basisdata dan pengambilan, dapat tetap tidak berubah, meninggalkan subkelas-subkelas untuk berurusan dengan tantangan dari mendukung jenis khusus dari berkas.

Django menyediakan sebuah kelas `File`, yang digunakan sebagai sebuah proxy pada isi berkas dan tindakan. Ini dapat disubkelaskan ke menyesuaikan bagaimana berkas diakses, dan cara apa yang tersedia. Dia tinggal di `django.db.models.fields.files`, dan kebiasaan awalnya adalah dijelaskan dalam file documentation.

Ketika sub kelas `File` dibuat, subkelas `FileField` harus diberitahu menggunakannya. Untuk melakukannya, tugaskan subkelas `File` ke atribut khusus `attr_class` dari subkelas `FileField`.

### Sedikit saran

Sebagai tambahan pada rincian diatas, terdapat sedikit panduan yang dapat meningkatkan efisiensi dan kesiapan dari kode bidang.

1. The source for Django's own `ImageField` (in django/db/models/fields/files.py) is a great example of how to subclass `FileField` to support a particular type of file, as it incorporates all of the techniques described above.
2. Menembolok atribut berkas dimanapaun memungkinkan. Sejak berkas-berkas mungkin disimpan dalam sistem penyimpanan jauh, mengambil mereka mungkin memakan waktu tambahan, atau bahkan uang, yang tidak selalu dibutuhkan. Sekali sebuah berkas diambil untuk mendapatkan beberapa data tentang isinya, simpan sebanyak mungkin data tersebut untuk mengurangi jumlah kali berkas harus diambil pada pemanggilan berikut untuk informasi itu.