Flask-Sqlalchemy:Table 有 3 个主键也是外键
Flask-Sqlalchemy: Table with 3 primary keys that are also foreign keys
我正在尝试将 table 从纯 SQL 转换为 Flask-Sqlalchemy,但可用的文档不清楚如何执行此特定场景 - 主键也是外键.
构建 table 的 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']
),
)
我想知道我走的路是否正确。例如,我没有找到如何声明外键约束的 name
以及如何设置 INDEX
。是否有更多 Flaks-Sqlalchemy
方法来完成这一切?
如何声明name
外键约束
添加多个外键约束可以通过在 __table_args__
中设置多个 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'),
)
在这里您可以看到您定义了本地列,然后是原始 table 中的列并为其命名。前两个参数是数组的原因是允许复合外键。
对您的代码进行此更改应评估以下查询:
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)
)
如何设置INDEX
添加索引的简单方法是在列声明中设置它:
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)
这将导致以下两个查询:
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)
或者在table声明后单独添加:
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 "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 的回答是正确的,但我要补充一点,你有一个复合主键但没有复合外键,你有三个单列外键指向不同的 tables意味着您也可以在列定义中声明外键:
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
对象更容易。 __table_args__
中定义的 ForeignKeyConstraint
对象通常仅在需要创建复合外键时直接使用,例如,如果您有另一个 table 想要引用 perfil_plano_transacao
,它需要是一个复合外键,您必须像上面那样定义它。
我将推迟@Halvor 对你问题的其余部分的回答。
我正在尝试将 table 从纯 SQL 转换为 Flask-Sqlalchemy,但可用的文档不清楚如何执行此特定场景 - 主键也是外键.
构建 table 的 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']
),
)
我想知道我走的路是否正确。例如,我没有找到如何声明外键约束的 name
以及如何设置 INDEX
。是否有更多 Flaks-Sqlalchemy
方法来完成这一切?
如何声明name
外键约束
添加多个外键约束可以通过在 __table_args__
中设置多个 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'),
)
在这里您可以看到您定义了本地列,然后是原始 table 中的列并为其命名。前两个参数是数组的原因是允许复合外键。
对您的代码进行此更改应评估以下查询:
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)
)
如何设置INDEX
添加索引的简单方法是在列声明中设置它:
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)
这将导致以下两个查询:
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)
或者在table声明后单独添加:
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 "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 的回答是正确的,但我要补充一点,你有一个复合主键但没有复合外键,你有三个单列外键指向不同的 tables意味着您也可以在列定义中声明外键:
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
对象更容易。 __table_args__
中定义的 ForeignKeyConstraint
对象通常仅在需要创建复合外键时直接使用,例如,如果您有另一个 table 想要引用 perfil_plano_transacao
,它需要是一个复合外键,您必须像上面那样定义它。
我将推迟@Halvor 对你问题的其余部分的回答。