我是使用 SQLAlchemy 的 ORM 的新手,我以前只使用原始 SQL。我有数据库表、Label
、Position
和 DataSet
,如下所示:
相应的 python 类如下:
class Label(Base):
__tablename__ = 'Label'
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False, unique=true)
class Position(Base):
__tablename__ = 'Position'
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False, unique=true)
class DataSet(Base):
__tablename__ = 'DataSet'
id = Column(Integer, primary_key=True)
label_id = Column(Integer, ForeignKey('Label.id'))
position_id = Column(Integer, ForeignKey('Position.id'))
timestamp = Column(Integer, nullable=False)
但在我的服务中,我不会公开那些 label_id
和 position_id
。所以我创建了一个新类 Data
以将 label
和 position
保存为字符串。
# Not a full class to only show my concept
class Data:
# data dictionary will have data
def __init__(self, **kwargs):
# So it doesn't have ids. Label and Position as string
keys = {'label', 'position', 'timestamp'}
self.data = {k: kwargs[k] for k in keys}
# An example of inserting data.
# skipped detail and error handling to clarify
def insert(self):
session = Session()
# get id of label and position
# remember that it returns a tuple, not a single value
self.data['label_id'] = session.query(Label.id).\
filter(Label.name == self.data['label']).one_or_none()
self.data['position_id'] = session.query(Position.id).\
filter(Position.name == self.data['position']).one_or_none()
# add new dataset
self.data.pop('label')
self.data.pop('position')
new_data = DataSet(**self.data)
session.add(new_data)
session.commit()
但它看起来有点难看,我认为应该有更简单的方法来做。有什么方法可以使用 SQLAlchemy API 组合这些表类吗?
最佳答案
您可以使用 relationships和 association proxies建立从 DataSet
到 Label
和 Position
对象的链接:
from sqlalchemy.orm import relationship
from sqlalchemy.ext.associationproxy import association_proxy
class DataSet(Base):
__tablename__ = 'DataSet'
id = Column(Integer, primary_key=True)
label_id = Column(Integer, ForeignKey('Label.id'))
label = relationship('Label')
label_name = association_proxy('label', 'name')
position_id = Column(Integer, ForeignKey('Position.id'))
position = relationship('Position')
position_name = association_proxy('position', 'name')
timestamp = Column(Integer, nullable=False)
在此之后,您可以通过新属性访问链接到 DataSet
(及其名称)的 Label
和 Position
对象:
>>> d = session.query(DataSet).first()
>>> d.position
<Position object at 0x7f3021a9ed30>
>>> d.position_name
'position1'
不幸的是,插入DataSet
对象并不是那么漂亮。您可以为 association_proxy
指定 creator
函数,它可以获取名称并创建或检索相应的对象(在 this answer 中找到):
def _label_creator(name):
session = Session()
label = session.query(Label).filter_by(name=name).first()
if not label:
label = Label(name=name)
session.add(label)
session.commit()
session.close()
return label
label_name = association_proxy('label', 'name', creator=_label_creator)
在为两个代理指定 creator
函数后,您可以通过这种方式创建新的 DataSet
对象:
dataset = DataSet(
label_name='label1',
position_name='position2',
timestamp=datetime.datetime.now()
)
关于python - 如何在 SQLAlchemy 中组合两个模型类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42287854/