简体   繁体   English

Flask-Sqlalchemy:具有3个主键的表,也是外键

[英]Flask-Sqlalchemy: Table with 3 primary keys that are also foreign keys

I am trying to translate a table from pure SQL to Flask-Sqlalchemy, but the documentation available is not clear about how to do this specific scenario - Primary keys that are also foreign keys. 我正在尝试将表从纯SQL转换为Flask-Sqlalchemy,但是可用的文档并不清楚如何执行此特定方案 - 主键也是外键。

The SQL to build the table is the following and it works fine: 构建表的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

And the Python code I've come until here is: 我到这里来的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']
        ),
    )

I would like to know if I am going toward the right way. 我想知道我是否走向正确的道路。 I dind't find, for example, how to declare the name of the foreign key constraint and how to set the INDEX . 例如,我找不到如何声明外键约束的name以及如何设置INDEX Is there a more Flaks-Sqlalchemy way to do all this? 还有更多的Flaks-Sqlalchemy方法可以做到这一切吗?

The answer by @Halvor is right, but I'll just add that you have a composite primary key but not a composite foreign key, you have three single column foreign keys pointing to different tables which means you can declare the foreign key in your column definition too: @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)

Using ForeignKeyConstraint is a little bit more verbose than using ForeignKey and the ForeignKey objects we create in your column definitions in this example are eventually converted to ForeignKeyConstraint objects anyway, its just easier to use the ForeignKey object when you are dealing with single column keys. 使用ForeignKeyConstraint比使用ForeignKey稍微冗长一点,我们在本例中的列定义中创建的ForeignKey对象最终转换为ForeignKeyConstraint对象,在处理单列键时更容易使用ForeignKey对象。 The ForeignKeyConstraint object defined in __table_args__ is usually only used directly when you need to create a composite foreign key, for example if you had another table that wanted to reference perfil_plano_transacao , it would need to be a composite foreign key and you'd have to define it as you have done above. __table_args__定义的ForeignKeyConstraint对象通常仅在需要创建复合外键时直接使用,例如,如果您有另一个表想要引用perfil_plano_transacao ,则它需要是复合外键,您必须定义就像你上面所做的一样。

I'll defer to @Halvor's answer for the rest of your question. 对于你提出的其他问题,我会按照@ Halvor的回答。

How to declare the name of the foreign key constraint 如何声明外键约束的name

Adding multiple foreign key constraints can be done by having multiple ForeignKeyConstraint s in your __table_args__ . 通过在__table_args__多个ForeignKeyConstraint可以添加多个外键约束。 For example: 例如:

__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'),
)

Here you see that your define your local column, then the column in the original table and give it a name. 在这里,您可以看到您定义本地列,然后是原始表中的列,并为其命名。 The reason the first two parameters are arrays are to allow for composite foreign keys. 前两个参数是数组的原因是允许复合外键。

Making this change to your code should evaluate to the following query: 对代码进行此更改应评估以下查询:

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)
)

How to set the INDEX 如何设置INDEX

The simple way of adding an index is setting it on the column declaration: 添加索引的简单方法是在列声明上设置它:

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)

Which would lead to the following two queries: 这将导致以下两个查询:

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)

Or you can add it separately after the table declaration: 或者您可以在表声明后单独添加它:

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())

Which would lead to the following two queries: 这将导致以下两个查询:

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM