SqlAlchemy 2.0 中文文档(八)(3)

简介: SqlAlchemy 2.0 中文文档(八)

SqlAlchemy 2.0 中文文档(八)(2)https://developer.aliyun.com/article/1559847


在核心级别使用自定义数据类型

通过使用应用于映射的 Table 元数据的自定义数据类型,可以以适合在 Python  中的表示方式与在数据库中的表示方式之间转换数据的方式来影响列的值的非 ORM  方法。这在某些编码/解码样式在数据进入数据库和返回时都发生的情况下更为常见;在核心文档中阅读更多关于此的内容,参见扩充现有类型。

使用描述符和混合类型

产生修改后的属性行为的更全面的方法是使用描述符。在 Python 中,通常使用 property() 函数来使用这些。描述符的标准 SQLAlchemy 技术是创建一个普通描述符,并从具有不同名称的映射属性读取/写入。下面我们使用 Python 2.6 风格的属性来说明这一点:

class EmailAddress(Base):
    __tablename__ = "email_address"
    id = mapped_column(Integer, primary_key=True)
    # name the attribute with an underscore,
    # different from the column name
    _email = mapped_column("email", String)
    # then create an ".email" attribute
    # to get/set "._email"
    @property
    def email(self):
        return self._email
    @email.setter
    def email(self, email):
        self._email = email

上述方法可行,但我们还可以添加更多内容。虽然我们的EmailAddress对象将值通过email描述符传递到_email映射属性中,但类级别的EmailAddress.email属性不具有通常可用于Select的表达语义。为了提供这些功能,我们使用 hybrid 扩展,如下所示:

from sqlalchemy.ext.hybrid import hybrid_property
class EmailAddress(Base):
    __tablename__ = "email_address"
    id = mapped_column(Integer, primary_key=True)
    _email = mapped_column("email", String)
    @hybrid_property
    def email(self):
        return self._email
    @email.setter
    def email(self, email):
        self._email = email

.email 属性除了在我们有EmailAddress实例时提供 getter/setter 行为外,在类级别使用时也提供了一个 SQL 表达式,即直接从EmailAddress类中:

from sqlalchemy.orm import Session
from sqlalchemy import select
session = Session()
address = session.scalars(
    select(EmailAddress).where(EmailAddress.email == "address@example.com")
).one()
SELECT  address.email  AS  address_email,  address.id  AS  address_id
FROM  address
WHERE  address.email  =  ?
('address@example.com',)
address.email = "otheraddress@example.com"
session.commit()
UPDATE  address  SET  email=?  WHERE  address.id  =  ?
('otheraddress@example.com',  1)
COMMIT 

hybrid_property还允许我们更改属性的行为,包括在实例级别与类/表达式级别访问属性时定义不同的行为,使用hybrid_property.expression()修饰符。例如,如果我们想要自动添加主机名,我们可能会定义两组字符串操作逻辑:

class EmailAddress(Base):
    __tablename__ = "email_address"
    id = mapped_column(Integer, primary_key=True)
    _email = mapped_column("email", String)
    @hybrid_property
    def email(self):
  """Return the value of _email up until the last twelve
 characters."""
        return self._email[:-12]
    @email.setter
    def email(self, email):
  """Set the value of _email, tacking on the twelve character
 value @example.com."""
        self._email = email + "@example.com"
    @email.expression
    def email(cls):
  """Produce a SQL expression that represents the value
 of the _email column, minus the last twelve characters."""
        return func.substr(cls._email, 0, func.length(cls._email) - 12)

以上,访问EmailAddress实例的email属性将返回_email属性的值,从值中删除或添加主机名@example.com。当我们针对email属性进行查询时,将呈现出一个产生相同效果的 SQL 函数:

address = session.scalars(
    select(EmailAddress).where(EmailAddress.email == "address")
).one()
SELECT  address.email  AS  address_email,  address.id  AS  address_id
FROM  address
WHERE  substr(address.email,  ?,  length(address.email)  -  ?)  =  ?
(0,  12,  'address') 

在混合属性中阅读更多内容。

同义词

同义词是一个映射级别的构造,允许类上的任何属性“镜像”另一个被映射的属性。

从最基本的意义上讲,同义词是一种简单的方式,通过额外的名称使某个属性可用:

from sqlalchemy.orm import synonym
class MyClass(Base):
    __tablename__ = "my_table"
    id = mapped_column(Integer, primary_key=True)
    job_status = mapped_column(String(50))
    status = synonym("job_status")

上述MyClass类有两个属性,.job_status.status,它们将作为一个属性行为,无论在表达式级别还是在实例级别:

>>> print(MyClass.job_status == "some_status")
my_table.job_status  =  :job_status_1
>>> print(MyClass.status == "some_status")
my_table.job_status  =  :job_status_1 

在实例级别上:

>>> m1 = MyClass(status="x")
>>> m1.status, m1.job_status
('x', 'x')
>>> m1.job_status = "y"
>>> m1.status, m1.job_status
('y', 'y')

