Django-eav (el embalaje original ya no es mantenido, pero tiene algunos thriving forks)
Esta solución se basa en Entity Attribute Value modelo de datos, esencialmente, usa varias tablas para almacenar atributos dinámicos de objetos. Grandes partes acerca de esta solución es que:
- utiliza varios modelos de Django puras y simples para representar campos dinámicos, lo que hace que sea fácil de entender y de base de datos agnóstica;
le permite conectar con eficacia/desconectar el almacenamiento atributo dinámico al modelo de Django con comandos simples como:
eav.unregister(Encounter)
eav.register(Patient)
Nicely integrates with Django admin;
Al mismo tiempo, ser realmente poderoso.
Desventajas:
No
- muy eficiente. Esto es más una crítica del propio patrón de EAV, que requiere fusionar manualmente los datos de un formato de columna a un conjunto de pares clave-valor en el modelo.
- Más difícil de mantener. El mantenimiento de la integridad de los datos requiere una restricción de clave única de varias columnas, que puede ser ineficiente en algunas bases de datos.
- Deberá seleccionar one of the forks, ya que el paquete oficial ya no se mantiene y no hay un líder claro.
El uso es bastante sencillo:
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)
campos hstore, JSON o JSONB en PostgreSQL
PostgreSQL soporta varios tipos de datos más complejos. La mayoría son compatibles con paquetes de terceros, pero en los últimos años Django los ha adoptado en django.contrib.postgres.fields.
HStoreField:
Django-hstore era originalmente un paquete de terceros, pero Django 1.8 añade HStoreField como incorporado, junto con varios otros tipos de campos de PostgreSQL-compatible.
Este enfoque es bueno en el sentido de que le permite tener lo mejor de ambos mundos: campos dinámicos y base de datos relacional. Sin embargo, hstore es not ideal performance-wise, especialmente si va a terminar almacenando miles de elementos en un campo. También solo admite cadenas para valores.
#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)
Con cáscara de Django puede utilizar de esta manera:
>>> 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'
puede emitir consultas indexados contra los campos 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/Los campos JSONB admiten cualquier tipo de datos codificables por JSON, no solo key/valu e pares, pero también tienden a ser más rápidos y (para JSONB) más compactos que Hstore. Varios paquetes implementar campos JSON/JSONB incluyendo django-pgfields, pero a partir de Django 1.9, JSONField es un sistema incorporado en el uso de JSONB para su almacenamiento. JSONField es similar a HStoreField, y puede funcionar mejor con diccionarios grandes. También admite tipos distintos de cadenas, como enteros, booleanos y diccionarios anidados.
#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)
creando en el shell:
>>> instance = Something.objects.create(
name='something',
data={'a': 1, 'b': 2, 'nested': {'c':3}}
)
consultas indizadas son casi idénticos a HStoreField, excepto de anidación es posible. Los índices complejos pueden requerir la creación manual (o una migración guionizada).
>>> Something.objects.filter(data__a=1)
>>> Something.objects.filter(data__nested__c=3)
>>> Something.objects.filter(data__has_key='a')
Django MongoDB
U otras adaptaciones NoSQL Django - con ellos se puede tener modelos totalmente dinámicos.
bibliotecas NoSQL Django son grandes, pero tenga en cuenta que no son 100% compatibles con Django el, por ejemplo, para migrar a Django-nonrel desde estándar Django tendrá que reemplazar ManyToMany con ListField entre otras cosas.
Pedido este ejemplo 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, ...}
Puede incluso crear embedded lists de cualquiera de los modelos de 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-mutant: Dynamic models based on syncdb and South-hooks
Django-mutant implementos completamente dinámico clave externa y M2M campos. Y está inspirado en soluciones increíbles pero algo hackish por Will Hardy y Michael Hall.
Todos ellos se basan en los ganchos de Django del Sur, que, de acuerdo con Will Hardy's talk at DjangoCon 2011(cuidado!) son, sin embargo, robusta y probada en producción (relevant source code).
Primero en implement this fue Michael Hall.
Sí, esto es mágico, con estos enfoques puede lograr aplicaciones totalmente dinámicas Django, modelos y campos con cualquier back-end de base de datos relacional. ¿Pero a qué precio? ¿La estabilidad de la aplicación sufrirá un uso intensivo? Estas son las preguntas a considerar. Debe asegurarse de mantener un lock adecuado para permitir solicitudes simultáneas de modificación de la base de datos.
Si está utilizando Michael Salas lib, el código se vería así:
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',
)
de forma preventiva, esto no es ninguna de estas preguntas: http://stackoverflow.com/questions/7801729/django-model-with-dynamic-attributes http://stackoverflow.com/questions/ 2854656/per-instance-dynamic-fields-django-model – GDorn