首页 > 编程问答 >sqlalchemy - 关系上的“验证”不会在分配事件上发出

sqlalchemy - 关系上的“验证”不会在分配事件上发出

时间:2024-07-29 12:32:50浏览次数:15  
标签:python python-3.x sqlalchemy

考虑以下使用 sqlalchemy

from sqlalchemy.orm import validates

class DeviceTestResult:
    __tablename__ = "device_test"

    passed: bool = mapped_column(default=False, init=False)
    failure_modes: Mapped[list['FailureMode']] = relationship(default_factory=list, back_populates='test')

    @validates('failure_modes')
    def validate_failure_modes(self, key, failure_mode):
        """
        Validator for failure modes. When attribute is changed, updates passed to be false if there are any fails.
        """
        currently_passes = all([fm.passed for fm in self.failure_modes])
        self.passed = all([fm for fm in [currently_passes, failure_mode.passed]])
        return failure_mode


class FailureMode:
    __tablename__ = "failure_mode"
    
    passed: bool = mapped_column()
    test: Mapped['DeviceTestResult'] = relationship(back_populates='failure_modes', default=None)
    completed_at: datetime = mapped_column(insert_default=datetime.now(), default=datetime.now())

    @validates('passed')
    def validate_test(self, key, passed):
        """
        validator for passed. Updates associated test object status
        """
        if self.test:
            currently_passes = all([fm.passed for fm in self.test.failure_modes])
            self.test._passed = all([fm for fm in [currently_passes, passed]])
        return passed

# Case 1 - append, emits validate_failure_modes
device_test = DeviceTest()
failure_mode = FailureMode()
device.failure_modes.append(failure_mode)

# Case 2 - assignment, does not emit validate_failure_modes
device.failure_modes = [failure_mode]

validate_failure_modes 在情况1中发出,但在情况2中不发出。

如何在情况2中获得验证?如果这是不可能的,我如何限制用户使用赋值来设置属性,以便他们只能 通过附加进行修改? 我已经尝试过使用

描述符和混合,但还没有没让它发挥作用。 sqlalchemy descriptors & hybrids but haven't gotten it to work.


你观察到的行为是因为 SQLAlchemy 处理列表类型关系上的赋值和附加操作的方式不同。当使用 append 时,SQLAlchemy 会检测到列表的变化并触发验证器。然而,当进行赋值时,它会将此解释为对整个列表的替换,因此不会为单个项目触发验证器。

以下是一些关于如何在这个场景中实现验证的方法:

1. 在 DeviceTestResult 上使用 event.listen_for

你可以使用 event.listen_for DeviceTestResult failure_modes 属性发生变化时触发一个函数。这将允许你在列表被修改时执行验证,而不管它是如何修改的。

from sqlalchemy import event
from sqlalchemy.orm import validates

class DeviceTestResult:
    # ... other code ...

    @validates('failure_modes')
    def validate_failure_modes(self, key, failure_mode):
        # ... your validation logic ...

@event.listen_for(DeviceTestResult.failure_modes, 'set')
def failure_modes_changed(target, value, oldvalue, initiator):
    # This function will be called whenever the `failure_modes` 
    # attribute of a `DeviceTestResult` instance is modified.
    # `target` is the `DeviceTestResult` instance
    # `value` is the new list of `FailureMode` objects
    # `oldvalue` is the old list of `FailureMode` objects

    # Perform your validation logic here, similar to what you have in 
    # the `validate_failure_modes` function. 
    currently_passes = all([fm.passed for fm in value])
    target.passed = currently_passes 

2. 使用集合而不是列表:

另一种方法是将 failure_modes 关系表示为一个集合而不是一个列表。集合在 SQLAlchemy 中具有可变性跟踪功能,并且对集合的任何修改都会触发验证器。

from sqlalchemy.orm import relationship

class DeviceTestResult:
    # ... other code ...

    failure_modes: Mapped[set['FailureMode']] = relationship(
        default_factory=set, back_populates='test'
    )

    @validates('failure_modes')
    def validate_failure_modes(self, key, failure_mode):
        # ... your validation logic ...

3. 创建一个自定义集合类:

你可以创建一个自定义集合类,该类继承自 Python 的 list 并覆盖 __setitem__ __delitem__ 方法来触发验证逻辑。

