Python Flask Sqlalchemy:表中有3个主键,它们也是外键

Python Flask Sqlalchemy:表中有3个主键,它们也是外键,python,sqlalchemy,foreign-keys,flask-sqlalchemy,composite-primary-key,Python,Sqlalchemy,Foreign Keys,Flask Sqlalchemy,Composite Primary Key,我正在尝试将一个表从纯SQL转换为Flask Sqlalchemy,但是可用的文档并不清楚如何实现这个特定场景——主键也是外键 用于构建表的SQL如下所示,并且工作正常: CREATE TABLE IF NOT EXISTS `ws`.`Perfil_Plano_Transacao` ( `pptr_perf_id` INT NOT NULL, `pptr_tran_id` INT NOT NULL, `pptr_plan_id` INT NOT NULL, `p

我正在尝试将一个表从纯SQL转换为Flask Sqlalchemy,但是可用的文档并不清楚如何实现这个特定场景——主键也是外键

用于构建表的SQL如下所示,并且工作正常:

CREATE TABLE IF NOT EXISTS `ws`.`Perfil_Plano_Transacao` (
    `pptr_perf_id` INT NOT NULL,
    `pptr_tran_id` INT NOT NULL,
    `pptr_plan_id` INT NOT NULL,
    `pptr_dt_incluscao` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `pptr_dt_atualizacao` TIMESTAMP NULL,
PRIMARY KEY (`pptr_perf_id`, `pptr_tran_id`, `pptr_plan_id`),
INDEX `fk_Perfil_Plano_Transacao_Transacao1_idx` (`pptr_tran_id` ASC),
INDEX `fk_Perfil_Plano_Transacao_Plano1_idx` (`pptr_plan_id` ASC),
CONSTRAINT `fk_Perfil_Plano_Transacao_Perfil1`
    FOREIGN KEY (`pptr_perf_id`)
    REFERENCES `ws`.`Perfil` (`perf_id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
CONSTRAINT `fk_Perfil_Plano_Transacao_Transacao1`
    FOREIGN KEY (`pptr_tran_id`)
    REFERENCES `ws`.`Transacao` (`tran_id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
CONSTRAINT `fk_Perfil_Plano_Transacao_Plano1`
    FOREIGN KEY (`pptr_plan_id`)
    REFERENCES `ws`.`Plano` (`plan_id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB
在此之前,我一直使用的Python代码是:

class PerfilPlanoTransacaoModel(db.Model):

    __tablename__ = 'perfil_plano_transacao'

    pptr_perf_id = db.Column(db.Integer, primary_key=True, autoincrement=False)
    pptr_plan_id = db.Column(db.Integer, primary_key=True, autoincrement=False)
    pptr_tran_id = db.Column(db.Integer, primary_key=True, autoincrement=False)
    pptr_dt_inclusao = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
    pptr_dt_atualizacao = db.Column(db.DateTime, nullable=True)

    __table_args__ = (
        db.ForeignKeyConstraint(
            ['pptr_perf_id', 'pptr_plan_id', 'pptr_tran_id'],
            ['perfil.perf_id', 'plano.plan_id', 'transacao.tran_id'],
            ['fk_Perfil_Plano_Transacao_Perfil1', 'fk_Perfil_Plano_Transacao_Plano1', 'fk_Perfil_Plano_Transacao_Transacao1']
        ),
    )

我想知道我是否走对了路。例如,我找不到如何声明外键约束的
名称
,以及如何设置
索引
。是否有更多的
Flaks Sqlalchemy
方法来实现这一切?

如何声明外键约束的
名称

添加多个外键约束可以通过在
\uu表\uu参数中有多个
ForeignKeyConstraint
来完成。例如:

__table_args__ = (
    ForeignKeyConstraint(['pptr_perf_id'], ['perfil.perf_id'], name='fk_Perfil_Plano_Transacao_Perfil1'),
    ForeignKeyConstraint(['pptr_plan_id'], ['plano.plan_id'], name='fk_Perfil_Plano_Transacao_Plano1'),
    ForeignKeyConstraint(['pptr_tran_id'], ['transacao.tran_id'], name='fk_Perfil_Plano_Transacao_Transacao1'),
)
在这里,您可以看到定义本地列,然后定义原始表中的列并为其命名。前两个参数是数组的原因是允许复合外键

对代码进行此更改应计算为以下查询:

CREATE TABLE perfil_plano_transacao (
        pptr_perf_id INTEGER NOT NULL,
        pptr_plan_id INTEGER NOT NULL,
        pptr_tran_id INTEGER NOT NULL,
        pptr_dt_inclusao DATETIME NOT NULL,
        pptr_dt_atualizacao DATETIME,
        PRIMARY KEY (pptr_perf_id, pptr_plan_id, pptr_tran_id),
        CONSTRAINT "fk_Perfil_Plano_Transacao_Perfil1" FOREIGN KEY(pptr_perf_id) REFERENCES perfil (perf_id),
        CONSTRAINT "fk_Perfil_Plano_Transacao_Plano1" FOREIGN KEY(pptr_plan_id) REFERENCES plano (plan_id),
        CONSTRAINT "fk_Perfil_Plano_Transacao_Transacao1" FOREIGN KEY(pptr_tran_id) REFERENCES transacao (tran_id)
)
如何设置
索引

添加索引的简单方法是在列声明中设置索引:

pptr_perf_id = Column(Integer, primary_key=True, autoincrement=False)
pptr_plan_id = Column(Integer, primary_key=True, autoincrement=False, index=True)
pptr_tran_id = Column(Integer, primary_key=True, autoincrement=False, index=True)
from sqlalchemy import Index
Index('fk_Perfil_Plano_Transacao_Transacao1_idx', PerfilPlanoTransacaoModel.pptr_tran_id.asc())
Index('fk_Perfil_Plano_Transacao_Plano1_idx', PerfilPlanoTransacaoModel.pptr_plan_id.asc())
这将导致以下两个问题:

CREATE INDEX ix_perfil_plano_transacao_pptr_plan_id ON perfil_plano_transacao (pptr_plan_id)
CREATE INDEX ix_perfil_plano_transacao_pptr_tran_id ON perfil_plano_transacao (pptr_tran_id)
CREATE INDEX "fk_Perfil_Plano_Transacao_Transacao1_idx" ON perfil_plano_transacao (pptr_tran_id ASC)
CREATE INDEX "fk_Perfil_Plano_Transacao_Plano1_idx" ON perfil_plano_transacao (pptr_plan_id ASC)
也可以在表声明后单独添加:

pptr_perf_id = Column(Integer, primary_key=True, autoincrement=False)
pptr_plan_id = Column(Integer, primary_key=True, autoincrement=False, index=True)
pptr_tran_id = Column(Integer, primary_key=True, autoincrement=False, index=True)
from sqlalchemy import Index
Index('fk_Perfil_Plano_Transacao_Transacao1_idx', PerfilPlanoTransacaoModel.pptr_tran_id.asc())
Index('fk_Perfil_Plano_Transacao_Plano1_idx', PerfilPlanoTransacaoModel.pptr_plan_id.asc())
这将导致以下两个问题:

CREATE INDEX ix_perfil_plano_transacao_pptr_plan_id ON perfil_plano_transacao (pptr_plan_id)
CREATE INDEX ix_perfil_plano_transacao_pptr_tran_id ON perfil_plano_transacao (pptr_tran_id)
CREATE INDEX "fk_Perfil_Plano_Transacao_Transacao1_idx" ON perfil_plano_transacao (pptr_tran_id ASC)
CREATE INDEX "fk_Perfil_Plano_Transacao_Plano1_idx" ON perfil_plano_transacao (pptr_plan_id ASC)

@Halvor的答案是正确的,但我要补充的是,您有一个复合主键,但没有复合外键,您有三个单列外键指向不同的表,这意味着您也可以在列定义中声明外键:

from sqlalchemy import ForeignKey

class PerfilPlanoTransacaoModel(db.Model):

    __tablename__ = 'perfil_plano_transacao'

    pptr_perf_id = db.Column(
        db.Integer, 
        ForeignKey('perfil.perf_id'),
        primary_key=True, 
        autoincrement=False,
    )
    pptr_plan_id = db.Column(
        db.Integer, 
        ForeignKey('plano.plan_id'),
        primary_key=True, 
        autoincrement=False,
    )
    pptr_tran_id = db.Column(
        db.Integer, 
        ForeignKey('transacao.tran_id'),
        primary_key=True, 
        autoincrement=False,
    )
    pptr_dt_inclusao = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
    pptr_dt_atualizacao = db.Column(db.DateTime, nullable=True)
使用
ForeignKeyConstraint
比使用
ForeignKey
要详细一点,在本例中,我们在列定义中创建的
ForeignKey
对象最终会转换为
ForeignKeyConstraint
对象,处理单列键时,使用
ForeignKey
对象更容易。在
\u table\u args\u\uuu
中定义的
ForeignKeyConstraint
对象通常仅在需要创建复合外键时直接使用,例如,如果您有另一个表要引用
perfil\u plano\u transacao
,它需要是一个复合外键,您必须像上面那样定义它


我将按照@Halvor的答案回答您的其余问题。

为什么您会有不止一个主键?为什么可能呢?我想你想要一个前妻和一段感情field@NotSoShabby因为在这种情况下,主键由其他3个表(角色、计划和事务)的主键组成。这是一个非常常见和已知的用例。在这种情况下,此表用于提供配置文件在特定计划下可以进行的事务。例如:如果您为计划类型A付费,并且您是vip角色,您可以进行交易X和Y,但是如果您是常规角色,您可以只使用交易Y。其他外汇键不属于其他表吗?我很确定每个表只能有一个主键。您得到了什么错误?@notsobaby是的,它们属于其他表,正如外键所期望的那样:-)。在SQL上,有一个组合主键是非常常见的,并且呈现的SQL工作良好。关键是我在炼金术中找不到这种特定场景的例子。我还没有收到任何错误,因为我没有尝试运行代码。我正在努力寻找更好的例子,以确保它能像预期的那样工作,而不仅仅是工作。非常感谢你的回答。我肯定会使用两者的混合(你的和@Halvor),因为你的贡献显示了对库的高水平使用,但是被接受的答案给了我我想要的答案。