Flask-SQLAlchemy使用复合键进行多对多

时间:2015-04-08 10:14:02

标签: python mysql flask-sqlalchemy

我正在尝试使用Flask-SQLAlchemy使用一个模型中的两个主键和另一个模型中的一个来构建多对多关系。我的模型如下:

服务:

class Service(db.Model):
    """
        Service model object
    """
    name = db.Column(db.String(120), primary_key=True, nullable=False)
    description = db.Column(db.Text)

ContactClosure:

class ContactClosure(db.Model):

    module = db.Column(db.Integer, primary_key=True, nullable=False)
    relay = db.Column(db.Integer, primary_key=True, nullable=False)
    status = db.Column(db.Boolean)
    description = db.Column(db.Text)

    #Relationships
    hostname = db.Column(db.String(120), db.ForeignKey('ip2cc.hostname'), primary_key=True, nullable=False)
    device_name = db.Column(db.String(120), db.ForeignKey('device.name'), primary_key=True, nullable=False)
    services = db.relationship('Service', secondary=cc_services, backref=db.backref('contact_closures', lazy='dynamic'))

这是相关表格:

cc_services = db.Table('cc_services',
                    db.Column('service_name', db.String(120), db.ForeignKey('service.name')),
                    db.Column('hostname', db.String(120), db.ForeignKey('contact_closure.hostname')),
                    db.Column('device_name', db.String(120), db.ForeignKey('contact_closure.device_name')),
                    )

这是我得到的错误:

  

" AmbiguousForeignKeysError:无法确定之间的连接条件   关系中的父/子表ContactClosure.services - 那里   是通过辅助表链接表的多个外键路径   ' cc_services&#39 ;.指定' foreign_keys'参数,提供清单   那些应被视为包含外键的列   从辅助表引用到父和子的每一个   表"

如果有人能说出这里有什么问题,我将非常感谢,我已经坚持了一段时间......

3 个答案:

答案 0 :(得分:1)

好的,最后我找到了解决这个问题的方法:

cc_services = db.Table('cc_services',
    db.Column('service_name', db.String(120),
    db.ForeignKey('service.name')),
    db.Column('cc_hostname', db.String(120)),
    db.Column('cc_module', db.Integer),
    db.Column('cc_relay', db.Integer),
    ForeignKeyConstraint(
        ('cc_hostname', 'cc_module', 'cc_relay'),
        ('contact_closure.hostname', 'contact_closure.module', 'contact_closure.relay')
    )
)

如果模型有多个键,则必须在ForeignKeyConstraint语句的辅助表上声明它们。

答案 1 :(得分:0)

您需要定义' foreign_keys'参数如错误文本所示,如下:

services = db.relationship('Service', secondary=cc_services, backref=db.backref('contact_closures', lazy='dynamic'), foreign_keys=[column_name])

答案 2 :(得分:0)

如果您使用关联表或完全声明的表元数据,则可以按照建议的 here 在两列中使用 primary_key=True

关联表示例:

employee_role = db.Table(
    "employee_role",
    db.Column("role_id", db.Integer, db.ForeignKey("role.id"), primary_key=True),
    db.Column("employee_id", db.Integer, db.ForeignKey("agent.id"), primary_key=True),
)

元数据示例:

# this is using SQLAlchemy
class EmployeeRole(Base):
    __tablename__ = "employee_role"

    role_id = Column(Integer, primary_key=True)
    employee_id = Column(Integer, primary_key=True)

# this is using Flask-SQLAlchemy with factory pattern, db gives you access to all SQLAlchemy stuff
class EmployeeRole(db.Model):
    __tablename__ = "employee_role"

    role_id = db.Column(db.Integer, primary_key=True)
    employee_id = db.Column(db.Integer, primary_key=True)

Alembic 迁移:

op.create_table(
        'employee_role',
        sa.Column('role_id', sa.Integer(), nullable=False),
        sa.Column('employee_id', sa.Integer(), nullable=False),
        sa.PrimaryKeyConstraint('role_id', 'employee_id')
    )

SQL:

CREATE TABLE agent_role (
    role_id INTEGER NOT NULL, 
    employee_id INTEGER NOT NULL, 
    PRIMARY KEY (role_id, employee_id)
);

就关系而言,在一侧声明它(这应该给你 role.employeesemployee.roles,它应该返回一个 list):

# this is using Flask-SQLAlchemy with factory pattern, db gives you access to all SQLAlchemy stuff
class Employee(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    roles = db.relationship("Role", secondary=employee_role, backref="employee")

您的角色类可以是:

# this is using Flask-SQLAlchemy with factory pattern, db gives you access to all SQLAlchemy stuff
class Role(db.Model):
    __tablename__ = "role"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(25), nullable=False, unique=True)