class ValidatedList(list):
    def __init__(self, parent, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.parent = parent

    def __setitem__(self, key, value):
        super().__setitem__(key, value)
        self.parent.validate_failure_modes('failure_modes', value)

    def __delitem__(self, key):
        super().__delitem__(key)
        # Trigger validation after deletion if needed

class DeviceTestResult:
    # ... other code ...

    failure_modes: Mapped[list['FailureMode']] = relationship(
        default_factory=lambda: ValidatedList(parent=self), 
        back_populates='test'
    )

    @validates('failure_modes')
    def validate_failure_modes(self, key, failure_mode):
        # ... your validation logic ...

这些方法中的每一种都有其自身的优缺点,你应该选择最适合你的特定用例的方法。

标签:python,python-3.x,sqlalchemy
From: 78796179

相关文章

  • python 将数字前面的字符替换为数字后面的新字符
    我有一些字符串看起来像:*.rem.1.gz和*.rem.2.gz我想将其替换为*.1.trim.gz和*.2.trim.gz1号文件和2号文件相互配对,我想创建一个单独的字符串来同时包含这两个文件。importosallfiles=os.listdirpair=[x.replace("rem.(\d+)","(\d+).trim")forxinall......
  • 使用python打开UNC文件
    如何使用python通过路径打开网络计算机上的文件?我当前正在使用os.startfile但随后出现错误winerror2:无法打开文件。文件路径是正确的,我可以通过win+R打开该文件。感谢您提供的任何帮助。importwin32wnetimportosdefopen_unc_path(unc_path,usern......
  • 使用“marshmallow-sqlalchemy”时发生错误,异常:反序列化需要会话
    使用marshmallow-sqlalchemy反序列化对象,但出现错误。我已经通过了session对象,也就是数据库DB,但是还是没有效果,这个问题已经2天了,依然无法解决。my_db.pyfromsqlalchemyimportcreate_enginefromsqlalchemy.ext.declarativeimportdeclarative_basefromsqlalchemy.o......
  • Python环境:深入理解与构建实践
    Python环境:深入理解与构建实践在当今的软件开发领域中,Python以其简洁的语法、丰富的库支持和广泛的应用场景,成为了众多开发者、数据科学家、机器学习工程师及自动化测试人员的首选语言。然而,要高效地使用Python进行项目开发,深入理解并合理构建Python环境是至关重要的。本文......
  • 界面自动化测试录制工具,让python selenium自动化测试脚本开发更加方便
    自动化测试中,QTP和seleniumIDE都支持浏览器录制与回放功能,简单的来说就像一个记录操作步骤的机器人,可以按照记录的步骤重新执行一遍,这就是脚本录制。个人觉得传统录制工具有些弊端,加上要定制支持我自己的自动化框架(python单机版自动化测试框架源代码),所以自己用javascript写了一个......
  • Python 面试常问问题及应用场景解析
    引言随着Python在数据科学、Web开发、自动化脚本、机器学习等领域中的广泛应用,越来越多的公司开始寻找具备Python技能的人才。因此,在Python面试中,面试官通常会通过一系列问题来评估应聘者的编程基础、问题解决能力和对Python特性的理解程度。本文将涵盖Python面试中最常见的......
  • python 虚拟环境
    python虚拟环境Python的venv模块允许你创建轻量级的“虚拟环境”,这些环境是独立的Python安装,用于项目的依赖隔离。每个虚拟环境都有自己的Python解释器、库和脚本,与系统中安装的Python相互隔离。这意呀着,你可以在一个项目中安装特定版本的库,而不会影响到系统上其他Pyt......
  • 使用 Azure Devops API (Python) 撰写 PR 评论
    在任何地方都找不到直接的方法。如何通过Python中的AzureDevopsAPI将注释添加到拉取请求?可以使用AzureDevOpsPythonAPI将注释添加到拉取请求。以下是执行此操作的方法:1.安装AzureDevOps库:pipinstallazure-devops2.导入必要的类并对的组......
  • Python\Python312\Lib\site-packages\torch\lib\fbgemm.dll
    在此处输入图像描述我正在尝试从HuggingFace导入GPT-2变压器模型,但当我尝试导入它时,遇到错误。即使当我尝试仅导入Torch时,我也会收到相同的错误。我已尝试重新安装Torch并完成了所有操作,包括更新VisualC++Redistributable软件包和更新我的驱动程序,但问题......
  • Python GEKKO 不更新参数
    我正在Python中使用GEKKO来估计弹跳球的轨迹。为此,我需要估计2个变量:e_1(恢复系数)和q_1(每次弹跳时的水平速度损失)。我已为其编写了以下代码,但参数似乎没有更新,尽管解算器已成功执行。参数的初始值与参数的最终优化值相同e_1=0.8和q_1=1代码:imp......