Django-eav (orijinal paket artık muhafaza edilmiyor , ancak gelişen çatalları var )
Bu çözüm, Varlık Özellik Değeri veri modelini temel alır, temel olarak nesnelerin dinamik niteliklerini depolamak için birkaç tablo kullanır. Bu çözümün harika kısımları:
- dinamik alanları temsil etmek için anlaşılması ve veritabanından agnostik hale getirilmesini sağlayan birkaç saf ve basit Django modeli kullanır;
dinamik özellik depolamasını Django modeline aşağıdaki gibi basit komutlarla etkili bir şekilde eklemenizi / ayırmanızı sağlar:
eav.unregister(Encounter)
eav.register(Patient)
Django admin ile iyi bütünleşir ;
Aynı zamanda gerçekten güçlü olmak.
Downsides:
- Çok verimli değil. Bu, verilerin bir sütun biçiminden modeldeki bir dizi anahtar / değer çiftine manuel olarak birleştirilmesini gerektiren EAV modelinin kendisinin bir eleştirisidir.
- Bakımı daha zor. Veri bütünlüğünü korumak, bazı veritabanlarında verimsiz olabilecek çok sütunlu benzersiz bir anahtar kısıtlaması gerektirir.
- Resmi paket artık korunmadığından ve net bir lider olmadığından çatallardan birini seçmeniz gerekecektir .
Kullanımı oldukça basittir:
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)
PostgreSQL içindeki Hstore, JSON veya JSONB alanları
PostgreSQL çok daha karmaşık veri türlerini destekler. Çoğu üçüncü taraf paketleriyle destekleniyor, ancak son yıllarda Django bunları django.contrib.postgres.fields olarak benimsedi.
HStoreField :
Django-hstore aslında üçüncü taraf bir paketti , ancak Django 1.8, HStoreField'ı yerleşik olarak ve diğer PostgreSQL destekli alan türleriyle birlikte ekledi .
Bu yaklaşım, her iki dünyanın da en iyisini elde etmenizi sağlayan bir anlamda iyidir: dinamik alanlar ve ilişkisel veritabanı. Bununla birlikte, hstore , özellikle bir alanda binlerce öğeyi depolayacaksanız, performans açısından ideal değildir . Ayrıca yalnızca değerler için dizeleri destekler.
#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)
Django'nun kabuğunda şöyle kullanabilirsiniz:
>>> 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'
Hstore alanlarına karşı dizine alınmış sorgular yayınlayabilirsiniz:
# 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 :
JSON / JSONB alanları, yalnızca anahtar / değer çiftlerini değil, aynı zamanda Hstore'dan daha hızlı ve (JSONB için) daha kompakt olma eğilimi gösteren herhangi bir JSON ile kodlanabilir veri türünü destekler. Birkaç paket , django-pgfields dahil olmak üzere JSON / JSONB alanlarını uygular , ancak Django 1.9'dan itibaren JSONField, depolama için JSONB kullanan bir yerleşiktir.
JSONField , HStoreField'a benzer ve büyük sözlüklerde daha iyi performans gösterebilir. Ayrıca tamsayılar, booleans ve iç içe sözlükler gibi dizeler dışındaki türleri de destekler.
#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)
Kabukta oluşturma:
>>> instance = Something.objects.create(
name='something',
data={'a': 1, 'b': 2, 'nested': {'c':3}}
)
Endekslenen sorgular, yuvalama yapılabilmesi dışında HStoreField ile hemen hemen aynıdır. Karmaşık dizinler el ile oluşturma (veya komut dosyası geçirilmiş taşıma) gerektirebilir.
>>> Something.objects.filter(data__a=1)
>>> Something.objects.filter(data__nested__c=3)
>>> Something.objects.filter(data__has_key='a')
Django MongoDB
Veya diğer NoSQL Django uyarlamaları - onlarla tamamen dinamik modellere sahip olabilirsiniz.
NoSQL Django kütüphaneleri harika, ancak standart Django'dan Django-nonrel'e geçmek için% 100 Django uyumlu olmadıklarını unutmayın. ManyToMany'yi ListField ile değiştirmelisiniz .
Bu Django MongoDB örneğine göz atın:
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, ...}
Herhangi bir Django modelinin gömülü listelerini bile oluşturabilirsiniz :
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-mutant: Syncdb ve Güney kancalarına dayanan dinamik modeller
Django-mutant tamamen dinamik Yabancı Anahtar ve m2m alanları uygular. Will Hardy ve Michael Hall'un inanılmaz ama biraz hackish çözümlerinden ilham alıyor .
Bunların hepsi, Will Hardy'nin DjangoCon 2011'deki konuşmasına (izleyin!) Göre Django South kancalarına dayanıyor , yine de sağlam ve üretimde test edildi ( ilgili kaynak kodu ).
İlk Bunu uygulamak oldu Michael Hall .
Evet, bu sihir, bu yaklaşımlarla herhangi bir ilişkisel veritabanı arka ucuyla tamamen dinamik Django uygulamaları, modelleri ve alanları elde edebilirsiniz . Ama ne pahasına olursa olsun? Ağır kullanımda uygulama stabilitesi etkilenecek mi? Bunlar dikkate alınması gereken sorular. Eşzamanlı veritabanı değiştirme isteklerine izin vermek için uygun bir kilit sağladığınızdan emin olmanız gerekir .
Michael Halls lib kullanıyorsanız, kodunuz şöyle görünecektir:
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',
)