【问题标题】:Create a reusable component with ZCA and SQLAlchemy使用 ZCA 和 SQLAlchemy 创建可重用组件
【发布时间】:2015-10-23 10:30:54
【问题描述】:

实际上,我正在使用 python 3.4 为桌面设计一个大型应用程序。 我选择了端口和适配器架构,即六边形架构。 它的主要目的是使用可重用的组件。

为了组织代码并设置一些规则,我们将使用 Zope 组件架构 (ZCA)

为了做一些 POC,我正在创建数据库组件。 但是使用 ORM 的事实阻止了我。我的意思是我设计了一些看起来像这样的数据库组件:

-IDatabase -IDatabaseConfig -IEntity -IKey -IReader -IWriter ... 和实施。

SQLAlchemy 管理很多东西,我不知道如何使我的组件可重用。

我找到了这段代码:

#Reflect each database table we need to use, using metadata
class Customer(Base):
    __table__ = Table('Customers', metadata, autoload=True)
    orders = relationship("Order", backref="customer")

class Shipper(Base):
    __table__ = Table('Shippers', metadata, autoload=True)
    orders = relationship("Order", backref="shipper")

class Product(Base):
    __table__ = Table('Products', metadata, autoload=True)
    supplier = relationship('Supplier', backref='products')
    category = relationship('Category', backref='products') 

但我猜这段代码真的很难与 SQLAlchemy 耦合。 那么我应该在我的架构中使用什么方法?

由于实体必须是应用程序的中心(域层),如果我需要更改我的数据库组件并且不使用 SQLAlchemy,那么该解决方案会出现问题吗?

我愿意接受所有建议。

【问题讨论】:

    标签: python sqlalchemy zope zope.component


    【解决方案1】:

    我将 ORM 用作实体对象并将适配器放在它上面:

    interfaces.py 的某个地方定义了 API:

    from zope.interface import Interface
    
    class IEntity(Interface):
    
        def pi_ing():
            '''makes the entity go "pi-ing" '''
    

    在某处定义了数据库模型:

    class EntityA(Base):       
        # .. table and relationship definitions are here
    

    在其他地方实现了 API:

    from zope.interface import implementer
    from zope.component import adapter, getGlobalSiteManager
    
    class EntityAPI(object):
    
        def __init__(self, instance):
            self.instance = instance
    
        def pi_ing(self):
            # make "pi_ing"
    
    
    @implementer(IEntityAProtocol)
    @adapter(int)
    def get_entity_a_by_id(id):
        return EntityAPI(session().query(EntityA).get(id))
    
    getGlobalSiteManager().registerAdapter(get_entity_a_by_id)
    

    现在一切就绪。在代码的业务逻辑中的某个地方 当您获得 entity_a 的 id 时,您可以这样做:

    from interfaces import IEntityAProtocol
    
    def stuff_which_goes_splat():        
        # ...
        entity_id = got_from_somewhere()
        IEntityProtocol(entity_id).pi_ing()
    

    现在您已经拥有了接口、数据库实体和 API 逻辑的完整独立实现。好消息是,您不必仅调整对象的 int ID 之类的原始内容,您可以调整任何内容,只要您可以实现从适配器到数据库实体的直接转换。

    警告:当然,相对于执行时间点,getGlobalSiteManager().registerAdapter(get_entity_a_by_id) 必须已经被调用。

    【讨论】:

      猜你喜欢
      • 2017-07-27
      • 1970-01-01
      • 2016-03-10
      • 1970-01-01
      • 1970-01-01
      • 2018-05-03
      • 2014-08-26
      • 2023-03-09
      • 2011-08-12
      相关资源
      最近更新 更多