SQLAlchemy如何使用declarati映射onetoone关系的单个列

2024-09-28 03:16:16 发布

您现在位置:Python中文网/ 问答频道 /正文

这与这个问题有关,这个问题一直没有得到回答。在

我们试图在一个现有的模式(一个我们不能改变的模式)上建立一个Flask-SQLAlchemy项目,并决定使用声明性语法,以便我们能够以一种合理的方式将类组织到多个文件中进行维护。这对我们的大多数关系都有效,除了我们称之为属性表(因为缺少更好的术语)之外。这些是一些主对象的一对一叶表,通常包含某种属性的受控词汇表。ORM中的目标是映射所有这些类型的表,就像它们是主表的属性一样。在

下面是一个包含两个表的SQA示例:

class MarkerType(db.Model):
    __tablename__="mrk_types"
    _marker_type_key = db.Column(db.Integer,primary_key=True)
    name = db.Column(db.String())

class Marker(db.Model):
    __tablename__="mrk_marker"
    _marker_key=db.Column(db.Integer,primary_key=True)
    _marker_type_key=db.Column(db.Integer())

我们想进入MarkerType.name好像我们在说Marker.markertype,或在查询中作为Marker.markertype==“东西”。我唯一可以管理的方法是在Marker类中使用column\u属性,如下所示:

^{pr2}$

然而,我似乎找不到如何用声明的方式来做这件事,也许这种方式并不存在。有没有一种明智的方法可以让我不必担心我的输入,或者更糟的是我的类的顺序?因为我们有数百个表要映射,所以如果我们不得不担心类和导入顺序,我可以看到这是一个维护噩梦。在

如果所有这些都是完全不可能的,一厢情愿的想法,那么有什么更好的方法来映射这些表呢?在


Tags: 方法key声明dbmodel属性方式模式
3条回答

这听起来是Association Proxy的一个很好的用例。这将代理相关模型的字段。在这种情况下,实施将是:

from sqlalchemy.orm import relationship
from sqlalchemy.ext.associationproxy import association_proxy

class MarkerType(db.Model):
    __tablename__="mrk_types"
    _marker_type_key = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String())

class Marker(db.Model):
    __tablename__="mrk_marker"
    _marker_key=db.Column(db.Integer,primary_key=True)
    _marker_type_key=db.Column(db.Integer, ForeignKey('mrk_types._marker_type_key')

    mt = relationship(MarkerType, uselist=False)
    marker_type = association_proxy('mt', 'name')

这允许查询类似session.query(Marker).filter_by(marker_type='my_marker_type')

marker_type字段是MarkerType对象上name字段的代理。该对象可以被mt字段(关系字段)引用

注意uselist=False。这表示每个标记有一个标记类型。关系会自动检测到外键并使用它。在

所以据我所知,你被困在两张桌子上。一个是整数列,一个是字符串列

Class Marker
    _marker_key_ primary_key
    # _ = Integer ## This can be ignored as its unnecessary.

另一个有一个

^{pr2}$

正如我所读到的,您希望类标记具有许多可以轻松操作或调用的类标记类型字符串。不过,我不确定这是否是你想要的。在

如果是这样,那么假设您控制了数据库的种子设定,就可以实现这一点。可以在每个名称的开头构建一个指向标记主键的标志。在

示例:MarkerType.name=10324_橙色

我不熟悉在没有sessions的情况下使用SQLAlchemy,也不太想做研究,所以我只想写下我的答案,假设你使用的是SQLAlchemy sessions,这样你就可以了解这个概念并根据需要进行调整。在

### !!! ASSUME 'create_session' method exists that 
####    creates a sqlalchemy session instance

Class Marker:
    # ... initialize and such
    # ... then add these helper methods

    ## Get all properties linked to this primary table row
    def marker_types():
        return db.query(MarkerType).
            filter(MarkerType.name.like(str(self._marker_key_)+"_%")).all()
    ## Get specific property linked to this primary table row
    def marker_type(marker_type_name):
        db = create_session()
        marker_type_list = db.query(MarkerType).
            filter(MarkerType.name.like(str(self._marker_key_)+"_%")
            AND marker_type_name == MarkerType.name ).first()
        db.close()
        return marker_type_list

    def update_marker_type(old_val, new_val)
        db = create_session()
        updated_marker_type = marker_type(old_val)
        updated_marker_type.name = str(self._marker_key_)+" "+new_val
        db.close()
        return True

    def create_marker_type(val)
        marker_type = MarkerType(name = str(self._marker_key_)+" "+val)
        db = create_session()
        db.add(marker_type)
        db.commit()
        db.close()
        return marker_type._marker_type_key

从这里可以向名称字符串添加其他标志。比如属性类型。在

Marker.id = 193

MarkerType.id = 1
MarkerType.name = "193_color_Black"
MarkerType.id = 2
MarkerType.name = "193_style_Fine"

这个附加的标志可以让您搜索链接到特定行的常规属性特定名称,它的可用性大大提高,尽管稍微复杂一些。实际上取决于你的用例。在

使用^{}允许从Marker表访问marker_type,并指定一个ForeignKey约束,以便SQLAlchemy理解表之间的关系。在

这允许您从标记记录轻松访问MarkerType属性,并对MarkerType.name进行查询。下面显示插入两条记录,然后根据属性name进行过滤。在

>>> db.session.add(Marker(marker_type=MarkerType(name="blue")))
>>> db.session.add(Marker(marker_type=MarkerType(name="red")))
>>> db.session.commit()


>>> markers = Marker.query.all()
>>> print({m._marker_key: m.marker_type.name for m in markers})

{1: 'blue', 2: 'red'}

>>> result = Marker.query.filter(Marker._marker_type_key==MarkerType._marker_type_key) \
...                      .filter(MarkerType.name=='blue').all()
>>> print({m._marker_key: m.marker_type.name for m in result})

{1: 'blue'}

类的声明顺序并不重要,类需要一起声明。不过,架构必须针对db的同一实例注册,当您查询表时,需要导入您引用的表类。在

relationshipForeignKey添加到标记后,声明性模式将变为:

^{pr2}$

相关问题 更多 >

    热门问题