Die verknüpfte Antwort enthält alle Komponenten. attribute_mapped_collection und association_proxy können zusammen viel leisten. Hier ist zunächst das Wörterbuch von string->tuple(int, boolean) (aktualisiert für 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
Hier ist es andersherum, mit den Tupeln auf der Assoziation und dem Namen auf dem Endpunkt:
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
Das ist wahrscheinlich alles, was Sie brauchen. Wenn Sie Postgresql verwenden, das SQL-Tupel unterstützt, können Sie die obigen Angaben durch Hybride plus tuple_()
, so dass as_tuple
kann auch auf der SQL-Ebene verwendet werden (im Folgenden wird auch One-to-many anstelle von Assoziationsobjekt verwendet, nur als Beispiel):
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()