use*_*527 8 python sqlalchemy commit
我正在开发一款多人游戏.当我使用库存中的对象时,它应该使用对象属性的值更新用户生物的统计数据.
这是我的代码:
try:
obj = self._get_obj_by_id(self.query['ObjectID']).first()
# Get user's current creature
cur_creature = self.user.get_current_creature()
# Applying object attributes to user attributes
for attribute in obj.attributes:
cur_creature.__dict__[str(attribute.Name)] += attribute.Value
dbObjs.session.commit()
except (KeyError, AttributeError) as err:
self.query_failed(err)
Run Code Online (Sandbox Code Playgroud)
现在,由于某种原因,这并没有正确提交,所以我尝试了:
cur_creature.Health = 100
logging.warning(cur_creature.Health)
dbObjs.session.commit()
Run Code Online (Sandbox Code Playgroud)
哪个有效,但不是很方便(因为我需要一个大的if语句来更新该生物的不同统计数据)
所以我尝试过:
cur_creature.__dict__['Health'] = 100
logging.warning(cur_creature.Health)
dbObjs.session.commit()
Run Code Online (Sandbox Code Playgroud)
我进入100日志,但没有变化,所以我试过:
cur_creature.__dict__['Health'] = 100
cur_creature.Health = cur_creature.__dict__['Health']
logging.warning(cur_creature.Health)
dbObjs.session.commit()
Run Code Online (Sandbox Code Playgroud)
日志中仍为'100',但没有变化,所以我试过:
cur_creature.__dict__['Health'] = 100
cur_creature.Health = 100
logging.warning(cur_creature.Health)
dbObjs.session.commit()
Run Code Online (Sandbox Code Playgroud)
其中仍然在日志中写入100,但不提交对数据库的更改.现在,这很奇怪,因为它只有不同的工作版本,因为它有这条线在顶部:
cur_creature.__dict__['Health'] = 100
Run Code Online (Sandbox Code Playgroud)
简介:如果我直接修改属性,则提交工作正常.相反,如果我通过类'字典修改属性,那么,无论我之后如何修改它,它都不会提交对数据库的更改.
有任何想法吗?
提前致谢
更新1:
此外,这会更新db中的Health,但不会更新Hunger:
cur_creature.__dict__['Hunger'] = 0
cur_creature.Health = 100
cur_creature.Hunger = 0
logging.warning(cur_creature.Health)
dbObjs.session.commit()
Run Code Online (Sandbox Code Playgroud)
因此,一般来说,访问字典对于属性来说不是问题,但是通过字典修改属性可以防止提交对该属性的更改.
更新2:
作为临时修复,我已经覆盖__set_item__(self)了类中的函数Creatures:
def __setitem__(self, key, value):
if key == "Health":
self.Health = value
elif key == "Hunger":
self.Hunger = value
Run Code Online (Sandbox Code Playgroud)
因此'use object'的新代码是:
try:
obj = self._get_obj_by_id(self.query['ObjectID']).first()
# Get user's current creature
cur_creature = self.user.get_current_creature()
# Applying object attributes to user attributes
for attribute in obj.attributes:
cur_creature[str(attribute.Name)] += attribute.Value
dbObjs.session.commit()
except (KeyError, AttributeError) as err:
self.query_failed(err)
Run Code Online (Sandbox Code Playgroud)
更新3:
通过查看答案中的建议,我找到了解决方案:
在 Creatures
def __setitem__(self, key, value):
if key in self.__dict__:
setattr(self, key, value)
else:
raise KeyError(key)
Run Code Online (Sandbox Code Playgroud)
在另一种方法中
# Applying object attributes to user attributes
for attribute in obj.attributes:
cur_creature[str(attribute.Name)] += attribute.Value
Run Code Online (Sandbox Code Playgroud)
ice*_*ime 11
问题不在于SQLAlchemy,而是由于Python的描述符机制.每个Column属性都是一个描述符:这就是SQLAlchemy"挂钩"属性检索和修改以产生数据库请求的方式.
让我们尝试一个更简单的例子:
class Desc(object):
def __get__(self, obj, type=None):
print '__get__'
def __set__(self, obj, value):
print '__set__'
class A(object):
desc = Desc()
a = A()
a.desc # prints '__get__'
a.desc = 2 # prints '__set__'
Run Code Online (Sandbox Code Playgroud)
但是,如果您浏览a 实例字典并为其设置另一个值'desc',则绕过描述符协议(请参阅调用描述符):
a.__dict__['desc'] = 0 # Does not print anything !
Run Code Online (Sandbox Code Playgroud)
在这里,我们刚刚创建了一个名为0的新实例属性'desc'.该Desc.__set__方法从未被调用过,在您的情况下,SQLAlchemy没有机会"捕获"赋值.
解决方案是使用setattr,这完全等同于编写a.desc:
setattr(a, 'desc', 1) # Prints '__set__'
Run Code Online (Sandbox Code Playgroud)