Для одного решения потребуются две части реализации:
- Реализация составных-прокси-серверов-прокси в
Addendum
- Сделать новое свойство из (1)
Addendum.badges
доступным из BaseValueObject
Часть 1: Реализация составной-прокси-ассоциации
Добавьте следующие свойства к Addendum
:
badges = association_proxy (
'addendum_badge_maps',
'badge_value',
creator=lambda bt, bv:
AddendumBadgeMap(badge_type=bt, badge_value=bv)
)
и следующие до AddendumBadgeMap
:
addendum = orm.relationship(Addendum, backref=orm.backref(
'addendum_badge_maps',
collection_class = attribute_mapped_collection("badge_type"),
cascade="all, delete-orphan")
)
badge = orm.relationship('Badge',
single_parent=True,
)
badge_value = association_proxy ('badge', 'value')
Теперь добавьте __init__
-метод к Badge
:
def __init__(self, value):
self.value = value
и добавьте сверху следующий импорт:
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.orm.collections import attribute_mapped_collection
Часть 2: Доступ к badge
-прокси из BaseValueObjects
Ссылка Addendum
-объекты на BaseValueObjects
через добавление свойства к Addendum
:
base_value_object = orm.relationship(
"BaseValueObject",
backref=orm.backref('addendum', uselist=False)
)
Чтобы получить доступ к badegs
, добавьте следующее к BaseValueObjects
:
def add_badge(self, badge_dict={}, **kwargs):
if self.addendum is None:
self.addendum = Addendum()
badge_dict.update(kwargs)
self.addendum.badges = badge_dict
_name = association_proxy('addendum', 'name',
creator=lambda name: Addendum(
name=name, description='', flag=False))
_description = association_proxy('addendum', 'description',
creator=lambda description: Addendum(
name='', description=description, flag=False))
_flag = association_proxy('addendum', 'flag',
creator=lambda flag: Addendum(
name='', description='', flag=flag))
@property
def badges(self):
try:
return self.addendum.badges
except AttributeError:
"In case that there is no ``Addendum`` specified, yet."
return None
@badges.setter
def badges(self, value):
self.add_badge(value)
@property
def name(self):
try:
return self._name
except AttributeError:
"In case that there is no ``Addendum`` specified, yet."
return ""
@name.setter
def name(self, value):
self._name = value
@property
def description(self):
try:
return self._description
except AttributeError:
"In case that there is no ``Addendum`` specified, yet."
return ""
@description.setter
def description(self, value):
self._description = value
@property
def flag(self):
try:
return self._flag
except AttributeError:
"In case that there is no ``Addendum`` specified, yet."
return ""
@flag.setter
def flag(self, value):
self._flag = value
Полный код
import sqlalchemy as sa
import sqlalchemy.orm as orm
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.orm.collections import attribute_mapped_collection
DBSession = scoped_session(sessionmaker())
Base = declarative_base ()
###### ValueObjects: ##########
class BaseValueObject(Base):
__tablename__ = 'value_objects'
id = sa.Column(sa.Integer, primary_key=True)
vo_type = sa.Column (sa.String, nullable=False)
__mapper_args__ = {'polymorphic_on': vo_type}
# Define Badge-Access:
def add_badge(self, badge_dict={}, **kwargs):
if self.addendum is None:
self.addendum = Addendum()
badge_dict.update(kwargs)
self.addendum.badges = badge_dict
_name = association_proxy('addendum', 'name',
creator=lambda name: Addendum(
name=name, description='', flag=False))
_description = association_proxy('addendum', 'description',
creator=lambda description: Addendum(
name='', description=description, flag=False))
_flag = association_proxy('addendum', 'flag',
creator=lambda flag: Addendum(
name='', description='', flag=flag))
@property
def badges(self):
try:
return self.addendum.badges
except AttributeError:
"In case that there is no ``Addendum`` specified, yet."
return None
@badges.setter
def badges(self, value):
self.add_badge(value)
@property
def name(self):
try:
return self._name
except AttributeError:
"In case that there is no ``Addendum`` specified, yet."
return ""
@name.setter
def name(self, value):
self._name = value
@property
def description(self):
try:
return self._description
except AttributeError:
"In case that there is no ``Addendum`` specified, yet."
return ""
@description.setter
def description(self, value):
self._description = value
@property
def flag(self):
try:
return self._flag
except AttributeError:
"In case that there is no ``Addendum`` specified, yet."
return ""
@flag.setter
def flag(self, value):
self._flag = value
class ObjectOne(BaseValueObject):
__tablename__ = 'objects_one'
__mapper_args__ = {'polymorphic_identity': 'ObjectOne'}
id = sa.Column(sa.ForeignKey('value_objects.id'), primary_key=True)
any_attribute = sa.Column(sa.String)
class ObjectTwo(BaseValueObject):
__tablename__ = 'objects_two'
__mapper_args__ = {'polymorphic_identity': 'ObjectTwo'}
id = sa.Column(sa.ForeignKey('value_objects.id'), primary_key=True)
any_attribute = sa.Column(sa.String)
###############################
##### Addendum and Bagde ##########
class Addendum(Base):
__tablename__ = 'addenda'
__table_args__ = (
sa.UniqueConstraint('name', 'id'),
{}
)
id = sa.Column (sa.Integer, primary_key=True)
name = sa.Column (sa.String, nullable=False, default='')
description = sa.Column (sa.String, nullable=False, default='')
flag = sa.Column ( sa.Boolean, nullable=False, default=False)
value_object_id = sa.Column ( sa.ForeignKey ('value_objects.id'),
unique=True)
# Properties:
base_value_object = orm.relationship(
"BaseValueObject",
backref=orm.backref('addendum', uselist=False)
)
badges = association_proxy (
'addendum_badge_maps',
'badge_value',
creator=lambda bt, bv:
AddendumBadgeMap(badge_type=bt, badge_value=bv)
)
class Badge(Base):
__tablename__ = 'badges'
id = sa.Column (sa.Integer, primary_key=True)
value = sa.Column (sa.String)
def __init__(self, value):
self.value = value
class AddendumBadgeMap(Base):
__tablename__ = 'addendum_badge_maps'
__table_args__ = (
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('badge_id', 'badge_type'),
{}
)
id = sa.Column('id', sa.Integer)
addendum_id = sa.Column(sa.ForeignKey('addenda.id'), nullable=False)
badge_id = sa.Column(sa.ForeignKey('badges.id'), nullable=False)
badge_type = sa.Column (sa.String)
#Properties:
addendum = orm.relationship(Addendum, backref=orm.backref(
'addendum_badge_maps',
collection_class = attribute_mapped_collection("badge_type"),
cascade="all, delete-orphan")
)
badge = orm.relationship('Badge',
single_parent=True,
)
badge_value = association_proxy ('badge', 'value')
###################################
if __name__ == '__main__':
engine = sa.create_engine('sqlite:///:memory:', echo=True)
DBSession.configure(bind=engine)
Base.metadata.create_all(engine)
session = DBSession()
o1 = ObjectOne(any_attribute="test1")
o1.name = "First Object"
session.add(o1)
session.commit()
o1.badges = {'first name': 'Max'}
o1.badges['last name'] = 'Mueller'
session.commit()
print o1.name
print o1.description
print o1.flag
print o1.any_attribute
print o1.badges