Django-eav (оригінальна упаковка більше не доглядається, але має процвітаючі виделки )
Це рішення засноване на моделі даних вартості атрибутів сутності , по суті, воно використовує кілька таблиць для зберігання динамічних атрибутів об'єктів. Відмінна частина цього рішення полягає в тому, що воно:
- використовує кілька чистих і простих моделей Django для представлення динамічних полів, що робить його простим для розуміння та агностики даних;
дозволяє ефективно приєднувати / від'єднувати динамічне зберігання атрибутів до моделі Django за допомогою простих команд, таких як:
eav.unregister(Encounter)
eav.register(Patient)
Чудово інтегрується з адміністратором Django ;
У той же час бути справді потужним.
Недоліки:
- Не дуже ефективно. Це скоріше критика самого шаблону EAV, який вимагає вручну об'єднати дані з формату стовпця до набору пар ключових значень у моделі.
- Важче у обслуговуванні. Підтримка цілісності даних вимагає унікального обмеження ключа у стовпцях, яке може бути неефективним для деяких баз даних.
- Вам потрібно буде вибрати один з виделок , оскільки офіційний пакет більше не підтримується і чіткого лідера немає.
Використання досить просто:
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 або JSONB в PostgreSQL
PostgreSQL підтримує кілька більш складних типів даних. Більшість підтримується через сторонні пакети, але останніми роками Django прийняв їх у django.contrib.postgres.fields.
HStoreField :
Спочатку Django-hstore був стороннім пакетом, але Django 1.8 додав HStoreField як вбудований разом із кількома іншими типами полів, підтримуваних PostgreSQL.
Цей підхід хороший тим, що він дозволяє вам мати найкраще з обох світів: динамічні поля та реляційні бази даних. Однак hstore не є ідеальним для продуктивності , особливо якщо ви збираєтеся зберігати тисячі предметів в одному полі. Він також підтримує лише рядки для значень.
#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)
У оболонці Джанго ви можете використовувати його так:
>>> 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, не тільки пари ключів / значень, але також мають тенденцію бути швидшими та (для JSONB) більш компактними, ніж Hstore. Кілька пакетів реалізують поля JSON / JSONB, включаючи django-pgfields , але, як і Django 1.9, JSONField є вбудованим, використовуючи 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)
Створення в оболонці:
>>> 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')
Джанго МонгоДБ
Або інші адаптації Django NoSQL - з ними ви можете мати повністю динамічні моделі.
Бібліотеки NoSQL Django чудові, але майте на увазі, що вони не на 100% сумісні з Django, наприклад, щоб перейти на Django-nonrel зі стандартного Django, вам потрібно буде замінити ManyToMany на ListField серед іншого.
Оформити цей приклад Джанго МонгоДБ:
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, ...}
Ви навіть можете створити вбудовані списки будь-яких моделей 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')]
)
Django-мутант: Динамічні моделі, засновані на syncdb та South-гаках
Django-мутант реалізує повністю динамічні поля Foreign Foreign Key та m2m. І його надихають неймовірні, але дещо хакерські рішення Вілла Харді та Майкла Холла.
Все це базується на гачках Джанго Саута , які, згідно з розмовами Вілла Харді на DjangoCon 2011 (дивіться це!) , Все-таки надійні і перевірені у виробництві ( відповідний вихідний код ).
Першим здійснити це був Майкл Холл .
Так, це магія, завдяки цим підходам ви можете досягти повністю динамічних додатків, моделей та полів Django за допомогою будь-якого резервного інтерфейсу бази даних. Але якою ціною? Чи погіршиться стабільність застосування при сильному використанні? Це питання, які слід розглянути. Ви повинні бути впевнені, щоб підтримувати належний замок , щоб дозволити одночасну зміну запитів бази даних.
Якщо ви використовуєте lib Michael Halls, ваш код буде виглядати приблизно так:
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',
)