Saya sedang mengerjakan aplikasi multi-penyewa di mana beberapa pengguna dapat menentukan bidang data mereka sendiri (melalui admin) untuk mengumpulkan data tambahan dalam bentuk dan melaporkan data tersebut. Bit terakhir membuat JSONField bukan pilihan yang bagus, jadi saya punya solusi berikut:
class CustomDataField(models.Model):
"""
Abstract specification for arbitrary data fields.
Not used for holding data itself, but metadata about the fields.
"""
site = models.ForeignKey(Site, default=settings.SITE_ID)
name = models.CharField(max_length=64)
class Meta:
abstract = True
class CustomDataValue(models.Model):
"""
Abstract specification for arbitrary data.
"""
value = models.CharField(max_length=1024)
class Meta:
abstract = True
Perhatikan bagaimana CustomDataField memiliki ForeignKey ke Situs - setiap Situs akan memiliki kumpulan bidang data khusus yang berbeda, tetapi menggunakan database yang sama. Kemudian berbagai bidang data konkret dapat didefinisikan sebagai:
class UserCustomDataField(CustomDataField):
pass
class UserCustomDataValue(CustomDataValue):
custom_field = models.ForeignKey(UserCustomDataField)
user = models.ForeignKey(User, related_name='custom_data')
class Meta:
unique_together=(('user','custom_field'),)
Ini mengarah ke penggunaan berikut:
custom_field = UserCustomDataField.objects.create(name='zodiac', site=my_site) #probably created in the admin
user = User.objects.create(username='foo')
user_sign = UserCustomDataValue(custom_field=custom_field, user=user, data='Libra')
user.custom_data.add(user_sign) #actually, what does this even do?
Tapi ini terasa sangat kikuk, terutama dengan kebutuhan untuk secara manual membuat data terkait dan mengaitkannya dengan model konkret. Apakah ada pendekatan yang lebih baik?
Opsi yang telah dibuang sebelumnya:
- Kustom SQL untuk memodifikasi tabel on-the-fly. Sebagian karena ini tidak akan skala dan sebagian karena terlalu banyak peretasan.
- Solusi tanpa skema seperti NoSQL. Saya tidak menentang mereka, tetapi mereka masih tidak cocok. Pada akhirnya data ini diketik, dan ada kemungkinan menggunakan aplikasi pelaporan pihak ketiga.
- JSONField, seperti yang tercantum di atas, karena tidak akan berfungsi dengan baik dengan kueri.
Jawaban:
Sampai hari ini, ada empat pendekatan yang tersedia, dua di antaranya membutuhkan backend penyimpanan tertentu:
Django-eav (paket asli tidak lagi dipertahankan tetapi memiliki beberapa garpu yang berkembang )
Solusi ini didasarkan pada model data Entity Attribute Value , pada dasarnya, ia menggunakan beberapa tabel untuk menyimpan atribut dinamis objek. Bagian hebat dari solusi ini adalah:
memungkinkan Anda untuk secara efektif melampirkan / melepaskan penyimpanan atribut dinamis ke model Django dengan perintah sederhana seperti:
Terintegrasi dengan baik dengan Django admin ;
Pada saat yang sama menjadi sangat kuat.
Kerugian:
Penggunaannya cukup mudah:
Bidang Hstore, JSON atau JSONB di PostgreSQL
PostgreSQL mendukung beberapa tipe data yang lebih kompleks. Sebagian besar didukung melalui paket pihak ketiga, tetapi dalam beberapa tahun terakhir Django telah mengadopsinya ke django.contrib.postgres.fields.
HStoreField :
Django-hstore pada awalnya adalah paket pihak ketiga, tetapi Django 1.8 menambahkan HStoreField sebagai built-in, bersama dengan beberapa jenis bidang yang didukung PostgreSQL lainnya.
Pendekatan ini baik dalam arti memungkinkan Anda memiliki yang terbaik dari kedua dunia: bidang dinamis dan basis data relasional. Namun, hstore tidak ideal untuk performa , terutama jika Anda akan menyimpan ribuan item dalam satu bidang. Ini juga hanya mendukung string untuk nilai.
Dalam shell Django Anda dapat menggunakannya seperti ini:
Anda dapat mengeluarkan kueri yang diindeks terhadap bidang hstore:
JSONField :
Bidang JSON / JSONB mendukung semua tipe data yang dikodekan JSON, bukan hanya pasangan kunci / nilai, tetapi juga cenderung lebih cepat dan (untuk JSONB) lebih kompak daripada Hstore. Beberapa paket mengimplementasikan JSON / JSONB field termasuk django-pgfields , tetapi pada Django 1.9, JSONField adalah built-in menggunakan JSONB untuk penyimpanan. JSONField mirip dengan HStoreField, dan dapat bekerja lebih baik dengan kamus besar. Ini juga mendukung tipe selain string, seperti bilangan bulat, boolean dan kamus bersarang.
Menciptakan di shell:
Kueri yang diindeks hampir identik dengan HStoreField, kecuali jika nesting mungkin dilakukan. Indeks kompleks mungkin memerlukan pembuatan secara manual (atau migrasi yang dituliskan).
Django MongoDB
Atau adaptasi NoSQL Django lainnya - dengan itu Anda dapat memiliki model yang sepenuhnya dinamis.
Pustaka NoSQL Django hebat, tetapi perlu diingat bahwa mereka tidak 100% kompatibel dengan Django, misalnya, untuk bermigrasi ke Django-nonrel dari Django standar, Anda harus mengganti ManyToMany dengan ListField di antara hal-hal lainnya.
Lihat contoh Django MongoDB ini:
Anda bahkan dapat membuat daftar tertanam dari model Django apa pun:
Django-mutan: Model dinamis berdasarkan syncdb dan South-hooks
Django-mutan mengimplementasikan Foreign Key dan m2m bidang yang sepenuhnya dinamis. Dan terinspirasi oleh solusi luar biasa tetapi agak retas oleh Will Hardy dan Michael Hall.
Semua ini didasarkan pada kait Selatan Django, yang, menurut ceramah Will Hardy di DjangoCon 2011 (tonton saja!) Namun kuat dan diuji dalam produksi ( kode sumber yang relevan ).
Pertama yang mengimplementasikan ini adalah Michael Hall .
Ya, ini ajaib, dengan pendekatan ini Anda dapat mencapai aplikasi, model, dan bidang Django yang sepenuhnya dinamis dengan backend basis data relasional apa pun. Tetapi berapa biayanya? Apakah kestabilan aplikasi akan terganggu karena penggunaan yang berlebihan? Ini adalah pertanyaan yang harus dipertimbangkan. Anda harus memastikan untuk mempertahankan kunci yang tepat untuk memungkinkan perubahan permintaan database secara simultan.
Jika Anda menggunakan Michael Halls lib, kode Anda akan terlihat seperti ini:
sumber
Saya telah berusaha mendorong ide django-dynamo lebih lanjut. Proyek ini masih tidak berdokumen tetapi Anda dapat membaca kode di https://github.com/charettes/django-mutant .
Sebenarnya bidang FK dan M2M (lihat contrib.related) juga berfungsi dan bahkan mungkin untuk menentukan pembungkus untuk bidang khusus Anda sendiri.
Ada juga dukungan untuk opsi model seperti unique_together dan pemesanan plus basis Model sehingga Anda dapat subkelas model proxy, abstrak atau mixin.
Saya benar-benar bekerja pada mekanisme kunci yang tidak ada dalam memori untuk memastikan bahwa definisi model dapat dibagikan di beberapa instance django yang sedang berjalan sambil mencegah mereka menggunakan definisi usang.
Proyek ini masih sangat alfa tetapi merupakan teknologi landasan untuk salah satu proyek saya sehingga saya harus membawanya ke produksi siap. Rencana besar mendukung django-nonrel juga sehingga kita dapat memanfaatkan driver mongodb.
sumber
Penelitian lebih lanjut mengungkapkan bahwa ini adalah kasus yang agak istimewa dari pola desain Nilai Atribut Entitas , yang telah diterapkan untuk Django oleh beberapa paket.
Pertama, ada proyek eav -django asli , yang ada di PyPi.
Kedua, ada garpu yang lebih baru dari proyek pertama, Django- EAV yang terutama merupakan refactor untuk memungkinkan penggunaan EAV dengan model atau model Django sendiri di aplikasi pihak ketiga.
sumber