python - 如何在 SQLAlchemy 中组合两个模型类

标签 python database orm sqlalchemy

我是使用 SQLAlchemy 的 ORM 的新手,我以前只使用原始 SQL。我有数据库表、LabelPositionDataSet,如下所示:

enter image description here

相应的 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_idposition_id。所以我创建了一个新类 Data 以将 labelposition 保存为字符串。

# 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 组合这些表类吗?

最佳答案

您可以使用 relationshipsassociation proxies建立从 DataSetLabelPosition 对象的链接:

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(及其名称)的 LabelPosition 对象:

>>> 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/

相关文章:

python - 伪字典作为属性

Python Flask POST/GET 请求

python - 在内存中SQLite3共享数据库python

java - 初学者问题: basic insertion idiom for JPA?

python - 我应该尽量减少 Pony ORM 中 db_session 的使用吗? db_session 的目的是什么?

python - 如何使用远程 API 重置数据存储模型的属性类型

python - 登录查看成功

php - 为什么这个简单的PHP代码无法将数据添加到我的数据库中?

database - 银行数据库设计问题

go - 在 beego orm 中插入带有 m2m 的模型