【问题标题】:How to create index on on SQLAlchemy column_property?如何在 SQLAlchemy column_property 上创建索引?
【发布时间】:2019-07-13 13:26:40
【问题描述】:

使用带有 SQLite 引擎的 SQLAlchemy,我得到了一个描述目录结构的自引用层次表。

from sqlalchemy import Column, Integer, String, ForeignKey, Index
from sqlalchemy.orm import column_property, aliased, join
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class Dr(Base):
    __tablename__ = 'directories'
    id = Column(Integer, primary_key=True)
    name = Column(String)
    parent_id = Column(Integer, ForeignKey('directories.id'))

每个 Dr 行只知道它自己的“名称”和它的“parent_id”。我添加了一个名为“path”的递归 column_property,它返回一个字符串,其中包含来自根 Dr 的 Dr 的所有祖先。

root_anchor = (
    select([Dr.id, Dr.name, Dr.parent_id,Dr.name.label('path')])
    .where(Dr.parent_id == None).cte(recursive=True)
)

dir_alias = aliased(Dr)
cte_alias = aliased(root_anchor)

path_table = root_anchor.union_all(
    select([
        dir_alias.id, dir_alias.name,
        dir_alias.parent_id, cte_alias.c.path + "/" + dir_alias.name
    ]).select_from(join(
        dir_alias, cte_alias, onclause=cte_alias.c.id==dir_alias.parent_id)
    ))
)

Dr.path = column_property(
    select([path_table.c.path]).where(path_table.c.id==Dr.id)
)

这是一个输出示例:

"""
-----------------------------
| id |   name   | parent_id |
-----------------------------
|  1 | root     | NULL      |
-----------------------------
|  2 | kid      | 1         |
-----------------------------
|  3 | grandkid | 2         |
-----------------------------
"""
sqllite_engine = create_engine('sqlite:///:memory:')
Session = sessionmaker(bind=sqllite_engine)
session = Session()

instance = session.query(Dr).filter(Dr.name=='grandkid').one()
print(instance.path)
# Outputs: "root/kid/grandkid" 

我希望能够在“路径”属性上添加一个索引或至少一个唯一约束,以便唯一路径不能在表中多次存在。我试过了:

Index('pathindex', Directory.path, unique=True)

...没有运气。没有引发错误,但 SQLAlchemy 似乎没有注册索引,它只是默默地忽略它。它仍然允许添加重复路径,例如:

session.add(Dr(name='grandkid', parent_id=2))
session.commit()

作为 Index() 被忽略的进一步证据,检查表的“indexes”属性会得到一个空集:

print(Dr.__table__.indexes)
#Outputs: set([])

数据库中不能存在重复路径对我来说很重要。我不确定我在 SQLAlchemy 中尝试使用 column_property 是否可行,如果不是,我很想听听一些关于如何解决此问题的建议。

【问题讨论】:

    标签: python sql sqlite sqlalchemy flask-sqlalchemy


    【解决方案1】:

    我认为唯一索引就足够了,在课堂上Db

    __table_args__ = (UniqueConstraint('parent_id', 'name'), )
    

    【讨论】:

    • 只有一个边缘情况,但如果它是一个问题则值得商榷:可以插入另一个根,因为唯一约束不会捕获另一个 NULL, 'root'。也许如果根节点也是自引用而不是NULL
    • ...或者可能是一些 hacky 的部分唯一索引来强制执行单根?
    • 类似Index('dir_single_root_idx', text("(1)"), unique=True, postgresql_where=Directory.parent_id == None)
    猜你喜欢
    • 1970-01-01
    • 2015-09-02
    • 1970-01-01
    • 2014-08-21
    • 2017-07-12
    • 1970-01-01
    • 2021-02-21
    • 2012-08-23
    • 2016-03-15
    相关资源
    最近更新 更多