使用派生字段更新多对多关联 table

Update many to many association table with derived field

我正在使用 Flask、Flask-SQLalchemy 和 Flask-Restful 编写 RESTful API。我有联系人和类别的模型,以及一个帮助程序 table 用于映射它们之间的多对多关系。

contactgrouping = db.Table('CONTACT_GROUPING',
    db.Column('catid', db.Integer, db.ForeignKey('CATEGORY.catid')),
    db.Column('contactid', db.Integer, db.ForeignKey('CONTACT.contactid')),
    db.Column('clientid', db.Integer, db.ForeignKey('CLIENT.clientid')),
)

class Contact(db.Model):

    __tablename__ = 'CONTACT'
    contactid = db.Column(db.Integer, primary_key=True)
    clientid = db.Column(db.Integer, db.ForeignKey('CLIENT.clientid'))
    firstname = db.Column(db.String(50))
    lastname = db.Column(db.String(50))
    categories = db.relationship('Category',secondary = contactgrouping, backref='contact', lazy='dynamic')

class Category(db.Model):

    __tablename__ = 'CATEGORY'
    catid = db.Column(db.Integer, primary_key=True)
    clientid = db.Column(db.Integer, db.ForeignKey('CLIENT.clientid'))
    catname = db.Column(db.String(50))

我正在使用 ORM 更新给定联系人的类别,效果很好。复杂的是映射 table 有一个非规范化字段 clientid,它与联系人 table 中的 clientid 相同。当 ORM 更新联系人的类别分配时,我需要填充此字段,但它仅插入 contactidcatid 列。

示例:

            category = Category.query.get(catid).first()
            if (category is not None):
                contact.categories.append(category)

这会生成 SQL:

INSERT INTO `CONTACT_GROUPING` (catid, contactid) VALUES (%s, %s)

当我真正需要它时:

INSERT INTO `CONTACT_GROUPING` (catid, contactid, clientid) VALUES (%s, %s, %s)

如何定义联系人和类别之间的关系,以便该派生字段也通过 ORM 填充?

我从 https://twitter.com/140am 那里得到了一些帮助。我需要将 contactgrouping 表示为模型而不是 Table,以便我可以直接使用关系和访问字段。

class Category(db.Model):

    resource_fields = {
        'id': fields.Integer(attribute='catid'),
        'name': fields.String(attribute='catname')
    }

    __tablename__ = 'CATEGORY'
    catid = db.Column(db.Integer, primary_key=True)
    clientid = db.Column(db.Integer, db.ForeignKey('CLIENT.clientid'))
    catname = db.Column(db.String(50))

    def __repr__(self):
        return '<Category %r>' % (self.catname)

class ContactGrouping(db.Model):

    resource_fields = {
        'id': fields.Integer(attribute='catid'),
        'name': fields.String(attribute='category.catname'),
    }

    __tablename__ = 'CONTACT_GROUPING'
    __table_args__ = (
        PrimaryKeyConstraint('catid', 'contactid', 'clientid'),
    )

    catid = db.Column(db.Integer, db.ForeignKey('CATEGORY.catid'))
    contactid = db.Column(db.Integer, db.ForeignKey('CONTACT.contactid'))
    clientid= db.Column(db.Integer, db.ForeignKey('CONTACT.clientid'))
    category = db.relationship('Category')

    def __repr__(self):
        return '<ContactGrouping %r %r>' % (self.catid, self.contactid)

class Contact(db.Model):

    resource_fields = {
        'id': fields.Integer(attribute='contactid'),
        'firstname': fields.String,
        'lastname': fields.String,
        'categories': fields.List(fields.Nested(ContactGrouping.resource_fields))
    }

    __tablename__ = 'CONTACT'
    contactid = db.Column(db.Integer, primary_key=True)
    clientid = db.Column(db.Integer, db.ForeignKey('CLIENT.clientid'))
    firstname = db.Column(db.String(50))
    lastname = db.Column(db.String(50))
    categories = db.relationship('ContactGrouping', backref='contact', lazy='dynamic', foreign_keys='ContactGrouping.contactid')

    def __repr__(self):
        return '<Contact %r %r>' % (self.firstname, self.lastname)

并在视图中使用它:

        category = Category.query.get(catid).first()
        contactgrouping = ContactGrouping(contactid=id, catid=category.catid, clientid = contact.clientid)
        if (contactgrouping is not None):
            contact.categories.append(contactgrouping)