Estoy tratando de tener una tabla que tenga la siguiente combinación única: solo podría haber una entrada con un account_id configurado como active , pero múltiples entradas de ese mismo account_id en el que active está configurado como False , lo que significa que esta es una posibilidad :
id | account_id | active | timestamp 0 | 12 | False | 2020-07-15 04:10:48.380781 1 | 12 | True | 2020-07-15 04:10:48.380781 2 | 12 | False |2020-07-15 04:10:48.380781Pero esto no puede:
id | account_id | active | timestamp 0 | 12 | False |2020-07-15 04:10:48.380781 1 | 12 | True |2020-07-15 04:10:48.380781 2 | 12 | True |2020-07-15 04:10:48.380781 Estoy tratando de usar un índice parcial para obtener esta funcionalidad, pero la advertencia es que tanto account_id como active se heredan de una clase genérica. Las clases quedan de la siguiente manera:
class GenericClass: id = Column(Integer, primary_key=True) active = Column(Boolean, nullable=False, doc='Whether this is active or not.' @declared_attr # declared_attr decorator makes it like classmethod def account_id(cls): return Column(Integer, ForeignKey('account.account_id'))Aquí está mi tabla real:
class AdvancedTable(Some.Model, GenericClass): __versioned__ = {} __table_args__ = ( Index('active_accid_index', 'account_id', unique=True, sqlite_where= GenericClass.active, postgresql_where= GenericClass.active), ) timestamp = Column( DateTime, nullable=True, doc='DateTime this info was activated.') Pero recibo el siguiente error: sqlalchemy.exc.CompileError: Cannot compile Column object until its 'name' is assigned.
¿Alguien puede ayudarme a lograr la funcionalidad que me gustaría tener sin obtener GenericClass (estoy usando postgresql y sqlite)?
Creo que logré superar el problema moviendo el índice fuera de la definición de la tabla. Vea el código a continuación. La pieza relevante está resaltada.
Base = declarative_base() class GenericClass(object): @declared_attr def account_id(cls): return Column('account_id', ForeignKey('account.id')) @declared_attr def account(cls): return relationship("Account") active = Column(Boolean, nullable=False, doc='Whether this is active or not.') class Account(Base): __tablename__ = 'account' id = Column(Integer, primary_key=True) name = String(length=32) class AdvancedTable(GenericClass, Base): __versioned__ = {} __tablename__ = "advanced" id = Column(Integer, primary_key=True) timestamp = Column( DateTime, nullable=True, doc='DateTime this info was activated.') my_index = Index('active_accid_index', AdvancedTable.account_id, unique = True, sqlite_where = AdvancedTable.active ) # ===== This is the key part ===== engine = create_engine('sqlite:///advanced.db') Base.metadata.create_all(engine)El esquema resultante, para sqlite, es:
CREATE TABLE account ( id INTEGER NOT NULL, PRIMARY KEY (id) ); CREATE TABLE advanced ( active BOOLEAN NOT NULL, id INTEGER NOT NULL, timestamp DATETIME, account_id INTEGER, PRIMARY KEY (id), CHECK (active IN (0, 1)), FOREIGN KEY(account_id) REFERENCES account (id) ); CREATE UNIQUE INDEX active_accid_index ON advanced (account_id) WHERE active;