从flask-sqlalchemy转到sqlalchemy,
少了一个特性,那就是每次请求后都自动commit(),现在需要再每次session.add后都自己session.commit()
这次遇到一个坑,想通过user.dict把user转为json,然而打印居然有时为空
user = db.session.query(User).filter_by(mobile=mobile).first()
if user and user.verify_password(password=password):
login = db.get_or_insert(Login, user_id=user.id)
login.ip = request.headers.get('X-Forwarded-For') or request.remote_addr
db.session.add(login)
print(user.__dict__)
db.session.commit()
print(user.__dict__)
a=user.id
print(user.__dict__)
第一次print输出
{ 'avatar': None,'role': 4, 'intro': None, 'boss_id': 1, 'mobile': '13000000001', 'id': 1, 'nick': '王一', 'words': None, '_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x7fe382f470b8>}
db.session.commit()后的print就输出
{'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x7fe382f470b8>}
其他的数据都不见了,被commit清空了?
最后跟着
a=user.id后print输出,
{ 'avatar': None,'role': 4, 'intro': None, 'boss_id': 1, 'mobile': '13000000001', 'id': 1, 'nick': '王一', 'words': None, '_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x7fe382f470b8>}
数据又出来了,判断:
_sa_instance_state有值,映射关系应该还是在都,只是dict被清空了,当调用Model的成员的时候,则自动把实例映射读取回来,这样就可以通过user.dict看到了user成员了。
打印出
_sa_instance_state:{'identity_token': None, '_strong_obj': None, '_instance_dict': <weakref at 0x1093265e8; to 'WeakInstanceDict' at 0x109328748>, 'class_': <class 'app.models.User'>, 'session_id': 1, 'runid': 1, 'committed_state': {}, 'expired_attributes': { 'words', 'code', 'boss_id', 'mobile', 'time', 'senior_id', 'leader_id', 'status', 'intro', 'nick', 'role', 'id', 'avatar'}, 'manager': <ClassManager of <class 'app.models.User'> at 108ef0f98>, 'obj': <weakref at 0x109382638; to 'User' at 0x10938fac8>, 'key': (<class 'app.models.User'>, (1,), None), 'load_path': CachingEntityRegistry((<Mapper at 0x108f01780; User>,)), 'load_options': set(), 'expired': True}
发现里面写着expired_attributes,和'expired': True,可见commit()后,之前的user对象就作为过期的处理,成员全部清空。
如何稳定遍历Model呢?
解决方法:
def to_dict(obj):
dic = {}
dic_columns = obj.__table__.columns
# 保证都是字符串和数字
types = [str,int,float,bool]
#注意,obj.__dict__会在commit后被作为过期对象清空dict,所以保险的办法还是用columns
for k,tmp in dic_columns.items():
# k=nick,tmp=user.nick
v = getattr(obj,k,None)
dic[k] = str(v) if v and type(v) not in types else v
return dic
print(to_dict(user))
网友评论