synonym()可以用于任何一种映射属性,包括映射列和关系,以及同义词本身,这些属性都是MapperProperty的子类。

除了简单的镜像之外,synonym()还可以引用用户定义的描述符。我们可以用@property来提供我们的status同义词:

class MyClass(Base):
    __tablename__ = "my_table"
    id = mapped_column(Integer, primary_key=True)
    status = mapped_column(String(50))
    @property
    def job_status(self):
        return "Status: " + self.status
    job_status = synonym("status", descriptor=job_status)

在使用声明性时,可以使用synonym_for()装饰器更简洁地表达上述模式:

from sqlalchemy.ext.declarative import synonym_for
class MyClass(Base):
    __tablename__ = "my_table"
    id = mapped_column(Integer, primary_key=True)
    status = mapped_column(String(50))
    @synonym_for("status")
    @property
    def job_status(self):
        return "Status: " + self.status

虽然synonym()对于简单的镜像很有用,但是使用描述符增强属性行为的用例更好地在现代使用中使用混合属性特性来处理,后者更加面向 Python 描述符。从技术上讲,一个synonym()可以做任何一个hybrid_property能做的事情,因为它也支持注入自定义 SQL 功能,但是在更复杂的情况下混合属性更容易使用。

对象名称 描述
synonym(name, *, [map_column, descriptor, comparator_factory, init, repr, default, default_factory, compare, kw_only, info, doc]) 将一个属性名表示为映射属性的同义词,即该属性将反映另一个属性的值和表达式行为。
function sqlalchemy.orm.synonym(name: str, *, map_column: bool | None = None, descriptor: Any | None = None, comparator_factory: Type[PropComparator[_T]] | None = None, init: _NoArg | bool = _NoArg.NO_ARG, repr: _NoArg | bool = _NoArg.NO_ARG, default: _NoArg | _T = _NoArg.NO_ARG, default_factory: _NoArg | Callable[[], _T] = _NoArg.NO_ARG, compare: _NoArg | bool = _NoArg.NO_ARG, kw_only: _NoArg | bool = _NoArg.NO_ARG, info: _InfoType | None = None, doc: str | None = None) → Synonym[Any]

将一个属性名表示为映射属性的同义词,即该属性将反映另一个属性的值和表达式行为。

例如:

class MyClass(Base):
    __tablename__ = 'my_table'
    id = Column(Integer, primary_key=True)
    job_status = Column(String(50))
    status = synonym("job_status")

参数:

  • name – 现有映射属性的名称。这可以引用在类上配置的 ORM 映射属性的字符串名称,包括列绑定属性和关系。
  • descriptor – 一个 Python 描述符,当访问此属性时将用作 getter(和可能的 setter)。
  • map_column
    仅适用于传统映射和对现有表对象的映射。如果为True,则synonym()构造将定位到在此同义词的属性名称通常与该同义词的属性名称相关联的映射表上的Column对象,并生成一个新的ColumnProperty,该属性将此Column映射到作为同义词的“name”参数给定的替代名称;通过这种方式,重新定义Column的映射为不同名称的步骤是不必要的。这通常用于当Column要被替换为也使用描述符的属性时,也就是与synonym.descriptor参数结合使用时:
my_table = Table(
    "my_table", metadata,
    Column('id', Integer, primary_key=True),
    Column('job_status', String(50))
)
class MyClass:
    @property
    def _job_status_descriptor(self):
        return "Status: %s" % self._job_status
mapper(
    MyClass, my_table, properties={
        "job_status": synonym(
            "_job_status", map_column=True,
            descriptor=MyClass._job_status_descriptor)
    }
)
  • 在上面的例子中,名为_job_status的属性会自动映射到job_status列:
>>> j1 = MyClass()
>>> j1._job_status = "employed"
>>> j1.job_status
Status: employed
  • 当使用声明式时,为了与同义词结合使用提供描述符,请使用sqlalchemy.ext.declarative.synonym_for()助手。但是,请注意,通常应优选混合属性功能,特别是在重新定义属性行为时。
  • info – 可选的数据字典,将填充到此对象的InspectionAttr.info属性中。
  • comparator_factory
    PropComparator的子类,将在 SQL 表达式级别提供自定义比较行为。
    注意
    对于提供重新定义属性的 Python 级别和 SQL 表达式级别行为的用例,请参阅使用描述符和混合中介绍的混合属性,这是一种更有效的技术。

另请参阅

同义词 - 同义词概述

synonym_for() - 一种面向声明式的辅助工具

使用描述符和混合 - 混合属性扩展提供了一种更新的方法,可以更灵活地增强属性行为,比同义词更有效。

运算符定制

SQLAlchemy ORM 和 Core 表达式语言使用的“运算符”是完全可定制的。例如,比较表达式 User.name == 'ed' 使用了 Python 本身内置的名为 operator.eq 的运算符 - SQLAlchemy 关联的实际 SQL 构造可以被修改。新的操作也可以与列表达式关联起来。最直接重新定义列表达式的运算符的方法是在类型级别进行 - 详细信息请参阅重新定义和创建新的运算符。

