100(原来的套餐不再受管理,但有大约101个)
该解决方案基于Entity Attribute Value数据模型,本质上,它使用多个表来存储对象的动态属性.这个解决方案的优点在于:
缺点:
- 效率不是很高.这更多的是对EAV模式本身的批评,它需要手动将数据从列格式合并到模型中的一组键-值对.
- 更难维护.维护数据完整性需要多列唯一键约束,这在某些数据库上可能效率低下.
- 您将需要 Select one of the forks,因为官方套餐不再维护,并且没有明确的领导者.
用法相当简单:
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)
Hstore, JSON or JSONB fields in PostgreSQL个
PostgreSQL支持几种更复杂的数据类型.大多数都是通过第三方软件包来支持的,但是近年来Django已经将它们采用到了django.contri.postgres.field中.
HStoreField:
Django-hstore最初是一个第三方包,但Django 1.8增加了101作为内置包,以及其他几种PostgreSQL支持的字段类型.
这种方法很好,因为它让您两全其美:动态字段和关系数据库.但是,hstore是not ideal performance-wise,特别是如果您最终要在一个字段中存储数千个项目.它还仅支持值的字符串.
#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的shell中,您可以这样使用它:
>>> 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字段发出索引查询:
# 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字段支持任何JSON编码的数据类型,不仅键/值对,而且往往比Hstore更快(对于JSONB)更紧凑.
有几个包实现了JSON/JSONB字段,包括100,但是在Django 1.9中,101是内置的,使用JSONB进行存储.
JSONField类似于HStoreField,在使用大型字典时性能可能会更好.它还支持字符串以外的类型,如整数、布尔值和嵌套字典.
#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)
在shell 中创建:
>>> instance = Something.objects.create(
name='something',
data={'a': 1, 'b': 2, 'nested': {'c':3}}
)
除了可以嵌套之外,索引查询几乎与HStoreField相同.复杂的索引可能需要手动创建(或脚本迁移).
>>> Something.objects.filter(data__a=1)
>>> Something.objects.filter(data__nested__c=3)
>>> Something.objects.filter(data__has_key='a')
100
或其他NoSQL Django改编--使用它们,您可以拥有完全动态的模型.
NoSQL Django库非常好,但请记住,它们不是Django-nonrel%与Django兼容的,例如,要从标准Django迁移到Django-nonrel,需要用ListField等替换许多.
查看此Django MongoDB示例:
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, ...}
您甚至可以创建embedded lists个任意Django模型:
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')]
)
100
Django-mutant实现完全动态的外键和M2M字段.灵感来自Will Hardy和迈克尔·霍尔令人难以置信但有点老套的解决方案.
所有这些都以Django South hooks为基础,根据Will Hardy's talk at DjangoCon 2011 (watch it!)的说法,Django South hooks仍然很 Solidity ,并在生产中经过了测试(relevant source code).
从第一到implement this是Michael Hall.
是的,这很神奇,通过这些方法,您可以在任何关系数据库后端实现fully dynamic Django apps, models and fields.但代价是什么?大量使用会影响应用的 solidity 吗?这些是需要考虑的问题.您需要确保保持适当的lock,以便允许同时更改数据库请求.
如果您使用的是Michael Halls lib,您的代码将如下所示:
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',
)