【发布时间】:2020-05-25 07:57:38
【问题描述】:
我正在使用带有 SQLAlchemy 的 Flask 框架创建一个 Python 应用程序,现在在创建新模型对象时遇到一个奇怪的行为。
假设我有一个模型 Offer,其中包含一些字段、一个私有属性 __validation_errors 和一个公共方法 validate:
from app import db
class Offer(db.Model):
currency = db.Column(db.String(255))
price = db.Column(db.Numeric(20, 5))
__validation_errors = []
def validate(self, errors: List[Exception]) -> bool:
self.validate_not_empty()
self.validate_price()
for err in self.__validation_errors:
errors.append(err)
if len(self.__validation_errors) > 0:
return False
return True
对象本身是通过调用在服务类中创建的
offer = Offer(currency, price)
并提供在路由器中通过 POST 请求接收到的数据。 如果验证失败,则会向用户返回一条错误消息,并且该对象不会写入 DB。
从这里开始奇怪的部分。如果接收到包含无效数据的请求并发送另一个包含正确数据的请求,则 __validation_errors 列表中的值不会在 offer 对象中消失,就像该对象被重用且未重置一样。如果发出另一个无效请求,则错误只会附加到列表中已经存在的错误。当然,可以通过每次调用validate()方法时设置__validation_errors = []来修复,但我想了解这里发生了什么。我错过了一些 SQLAlchemy 的特定功能吗? app.db 对象和 Session 都是在 app 上创建的,并且一直存在。
【问题讨论】:
-
我不完全确定这是否是你的问题,但因为
__validation_errors是类声明的一部分,并且它没有被替换(只是appended to),@987654329 @ 将与Offer.__validation_errors相同(即它在类的所有实例之间共享)。您可能希望在__init__方法中创建它,例如:def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs); self.__validation_errors = [] -
@ChristianReall-Fluharty 感谢您的回复。我对 Python 很陌生,可能对类声明还不够熟悉。如果确实如此,那么如果没有明确设置类中声明的属性是共享的,那么它应该是它......我通过在调用验证方法之前将其设置为 [] 来解决它。在
__init__中将其设置为 [] 可能也可以。 -
是的,所以在
class ...:的主体中声明/创建的任何内容都是类本身的一部分,就像 C / Java 中的静态变量一样。而对于 C / Java,您要声明每个实例将具有的属性(因为编译器需要知道每个类在内存中的大小)。当您考虑到函数是 python 中的对象这一事实时,这是有道理的,因此通过将它们放在类声明中,它们是所有实例之间共享的方法。 -
而且您并没有明确地设置它们,而是您正在用对实例属性的引用替换对类属性的引用(您应该查找 python pass-by -value vs pass-by-reference 了解为什么重置 __validation_errors 修复它[使它成为实例属性而不是类属性],如果您还不熟悉它)
-
@ChristianReall-Fluharty,谢谢。最后两件事是已知的,但不知道如何共享实例之间共享的方法和属性。如果您将其添加为答案,我会接受。
标签: python flask sqlalchemy