سؤال

ولدي قاعدة بيانات النجوم مخطط architectured أنني أريد أن تمثل في SQLAlchemy. الآن لدي مشكلة حول كيفية يمكن القيام بذلك في أفضل طريقة ممكنة. الآن لدي الكثير من الخصائص مع العرف انضمام الظروف، لأنه يتم تخزين البيانات في جداول مختلفة. وسيكون لطيفا إذا كان من الممكن إعادة استخدام أبعاد مختلفة tablesw حقيقة لكني لم أحسب كيف يمكن القيام به بشكل جيد.

هل كانت مفيدة؟

المحلول

وجدول الحقيقة نموذجي في مخطط نجوم يحتوي على مراجع المفاتيح الخارجية لجميع الجداول البعد، لذلك عادة لن يكون هناك أي حاجة للعرف الانضمام الظروف - يتم تحديدها تلقائيا من المراجع الرئيسية الخارجية

وعلى سبيل المثال مخطط نجوم مع جدولين الحقيقة ستبدو:

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)

ولكن لنفترض أنك تريد تقليل النمطي في أي حال. فما استقاموا لكم فاستقيموا إنشاء مولدات المحلية إلى الطبقات البعد الذي تكوين نفسها على جدول حقيقة:

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)

والذي من شأنه أن استخدام الحالة سيكون مثل:

class FactOne(Base):
    ...

Store.add_dimension(FactOne)

ولكن، هناك مشكلة في ذلك. وإذا افترضنا أن الأعمدة البعد كنت تقوم بإضافة هي أعمدة المفاتيح الأساسية، وتكوين معين سوف تفشل لأن الطبقة يجب أن يكون لديك مفاتيح الأساسية التي أنشئت قبل تعيين تعيين ما يصل. حتى على افتراض أننا نستخدم التعريفي (والتي سترى أدناه له تأثير لطيفة)، لجعل هذا العمل النهج سيكون لدينا لاستخدام وظيفة instrument_declarative() بدلا من metaclass القياسية:

meta = MetaData()
registry = {}
def register_cls(*cls):
    for c in cls:
        instrument_declarative(c, registry, meta)

وحتى ذلك الحين كنا نفعل شيئا على غرار:

class Store(object):
    # ...

class FactOne(object):
    __tablename__ = 'sales_fact_one'

Store.add_dimension(FactOne)

register_cls(Store, FactOne)

إذا كان لديك بالفعل سبب وجيه للعرف الانضمام الظروف، ما دام هناك بعض نمط لكيفية خلق هذه الظروف، يمكنك توليد أنه مع 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)

ولكن الشيء بارد النهائي إذا كنت على 2.6، هو تحويل add_dimension في الديكور الطبقة. وهنا مثال مع كل شيء تنظيف:

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()
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top