Целочисленный SQLalchemy TypeDecorator для Python IntFlag: отфильтровать несколько записей - PullRequest
0 голосов
/ 15 октября 2019

Я хочу использовать тип данных Python IntFlag в приложении. В таблице базы данных доступен только тип Integer. Чтобы обеспечить обмен данными между приложением и БД, я использую Integer TypeDecorator из SQLalchemy.

База данных уже существует и использует MariaDB. Далее вниз sqlite используется для облегчения подражания примеру.

from enum import IntFlag, auto
import sqlalchemy as sa
from sqlalchemy.orm import create_session
from sqlalchemy.ext.declarative import declarative_base

class IntegerIntFlag(sa.types.TypeDecorator):
    impl = sa.Integer

    def __init__(self, intflagtype, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._intflagtype = intflagtype

    def process_bind_param(self, value, dialect):
        return value.value

    def process_result_value(self, value, dialect):
        return self._intflagtype(value)


class Dog(IntFlag):
    Puppy = auto()
    Medium = auto()
    Old = auto()
    TailWag = auto()
    Bark = auto()
    Run = auto()
    Hunt = auto()
    Sleep = auto()
    CatsLike = auto()
    CatsDislike = auto()

engine = sa.create_engine('sqlite:///:memory:')
session = sa.orm.sessionmaker(bind=engine)()
Base = declarative_base()


class DogTbl(Base):
    __tablename__ = 'dogs'

    Id = sa.Column('id', sa.Integer, primary_key=True)
    Name = sa.Column('name', sa.String)
    State = sa.Column('state', IntegerIntFlag(Dog))


Base.metadata.create_all(engine)

session.add(DogTbl(Name='dogA', State=Dog.Puppy))
session.add(DogTbl(Name='dogB', State=Dog.Medium))
session.add(DogTbl(Name='dogC', State=Dog.Old))
session.commit()
engine.execute(sa.text('insert into dogs values(4, "dogD", 4+16+512);'))

for dog in session.query(DogTbl):
    print(dog.Name, ':', dog.State, '(', dog.State.value, ')')

Результат печати должен выглядеть следующим образом:

dogA : Dog.Puppy ( 1 )
dogB : Dog.Medium ( 2 )
dogC : Dog.Old ( 4 )
dogD : Dog.CatsDislike|Bark|Old ( 532 )

Столбец stateтипа Integer в таблице dogs возвращает тип данных Python IntFlag правильно.

Фильтрация записей, которые имеют только 1 статусную запись, проста:

qry = session.query(DogTbl).filter(DogTbl.State == Dog.Puppy).first()

Но как мне отфильтровать старых собак, которые тоже лают?

Это, конечно, только пример. Класс IntFlag Dog может быть расширен по желанию.

Я не могу ответить на вопрос, как несколько записей Dog применяются к таблице для фильтрации. - Любая подсказка приветствуется.

1 Ответ

0 голосов
/ 24 октября 2019

Но как мне отфильтровать старых собак, которые также лают?

Учебник по SQLalchemy : см. Operators.op()

for dog in session.query(DogTbl).\
    filter(
        and_(DogTbl.State.op('&')(Dog.Old),
             DogTbl.State.op('&')(Dog.Bark))).\
        order_by(DogTbl.Name).all():
    print(dog.Name, dog.State)

Это уже половина решения. Я по-прежнему заинтересован в использовании SQLalchemy automap_base для моей существующей схемы MariaDB.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...