Как создать индекс по SQLAlchemy column_property? - PullRequest
0 голосов
/ 20 февраля 2019

Используя SQLAlchemy с движком SQLite, я получил иерархическую таблицу с самообращением, которая описывает структуру каталогов.

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 знает только свое «имя» и свой «родительский_идентификатор»,Я добавил рекурсивный column_property под названием «путь», который возвращает строку, содержащую всех предков доктора из корня 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([])

Для меня важно, чтобы в базе данных не существовало повторяющихся путей.Я не уверен, возможно ли то, что я пытаюсь сделать с column_property, в SQLAlchemy, и если нет, то я бы хотел услышать некоторые предложения о том, как еще я могу это сделать.

1 Ответ

0 голосов
/ 20 февраля 2019

Я думаю, что в классе должно быть достаточно уникального индекса Db

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