ORM 级别的函数如column_property()relationship()composite()还提供了在 ORM 级别重新定义运算符的功能,方法是将PropComparator子类传递给每个函数的comparator_factory参数。在这个级别定制运算符的情况很少见。详细信息请参阅PropComparator的文档概述。


SqlAlchemy 2.0 中文文档(八)(4)https://developer.aliyun.com/article/1559851

相关文章
|
5月前
|
弹性计算 机器人 应用服务中间件
一键部署开源Qwen3并集成到钉钉、企业微信
Qwen3系列模型现已正式发布并开源,包含8款“混合推理模型”,其中涵盖两款MoE模型(Qwen3-235B-A22B与Qwen3-30B-A3B)及六个Dense模型。阿里云计算巢已支持Qwen3-235B-A22B和Qwen3-32B的私有化部署,用户可通过计算巢轻松完成部署,并借助AppFlow集成至钉钉机器人或企业微信。文档详细介绍了从模型部署、创建应用到配置机器人的全流程,帮助用户快速实现智能助手的接入与使用。
395 19
一键部署开源Qwen3并集成到钉钉、企业微信
|
2月前
|
数据采集 编解码 人工智能
Gemma 3n正式版开源:谷歌全新端侧多模态大模型,2GB 内存就能跑,重点提升编码和推理能力!
6月底,Google正式开源发布了全新端侧多模态大模型 Gemma 3n!相较此前的预览版,最新的 Gemma 3n 完整版进一步提升性能表现,支持在 2GB 内存的硬件上本地运行,重点提升了编码和推理方面的能力。
329 1
|
12月前
|
机器学习/深度学习 算法 TensorFlow
交通标志识别系统Python+卷积神经网络算法+深度学习人工智能+TensorFlow模型训练+计算机课设项目+Django网页界面
交通标志识别系统。本系统使用Python作为主要编程语言,在交通标志图像识别功能实现中,基于TensorFlow搭建卷积神经网络算法模型,通过对收集到的58种常见的交通标志图像作为数据集,进行迭代训练最后得到一个识别精度较高的模型文件,然后保存为本地的h5格式文件。再使用Django开发Web网页端操作界面,实现用户上传一张交通标志图片,识别其名称。
455 7
交通标志识别系统Python+卷积神经网络算法+深度学习人工智能+TensorFlow模型训练+计算机课设项目+Django网页界面
|
11月前
|
算法 计算机视觉 Python
圆形检测算法-基于颜色和形状(opencv)
该代码实现了一个圆检测算法,用于识别视频中的红色、白色和蓝色圆形。通过将图像从RGB转换为HSV颜色空间,并设置对应颜色的阈值范围,提取出目标颜色的区域。接着对这些区域进行轮廓提取和面积筛选,使用霍夫圆变换检测圆形,并在原图上绘制检测结果。
350 0
|
12月前
|
机器学习/深度学习 数据采集 开发者
深度学习中的模型优化策略
【9月更文挑战第20天】在深度学习的海洋里,每一个研究者和实践者都在追求更高效、更准确的模型。本文将深入探讨深度学习中模型优化的策略,从数据预处理到正则化技术,再到超参数调整,我们将一步步揭开模型优化的神秘面纱。无论你是初学者还是有经验的开发者,这篇文章都将为你提供宝贵的见解和实用的技巧。让我们一起探索如何让你的深度学习模型更加出色吧!
221 8
|
9月前
|
人工智能 API 数据库
Qwen-Agent功能调用实践探索
本文详细解析了Qwen-Agent的核心功能——功能调用,涵盖其定义、工作流程、重要性和实际应用,通过实例展示了如何在Qwen-Agent中利用此功能与外部工具和API互动,扩展AI应用范围。
|
SQL 关系型数据库 MySQL
Pandas获取SQL数据库read_sql()函数及参数一文详解+实例代码
Pandas获取SQL数据库read_sql()函数及参数一文详解+实例代码
7554 0
Pandas获取SQL数据库read_sql()函数及参数一文详解+实例代码
|
网络协议 网络安全 网络虚拟化
三层交换机与防火墙对接上网配置示例
三层交换机是具有路由功能的交换机,由于路由属于OSI模型中第三层网络层的功能,所以称为三层交换机。 三层交换机既可以工作在二层也可以工作在三层,可以部署在接入层,也可以部署在汇聚层,作为用户的网关。
290 0
|
缓存 Linux 测试技术
安装【银河麒麟V10】linux系统--并挂载镜像12
【7月更文挑战第12天】安装【银河麒麟V10】linux系统--并挂载镜像
4158 0
|
存储 算法 搜索推荐
图解堆排序(一次弄懂堆结构以及堆排序)
图解堆排序(一次弄懂堆结构以及堆排序)