我知道我可以像这样简单地更新多对多关系:
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更新它们,假设我必须创建一个仅接受person
和id
作为地址的常规函数并对其进行更新。
我想要的是这样的:
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
答案 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()
我不确定这种方法的警告,但对我有用。欢迎任何改进和建议。