связанный ответ имеет все компоненты.attribute_mapped_collection и association_proxy могут делать много вместе.Сначала вот словарь string-> tuple (int, boolean) (обновлен для m2m):
from sqlalchemy import Integer, Boolean, String, Column, create_engine, \
ForeignKey
from sqlalchemy.orm import Session, relationship
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.orm.collections import attribute_mapped_collection
Base = declarative_base()
class SomeClass(Base):
__tablename__ = 'sometable'
id = Column(Integer, primary_key=True)
tuple_elements = relationship(
"TupleAssociation",
collection_class=attribute_mapped_collection("name"),
cascade="all, delete-orphan"
)
items = association_proxy("tuple_elements", "as_tuple")
class TupleAssociation(Base):
__tablename__ = 'tuple_association'
parent_id = Column(Integer, ForeignKey('sometable.id'), primary_key=True)
tuple_id = Column(Integer, ForeignKey("tuple_data.id"), primary_key=True)
name = Column(String)
tuple_element = relationship("TupleElement")
def __init__(self, key, tup):
self.name = key
self.tuple_element = TupleElement(tup)
@property
def as_tuple(self):
return self.tuple_element.as_tuple
class TupleElement(Base):
__tablename__ = 'tuple_data'
id = Column(Integer, primary_key=True)
col1 = Column(Integer)
col2 = Column(Boolean)
def __init__(self, tup):
self.col1, self.col2 = tup
@property
def as_tuple(self):
return self.col1, self.col2
e = create_engine('sqlite://')
Base.metadata.create_all(e)
s = Session(e)
collection = SomeClass()
collection.items["item name 1"] = (3, True)
collection.items["item name 2"] = (1, False)
print collection.items
s.add(collection)
s.commit()
collection = s.query(SomeClass).first()
print collection.items
Здесь все наоборот: кортежи в ассоциации и имя в конечной точке:
from sqlalchemy import Integer, Boolean, String, Column, create_engine, \
ForeignKey
from sqlalchemy.orm import Session, relationship
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.orm.collections import attribute_mapped_collection
Base = declarative_base()
class SomeClass(Base):
__tablename__ = 'sometable'
id = Column(Integer, primary_key=True)
tuple_elements = relationship(
"TupleAssociation",
collection_class=attribute_mapped_collection("name"),
cascade="all, delete-orphan"
)
items = association_proxy("tuple_elements", "as_tuple")
class TupleAssociation(Base):
__tablename__ = 'tuple_association'
parent_id = Column(Integer, ForeignKey('sometable.id'), primary_key=True)
name_id = Column(Integer, ForeignKey("name_data.id"), primary_key=True)
col1 = Column(Integer)
col2 = Column(Boolean)
name_element = relationship("NameElement")
def __init__(self, key, tup):
self.name_element = NameElement(name=key)
self.col1, self.col2 = tup
@property
def name(self):
return self.name_element.name
@property
def as_tuple(self):
return self.col1, self.col2
class NameElement(Base):
__tablename__ = 'name_data'
id = Column(Integer, primary_key=True)
name = Column(String)
e = create_engine('sqlite://', echo=True)
Base.metadata.create_all(e)
s = Session(e)
collection = SomeClass()
collection.items["item name 1"] = (3, True)
collection.items["item name 2"] = (1, False)
print collection.items
s.add(collection)
s.commit()
collection = s.query(SomeClass).first()
print collection.items
это, вероятно, все, что вам нужно.Если вы используете Postgresql, который поддерживает кортежи SQL, вы можете добавить больше к вышеперечисленному, используя гибриды плюс tuple_()
, так что as_tuple
можно использовать и на уровне SQL (ниже также используется один ко многим вместообъект ассоциации только для примера):
from sqlalchemy import Integer, Boolean, String, Column, create_engine, \
ForeignKey
from sqlalchemy.orm import Session, relationship
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.orm.collections import attribute_mapped_collection
from sqlalchemy.ext import hybrid
from sqlalchemy.sql import tuple_
Base = declarative_base()
class SomeClass(Base):
__tablename__ = 'sometable'
id = Column(Integer, primary_key=True)
tuple_elements = relationship(
"TupleElement",
collection_class=attribute_mapped_collection("name"),
cascade="all, delete-orphan"
)
items = association_proxy("tuple_elements", "as_tuple")
class TupleElement(Base):
__tablename__ = 'tuple_data'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('sometable.id'), nullable=False)
name = Column(String)
col1 = Column(Integer)
col2 = Column(Boolean)
def __init__(self, key, tup):
self.name = key
self.col1, self.col2 = tup
@hybrid.hybrid_property
def as_tuple(self):
return self.col1, self.col2
@as_tuple.expression
def as_tuple(self):
return tuple_(self.col1, self.col2)
e = create_engine('postgresql://scott:tiger@localhost/test', echo=True)
Base.metadata.drop_all(e)
Base.metadata.create_all(e)
s = Session(e)
collection = SomeClass()
collection.items["item name 1"] = (3, True)
collection.items["item name 2"] = (1, False)
print collection.items
s.add(collection)
s.commit()
q = s.query(SomeClass).join(SomeClass.tuple_elements)
assert q.filter(TupleElement.as_tuple == (3, True)).first() is collection
assert q.filter(TupleElement.as_tuple == (5, False)).first() is None
print s.query(TupleElement.as_tuple).all()