Flask Sqlalchemy模型通过调用model返回不同的结果。__dict __(有时显示backrefs,有时不显示)

时间:2019-02-06 10:40:44

标签: python json flask sqlalchemy flask-sqlalchemy

我想从查询中获取结果并将其与jsonify发送给客户端,我创建了一个获取模型实例的函数,使用其' dict '属性删除未使用的值,例如'_sa_instance_state',然后将新字典作为jsonified对象返回给客户端。 这是我的代码:

def display(Object):
        data= Object.__dict__.copy()
        del data['_sa_instance_state']
        return data`

user = User.query.first()

@app.route('/')
def main():
       return jsonify(display(user))

有时我会收到此错误

  

TypeError:Admin类型的对象不可JSON序列化

管理员在哪里 另一个model在用户模型中具有反向引用。 奇怪的事情在这里发生,因为有时不做任何更改我不会得到错误。 当我尝试找出Jupyter笔记本中发生的情况时,我发现__dict__jupyter notebook中没有显示反向引用,但是有时当我从flask应用程序调用它时,它会显示反向引用。

1 个答案:

答案 0 :(得分:2)

请勿在SQLAlchemy模型上使用__dict__。是的,可能存在反向引用 depending on how you configured reference loading,其他SQLAlchemy特定信息也可能存在。

您可以使用runtime introspection来获取InstanceState instance。然后,您可以决定要在JSON中反映什么以及应该忽略什么:

from operator import attrgetter
from sqlalchemy import inspect

def display(object, only_loaded=False):
    insp = inspect(object)
    assert insp.is_instance
    value = attrgetter('loaded_value' if only_loaded else 'value')
    return {
        name: value(attr) for name, attr in insp.attrs.items()
        if name not in insp.mapper.relationships
    }

以上内容使用Mapper.relationships namespace来跳过任何相关对象。处理相关对象的另一种方法是将它们也递归地转换成字典:

def display(object, include_related=True, only_loaded=False, seen=None):
    insp = inspect(object)
    assert insp.is_instance
    value = attrgetter('loaded_value' if only_loaded else 'value')
    result = {
        name: value(attr) for name, attr in insp.attrs.items()
        if name not in insp.mapper.relationships
    }
    if include_related:
        if seen is None:
            seen = set()
        seen.add(id(object))
        for name, rel in insp.mapper.relationships.items():
            related = value(insp.attrs[name])
            if related is not None:
                if rel.uselist:
                    displays = result[name] = []
                    for r in related:
                        if id(r) in seen:
                            continue
                        displays.append(display(r, True, only_loaded, seen))
                else:
                    if id(related) in seen:
                        continue
                    result[name] = display(related, True, only_loaded)
    return result

但是要考虑到,使用双向关系对象,您可能很快就会反映出比您预期的要大得多的数据库块。

就个人而言,我发现将as_dict()方法添加到产生字典以反映或使用provides a reflection API的Flask附加组件的模型中比较容易。