Tengo una base de datos de arquitectura de esquema de estrellas que quiero representar en SQLAlchemy. Ahora tengo el problema de cómo se puede hacer de la mejor manera posible. En este momento tengo muchas propiedades con condiciones de combinación personalizadas, porque los datos se almacenan en diferentes tablas. Sería bueno si fuera posible reutilizar las dimensiones para diferentes tablas de hechos, pero no he descubierto cómo hacerlo bien.Esquema de estrella en SQLAlchemy
Respuesta
Una tabla de hechos típica en un esquema en estrella contiene referencias de claves externas a todas las tablas de dimensiones, por lo que normalmente no habría necesidad de condiciones de combinación personalizadas; se determinan automáticamente a partir de referencias de claves externas.
Por ejemplo, un esquema en estrella con dos tablas de hechos se vería así:
Base = declarative_meta()
class Store(Base):
__tablename__ = 'store'
id = Column('id', Integer, primary_key=True)
name = Column('name', String(50), nullable=False)
class Product(Base):
__tablename__ = 'product'
id = Column('id', Integer, primary_key=True)
name = Column('name', String(50), nullable=False)
class FactOne(Base):
__tablename__ = 'sales_fact_one'
store_id = Column('store_id', Integer, ForeignKey('store.id'), primary_key=True)
product_id = Column('product_id', Integer, ForeignKey('product.id'), primary_key=True)
units_sold = Column('units_sold', Integer, nullable=False)
store = relation(Store)
product = relation(Product)
class FactTwo(Base):
__tablename__ = 'sales_fact_two'
store_id = Column('store_id', Integer, ForeignKey('store.id'), primary_key=True)
product_id = Column('product_id', Integer, ForeignKey('product.id'), primary_key=True)
units_sold = Column('units_sold', Integer, nullable=False)
store = relation(Store)
product = relation(Product)
Pero supongamos que desea reducir el repetitivo en cualquier caso. Me gustaría crear generadores local para las clases de dimensiones que configuran a sí mismos en una tabla de hechos:
class Store(Base):
__tablename__ = 'store'
id = Column('id', Integer, primary_key=True)
name = Column('name', String(50), nullable=False)
@classmethod
def add_dimension(cls, target):
target.store_id = Column('store_id', Integer, ForeignKey('store.id'), primary_key=True)
target.store = relation(cls)
en el que el uso de caso sería como:
class FactOne(Base):
...
Store.add_dimension(FactOne)
embargo, hay un problema con eso. Suponiendo que las columnas de dimensión que está agregando son columnas de clave primaria, la configuración del asignador va a fallar, ya que una clase necesita tener sus claves principales configuradas antes de que se establezca la asignación. Así que asumiendo que estamos usando declarativa (que se verá más adelante tiene un efecto agradable), para que este enfoque de trabajo que tendríamos que utilizar la función instrument_declarative()
en lugar de la metaclase estándar:
meta = MetaData()
registry = {}
def register_cls(*cls):
for c in cls:
instrument_declarative(c, registry, meta)
Así entonces 'd hacer algo a lo largo de las líneas de:
class Store(object):
# ...
class FactOne(object):
__tablename__ = 'sales_fact_one'
Store.add_dimension(FactOne)
register_cls(Store, FactOne)
Si realmente tiene una buena razón para encargo condiciones de unión, siempre y cuando no hay un patrón de cómo se crean estas condiciones, puede generar que con su add_dimension()
:
class Store(object):
...
@classmethod
def add_dimension(cls, target):
target.store_id = Column('store_id', Integer, ForeignKey('store.id'), primary_key=True)
target.store = relation(cls, primaryjoin=target.store_id==cls.id)
Pero la última cosa interesante si estás en 2.6, es convertir add_dimension
en un decorador de clases. Aquí hay un ejemplo con todo lo que se limpió:
from sqlalchemy import *
from sqlalchemy.ext.declarative import instrument_declarative
from sqlalchemy.orm import *
class BaseMeta(type):
classes = set()
def __init__(cls, classname, bases, dict_):
klass = type.__init__(cls, classname, bases, dict_)
if 'metadata' not in dict_:
BaseMeta.classes.add(cls)
return klass
class Base(object):
__metaclass__ = BaseMeta
metadata = MetaData()
def __init__(self, **kw):
for k in kw:
setattr(self, k, kw[k])
@classmethod
def configure(cls, *klasses):
registry = {}
for c in BaseMeta.classes:
instrument_declarative(c, registry, cls.metadata)
class Store(Base):
__tablename__ = 'store'
id = Column('id', Integer, primary_key=True)
name = Column('name', String(50), nullable=False)
@classmethod
def dimension(cls, target):
target.store_id = Column('store_id', Integer, ForeignKey('store.id'), primary_key=True)
target.store = relation(cls)
return target
class Product(Base):
__tablename__ = 'product'
id = Column('id', Integer, primary_key=True)
name = Column('name', String(50), nullable=False)
@classmethod
def dimension(cls, target):
target.product_id = Column('product_id', Integer, ForeignKey('product.id'), primary_key=True)
target.product = relation(cls)
return target
@Store.dimension
@Product.dimension
class FactOne(Base):
__tablename__ = 'sales_fact_one'
units_sold = Column('units_sold', Integer, nullable=False)
@Store.dimension
@Product.dimension
class FactTwo(Base):
__tablename__ = 'sales_fact_two'
units_sold = Column('units_sold', Integer, nullable=False)
Base.configure()
if __name__ == '__main__':
engine = create_engine('sqlite://', echo=True)
Base.metadata.create_all(engine)
sess = sessionmaker(engine)()
sess.add(FactOne(store=Store(name='s1'), product=Product(name='p1'), units_sold=27))
sess.commit()
- 1. esquema sqlalchemy oracle
- 2. ORM Equivalente para un esquema de estrella/copo de nieve
- 3. Botón Estrella en Android
- 4. ¿Cómo administrar eficientemente los cambios de esquema frecuentes usando sqlalchemy?
- 5. Algoritmo de estrella
- 6. ¿Qué significa * (estrella) en Ruby?
- 7. NSLayoutConstraint se estrella ViewController
- 8. Cómo obtener favoritos estrella
- 9. TRAGO se estrella Python
- 10. jQuery Grado de la estrella
- 11. C++: Asteriscos, Signo y Estrella?
- 12. WaWorkerHost.exe se estrella papel: CallbackException
- 13. urlencode() el 'asterisco' (estrella?) Carácter
- 14. partido Regex estrella barra invertida
- 15. Dibujando formas de estrella con parámetros variables
- 16. variable de ActionScript declarada como * (estrella) TIPO
- 17. SQLAlchemy, borre el contenido de la base de datos, pero no descarte el esquema
- 18. Actualizar un esquema de base de datos sqlite con sqlalchemy y elixir
- 19. Unir base de datos cruzada en sqlalchemy
- 20. colección personalizada se estrella en la cuadrícula de datos Editar
- 21. Soporte de SQLAlchemy de Postgres Schemas
- 22. Qué hace la estrella WPF (Ancho = "100 *")
- 23. Discos de Python en sqlalchemy
- 24. claves compuestas en sqlalchemy
- 25. Sumar campos en sqlAlchemy
- 26. sqlalchemy en la cláusula
- 27. Seleccionar como en sqlalchemy
- 28. sencilla actualización en sqlalchemy
- 29. Usando O en SQLAlchemy
- 30. Selección nulo en SQLAlchemy
Very nice design - beautiful! –
Inspirado por esto, finalmente descubrí cómo pasar la configuración a declaration_attr, para que las bibliotecas puedan conocer los modelos de aplicaciones de host: https://gist.github.com/miohtama/844cc78bcf1d317e31ca –