Создайте повторно используемый компонент с ZCA и SQLAlchemy
На самом деле я разрабатываю большое приложение для рабочего стола с Python 3.4. Я выбрал архитектуру портов и адаптеров, известную как шестиугольная архитектура. Основная цель это работа с многоразовым компонентом.
Для организации кода и введения некоторых правил мы будем использовать Zope Component Architecture (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?
Я открыт для всех предложений.
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, вы можете просто сделать:
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)
Должно быть, уже был вызван.