如何通过将ID与sqlalchemy一起使用来更新多对多关系?

时间:2019-02-13 13:15:30

标签: python sqlalchemy

我知道我可以像这样简单地更新多对多关系:

tags = db.Table('tags',
    db.Column('tag_id', db.Integer, db.ForeignKey('tag.id'), primary_key=True),
    db.Column('page_id', db.Integer, db.ForeignKey('page.id'), primary_key=True)
)

class Page(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    tags = db.relationship('Tag', secondary=tags, lazy='subquery',
        backref=db.backref('pages', lazy=True))

class Tag(db.Model):
    id = db.Column(db.Integer, primary_key=True)

tag1 = Tag()
tag2 = Tag()
page = Page( tags=[tag1])

以及以后进行更新:


page.append(tag2)

但是我只想通过标签ID更新它们,假设我必须创建一个仅接受personid作为地址的常规函数​​并对其进行更新。 我想要的是这样的:

page = Page(tags=[1,2]) # 1 and 2 are primary keys of (tag)s

或在函数中

def update_with_foreignkey(page, tags=[1,2]):
 # dosomething to update page without using Tag object
 return  updated page

1 个答案:

答案 0 :(得分:0)

使用邪恶的eval有点棘手,但是最后,我找到了一种使用外键更新许多关系的通用方法。我的目标是通过从PUT请求中获取数据来更新对象,并且在该请求中,我仅获取与其他数据之间的关系的外键。

分步解决方案:

1-找到对象中的关系,我使用__mapper__.relationships

2-找到代表关系的键。

for rel in Object.__mapper__.relationships:
        key = str(rel).rsplit('.',1)[-1]

在有疑问的情况下,它返回'tags'作为结果。

3-查找关系另一侧的模型(在本示例中为Tag)。 3-1查找表的名称。 3-2将表名转换为camleCase,因为sqlalchemy将下划线用于表名,将camelCase用于模型。 3-3使用eval获取模型。

 if key in data:
            table = eval(convert_to_CamelCase(rel.table.name))
            temp = table.query.filter(table.id.in_(data[key])).all() # this line convert ids to sqlacemy objects

在一起

def convert_to_CamelCase(word):
    return ''.join(x.capitalize() or '_' for x in word.split('_'))

def update_relationship_withForeingkey(Object, data):
    for rel in Object.__mapper__.relationships:
        key = str(rel).rsplit('.',1)[-1]

        if key in data:
            table = eval(convert_to_CamelCase(rel.table.name))
            temp = table.query.filter(table.id.in_(data[key])).all() # this line convert ids to sqlacemy objects
            data[key] = temp


    return data

data是我从请求中得到的,Object是我要更新的sqlalchemy模型。

运行这几行更新会给我结果:

item = Object.query.filter_by(id=data['id'])
data = update_relationship_withForeingkey(Object,data)
for i,j in data.items():
            setattr(item,i,j)
db.session.commit()

我不确定这种方法的警告,但对我有用。欢迎任何改进和建议。