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:
- menggunakan beberapa model Django murni dan sederhana untuk mewakili bidang dinamis, yang membuatnya mudah dipahami dan database-agnostik;
memungkinkan Anda untuk secara efektif melampirkan / melepaskan penyimpanan atribut dinamis ke model Django dengan perintah sederhana seperti:
eav.unregister(Encounter)
eav.register(Patient)
Terintegrasi dengan baik dengan Django admin ;
Pada saat yang sama menjadi sangat kuat.
Kerugian:
- Tidak terlalu efisien. Ini lebih merupakan kritik terhadap pola EAV itu sendiri, yang mengharuskan penggabungan data secara manual dari format kolom ke satu set pasangan nilai kunci dalam model.
- Sulit dipertahankan. Menjaga integritas data memerlukan batasan kunci unik multi-kolom, yang mungkin tidak efisien pada beberapa basis data.
- Anda harus memilih salah satu dari garpu , karena paket resmi tidak lagi dipertahankan dan tidak ada pemimpin yang jelas.
Penggunaannya cukup mudah:
import eav
from app.models import Patient, Encounter
eav.register(Encounter)
eav.register(Patient)
Attribute.objects.create(name='age', datatype=Attribute.TYPE_INT)
Attribute.objects.create(name='height', datatype=Attribute.TYPE_FLOAT)
Attribute.objects.create(name='weight', datatype=Attribute.TYPE_FLOAT)
Attribute.objects.create(name='city', datatype=Attribute.TYPE_TEXT)
Attribute.objects.create(name='country', datatype=Attribute.TYPE_TEXT)
self.yes = EnumValue.objects.create(value='yes')
self.no = EnumValue.objects.create(value='no')
self.unkown = EnumValue.objects.create(value='unkown')
ynu = EnumGroup.objects.create(name='Yes / No / Unknown')
ynu.enums.add(self.yes)
ynu.enums.add(self.no)
ynu.enums.add(self.unkown)
Attribute.objects.create(name='fever', datatype=Attribute.TYPE_ENUM,\
enum_group=ynu)
# When you register a model within EAV,
# you can access all of EAV attributes:
Patient.objects.create(name='Bob', eav__age=12,
eav__fever=no, eav__city='New York',
eav__country='USA')
# You can filter queries based on their EAV fields:
query1 = Patient.objects.filter(Q(eav__city__contains='Y'))
query2 = Q(eav__city__contains='Y') | Q(eav__fever=no)
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.
#app/models.py
from django.contrib.postgres.fields import HStoreField
class Something(models.Model):
name = models.CharField(max_length=32)
data = models.HStoreField(db_index=True)
Dalam shell Django Anda dapat menggunakannya seperti ini:
>>> instance = Something.objects.create(
name='something',
data={'a': '1', 'b': '2'}
)
>>> instance.data['a']
'1'
>>> empty = Something.objects.create(name='empty')
>>> empty.data
{}
>>> empty.data['a'] = '1'
>>> empty.save()
>>> Something.objects.get(name='something').data['a']
'1'
Anda dapat mengeluarkan kueri yang diindeks terhadap bidang hstore:
# equivalence
Something.objects.filter(data={'a': '1', 'b': '2'})
# subset by key/value mapping
Something.objects.filter(data__a='1')
# subset by list of keys
Something.objects.filter(data__has_keys=['a', 'b'])
# subset by single key
Something.objects.filter(data__has_key='a')
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.
#app/models.py
from django.contrib.postgres.fields import JSONField
class Something(models.Model):
name = models.CharField(max_length=32)
data = JSONField(db_index=True)
Menciptakan di shell:
>>> instance = Something.objects.create(
name='something',
data={'a': 1, 'b': 2, 'nested': {'c':3}}
)
Kueri yang diindeks hampir identik dengan HStoreField, kecuali jika nesting mungkin dilakukan. Indeks kompleks mungkin memerlukan pembuatan secara manual (atau migrasi yang dituliskan).
>>> Something.objects.filter(data__a=1)
>>> Something.objects.filter(data__nested__c=3)
>>> Something.objects.filter(data__has_key='a')
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:
from djangotoolbox.fields import DictField
class Image(models.Model):
exif = DictField()
...
>>> image = Image.objects.create(exif=get_exif_data(...))
>>> image.exif
{u'camera_model' : 'Spamcams 4242', 'exposure_time' : 0.3, ...}
Anda bahkan dapat membuat daftar tertanam dari model Django apa pun:
class Container(models.Model):
stuff = ListField(EmbeddedModelField())
class FooModel(models.Model):
foo = models.IntegerField()
class BarModel(models.Model):
bar = models.CharField()
...
>>> Container.objects.create(
stuff=[FooModel(foo=42), BarModel(bar='spam')]
)
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:
from dynamo import models
test_app, created = models.DynamicApp.objects.get_or_create(
name='dynamo'
)
test, created = models.DynamicModel.objects.get_or_create(
name='Test',
verbose_name='Test Model',
app=test_app
)
foo, created = models.DynamicModelField.objects.get_or_create(
name = 'foo',
verbose_name = 'Foo Field',
model = test,
field_type = 'dynamiccharfield',
null = True,
blank = True,
unique = False,
help_text = 'Test field for Foo',
)
bar, created = models.DynamicModelField.objects.get_or_create(
name = 'bar',
verbose_name = 'Bar Field',
model = test,
field_type = 'dynamicintegerfield',
null = True,
blank = True,
unique = False,
help_text = 'Test field for Bar',
)