编辑 SQLAlchemy 条目并提交更新会更改模型方法的输出
Editing a SQLAlchemy entry & committing the update changes the output of Model method
在使用 SQLAlchemy 的 Flask 应用程序中,我声明了一个 Deliverymen
模型,其中包含一些方法、属性和 class 方法。其中之一,get_own_data(self)
构建并 returns 一个只包含最终用户需要的相关信息的字典(完整的模型声明在下面):
def get_own_data(self):
own_data = {
key: value
for (key, value) in vars(self).items()
# Exclude the following keys
if key != "_sa_instance_state" and key != "moto_placa"
}
# Add this key, which isn't found in 'vars(self)' as it is a class property
own_data["moto_placa_upper"] = self.moto_placa
return own_data
由于表单处理和 属性 setter 需要用户输入并转动 placa(或牌照),因此必须像这样定义密钥对) 转换为大写。 属性 及其 setter 也可在下方找到。
当我尝试编辑现有条目然后提交更改时,get_own_data
方法 仅 returns 最后定义的密钥对,如下:
Python 3.10.4 (main, Mar 23 2022, 23:05:40) [GCC 11.2.0] on linux
App: app [development]
Instance: /home/daniel/Documents/work/breakfast4you/reportes/backend/instance
>>> d = Deliveryman.query.first()
>>> d.get_own_data()
{'user_id': 9, 'nombre': 'James Bond', 'telefono': '1234567890', 'status': 1, 'arp': 'Protección', 'tipo_cuenta': 'Ahorros', 'direccion': 'Dirección de prueba', 'id': 1, 'gov_id': '1234789845', 'eps': 'Sanitas', 'moto_marca': 'AKT', 'nombre_banco': 'Davivienda', 'num_cuenta': '1234567890', 'moto_placa_upper': 'BND 007'}
>>> d.nombre = "Carlos"
>>> db.session.commit()
>>> d.get_own_data()
{'moto_placa_upper': 'BND 007'}
令人困惑的是,如果在提交更改后我访问了任何对象属性,然后 运行 d.get_own_data()
... 它再次起作用!
>>> d.nombre
'Carlos'
>>> d.get_own_data()
{'nombre': 'Carlos', 'tipo_cuenta': 'Ahorros', 'status': 1, 'user_id': 9, 'arp': 'Protección', 'telefono': '1234567890', 'direccion': 'Dirección de prueba', 'num_cuenta': '1234567890', 'eps': 'Sanitas', 'nombre_banco': 'Davivienda', 'id': 1, 'gov_id': '1234789845', 'moto_marca': 'AKT', 'moto_placa_upper': 'BND 007'}
这是模型声明:
class Deliveryman(db.Model):
__tablename__ = "delivery_men"
id = db.Column(db.Integer, primary_key=True, unique=True)
user_id = db.Column(db.ForeignKey("users.id"), index=True, unique=True)
nombre = db.Column(db.String(40), nullable=False, index=True)
direccion = db.Column(db.String(120), nullable=False)
telefono = db.Column(db.String(15), nullable=False)
gov_id = db.Column(db.String(20), nullable=False, unique=True)
status = db.Column(db.Integer)
eps = db.Column(db.String(150))
arp = db.Column(db.String(150))
moto_marca = db.Column(db.String(20))
moto_placa = db.Column(db.String(7))
nombre_banco = db.Column(db.String(20))
tipo_cuenta = db.Column(db.String(20))
num_cuenta = db.Column(db.String(30))
@property
def moto_placa_upper(self):
return self.moto_placa
@moto_placa_upper.setter
def moto_placa_upper(self, placa):
if placa is None:
pass
else:
self.moto_placa = placa.upper()
# Another method that is irrelevant to this question
def get_own_data(self):
own_data = {
key: value
for (key, value) in vars(self).items()
if key != "_sa_instance_state" and key != "moto_placa"
}
own_data["moto_placa_upper"] = self.moto_placa
return own_data
# Class methods irrelevant to this question
什么可能导致此问题?我不是 OOP 专家,我感觉我的方法和 属性 声明中存在错误,但我无法指出。
这里的问题是提交时会话中的 SQLAlchemy expires 对象。 Expiry 从持久化对象的 __dict__
中删除所有持久化属性,因此在调用 get_own_data
时没有什么可迭代的。
有几种解决方法:
- 在调用
get_own_data
之前调用db.session.refresh(obj)
刷新对象;这将触发 SELECT
来获取数据。
- 在创建
SQLAlchemy
(db
) 对象时通过传递 session_options={'expire_on_commit': False}
禁用提交时过期。这是一个全局设置,您冒着包含陈旧数据的实例的风险,因为在这种情况下 SELECT
是 not 发出的。
- 不是遍历
vars
,而是遍历列名并使用 getattr
获取值;与刷新一样,这将触发 SELECT
。
from sqlalchemy import inspect
...
def get_own_data(self):
insp = inspect(self)
own_data = {
key: getattr(self, key)
for key in insp.mapper.columns.keys()
# Exclude the following keys
if key != "moto_placa"
}
# Add this key, which isn't found in 'vars(self)' as it is a class property
own_data["moto_placa_upper"] = self.moto_placa
return own_data
在使用 SQLAlchemy 的 Flask 应用程序中,我声明了一个 Deliverymen
模型,其中包含一些方法、属性和 class 方法。其中之一,get_own_data(self)
构建并 returns 一个只包含最终用户需要的相关信息的字典(完整的模型声明在下面):
def get_own_data(self):
own_data = {
key: value
for (key, value) in vars(self).items()
# Exclude the following keys
if key != "_sa_instance_state" and key != "moto_placa"
}
# Add this key, which isn't found in 'vars(self)' as it is a class property
own_data["moto_placa_upper"] = self.moto_placa
return own_data
由于表单处理和 属性 setter 需要用户输入并转动 placa(或牌照),因此必须像这样定义密钥对) 转换为大写。 属性 及其 setter 也可在下方找到。
当我尝试编辑现有条目然后提交更改时,get_own_data
方法 仅 returns 最后定义的密钥对,如下:
Python 3.10.4 (main, Mar 23 2022, 23:05:40) [GCC 11.2.0] on linux
App: app [development]
Instance: /home/daniel/Documents/work/breakfast4you/reportes/backend/instance
>>> d = Deliveryman.query.first()
>>> d.get_own_data()
{'user_id': 9, 'nombre': 'James Bond', 'telefono': '1234567890', 'status': 1, 'arp': 'Protección', 'tipo_cuenta': 'Ahorros', 'direccion': 'Dirección de prueba', 'id': 1, 'gov_id': '1234789845', 'eps': 'Sanitas', 'moto_marca': 'AKT', 'nombre_banco': 'Davivienda', 'num_cuenta': '1234567890', 'moto_placa_upper': 'BND 007'}
>>> d.nombre = "Carlos"
>>> db.session.commit()
>>> d.get_own_data()
{'moto_placa_upper': 'BND 007'}
令人困惑的是,如果在提交更改后我访问了任何对象属性,然后 运行 d.get_own_data()
... 它再次起作用!
>>> d.nombre
'Carlos'
>>> d.get_own_data()
{'nombre': 'Carlos', 'tipo_cuenta': 'Ahorros', 'status': 1, 'user_id': 9, 'arp': 'Protección', 'telefono': '1234567890', 'direccion': 'Dirección de prueba', 'num_cuenta': '1234567890', 'eps': 'Sanitas', 'nombre_banco': 'Davivienda', 'id': 1, 'gov_id': '1234789845', 'moto_marca': 'AKT', 'moto_placa_upper': 'BND 007'}
这是模型声明:
class Deliveryman(db.Model):
__tablename__ = "delivery_men"
id = db.Column(db.Integer, primary_key=True, unique=True)
user_id = db.Column(db.ForeignKey("users.id"), index=True, unique=True)
nombre = db.Column(db.String(40), nullable=False, index=True)
direccion = db.Column(db.String(120), nullable=False)
telefono = db.Column(db.String(15), nullable=False)
gov_id = db.Column(db.String(20), nullable=False, unique=True)
status = db.Column(db.Integer)
eps = db.Column(db.String(150))
arp = db.Column(db.String(150))
moto_marca = db.Column(db.String(20))
moto_placa = db.Column(db.String(7))
nombre_banco = db.Column(db.String(20))
tipo_cuenta = db.Column(db.String(20))
num_cuenta = db.Column(db.String(30))
@property
def moto_placa_upper(self):
return self.moto_placa
@moto_placa_upper.setter
def moto_placa_upper(self, placa):
if placa is None:
pass
else:
self.moto_placa = placa.upper()
# Another method that is irrelevant to this question
def get_own_data(self):
own_data = {
key: value
for (key, value) in vars(self).items()
if key != "_sa_instance_state" and key != "moto_placa"
}
own_data["moto_placa_upper"] = self.moto_placa
return own_data
# Class methods irrelevant to this question
什么可能导致此问题?我不是 OOP 专家,我感觉我的方法和 属性 声明中存在错误,但我无法指出。
这里的问题是提交时会话中的 SQLAlchemy expires 对象。 Expiry 从持久化对象的 __dict__
中删除所有持久化属性,因此在调用 get_own_data
时没有什么可迭代的。
有几种解决方法:
- 在调用
get_own_data
之前调用db.session.refresh(obj)
刷新对象;这将触发SELECT
来获取数据。 - 在创建
SQLAlchemy
(db
) 对象时通过传递session_options={'expire_on_commit': False}
禁用提交时过期。这是一个全局设置,您冒着包含陈旧数据的实例的风险,因为在这种情况下SELECT
是 not 发出的。 - 不是遍历
vars
,而是遍历列名并使用getattr
获取值;与刷新一样,这将触发SELECT
。from sqlalchemy import inspect ... def get_own_data(self): insp = inspect(self) own_data = { key: getattr(self, key) for key in insp.mapper.columns.keys() # Exclude the following keys if key != "moto_placa" } # Add this key, which isn't found in 'vars(self)' as it is a class property own_data["moto_placa_upper"] = self.moto_placa return own_data