版本:1.1.0b2 |发布日期:2016年7月1日

SQLAlchemy 1.1文档

自定义类型

存在多种方法来重新定义现有类型的行为并提供新的类型。

重写类型编译

经常需要强制更改类型的“字符串”版本,即在CREATE TABLE语句或其他SQL函数(如CAST)中呈现的类型。例如,应用程序可能希望强制为所有平台呈现BINARY,除了要呈现其中的BLOB之外的所有平台。对于大多数使用情况,现有泛型类型(在本例中为LargeBinary)的使用是首选。但为了更准确地控制类型,每个方言的编译指令可以与任何类型相关联:

from sqlalchemy.ext.compiler import compiles
from sqlalchemy.types import BINARY

@compiles(BINARY, "sqlite")
def compile_binary_sqlite(type_, compiler, **kw):
    return "BLOB"

上面的代码允许使用types.BINARY,它将针对除SQLite以外的所有后端生成字符串BINARY,在这种情况下,它将生成BLOB

有关其他示例,请参阅Changing Compilation of Types一节(Custom SQL Constructs and Compilation Extension的小节)。

增加现有类型

TypeDecorator允许创建自定义类型,将绑定参数和结果处理行为添加到现有的类型对象。当需要对数据库进行额外的Python数据封送处理时使用它。

注意

The bind- and result-processing of TypeDecorator is in addition to the processing already performed by the hosted type, which is customized by SQLAlchemy on a per-DBAPI basis to perform processing specific to that DBAPI. 要更改现有类型的DBAPI级处理,请参阅Replacing the Bind/Result Processing of Existing Types部分。

class sqlalchemy.types.TypeDecorator(*args, **kwargs)

基础:sqlalchemy.sql.expression.SchemaEventTargetsqlalchemy.types.TypeEngine

允许创建向现有类型添加附加功能的类型。

此方法优先于指定SQLAlchemy内置类型的子类化,因为它确保所有必需的基础类型功能都保留在原位。

典型用法:

import sqlalchemy.types as types

class MyType(types.TypeDecorator):
    '''Prefixes Unicode values with "PREFIX:" on the way in and
    strips it off on the way out.
    '''

    impl = types.Unicode

    def process_bind_param(self, value, dialect):
        return "PREFIX:" + value

    def process_result_value(self, value, dialect):
        return value[7:]

    def copy(self, **kw):
        return MyType(self.impl.length)

类级别的“impl”属性是必需的,并且可以引用任何TypeEngine类。或者,可以使用load_dialect_impl()方法根据给定的方言提供不同的类型类;在这种情况下,“impl”变量可以引用TypeEngine作为占位符。

接收与所使用的最终类型不相似的Python类型的类型可能需要定义TypeDecorator.coerce_compared_value()方法。这用于在将表达式中的Python对象强制为绑定参数时为表达式系统提供提示。考虑这个表达式:

mytable.c.somecol + datetime.date(2009, 5, 15)

在上面,如果“somecol”是一个Integer变体,那么我们在做日期算术是有意义的,上面的数据通常被数据库解释为给给定日期添加了几天。表达式系统通过不尝试将“date()”值强制为面向整数的绑定参数来做正确的事情。

但是,在TypeDecorator的情况下,我们通常将传入的Python类型更改为新的 - TypeDecorator默认情况下会“强制”非类型侧是相同的键入本身。如下所示,我们定义一个“纪元”类型,它将日期值存储为整数:

class MyEpochType(types.TypeDecorator):
    impl = types.Integer

    epoch = datetime.date(1970, 1, 1)

    def process_bind_param(self, value, dialect):
        return (value - self.epoch).days

    def process_result_value(self, value, dialect):
        return self.epoch + timedelta(days=value)

Our expression of somecol + date with the above type will coerce the “date” on the right side to also be treated as MyEpochType.

此行为可以通过coerce_compared_value()方法覆盖,该方法返回应该用于表达式值的类型。下面我们将它设置为整数值将被视为一个Integer,并且任何其他值被假定为日期并且将被视为MyEpochType

def coerce_compared_value(self, op, value):
    if isinstance(value, int):
        return Integer()
    else:
        return self

警告

请注意,coerce_compared_value的行为默认不会从基类型的行为继承。如果TypeDecorator增加了某种类型的操作符需要特殊逻辑的类型,则必须重写此方法一个关键的例子是装饰postgresql.JSONpostgresql.JSONB类型;应该使用TypeEngine.coerce_compared_value()的默认规则来处理像索引操作这样的操作符:

class MyJsonType(TypeDecorator):
    impl = postgresql.JSON

    def coerce_compared_value(self, op, value):
        return self.impl.coerce_compared_value(op, value)

如果没有上述步骤,像mycol['foo']这样的索引操作将导致索引值'foo'进行JSON编码。

__ init __ * args** kwargs T5>

构建一个TypeDecorator

Arguments sent here are passed to the constructor of the class assigned to the impl class level attribute, assuming the impl is a callable, and the resulting object is assigned to the self.impl instance attribute (thus overriding the class attribute of the same name).

如果类级别impl不是可调用的(不寻常的情况),它将被分配给同样的实例属性'as-is',忽略传递给构造函数的那些参数。

子类可以覆盖它来完全自定义self.impl的生成。

adapt(cls, **kw)
inherited from the adapt() method of TypeEngine

产生这种类型的“适应”形式,给予一个“impl”类来处理。

此方法在内部用于将泛型与特定于特定方言的“实现”类型相关联。

bind_expression T0> ( T1> bindvalue T2> ) T3> ¶ T4>
inherited from the bind_expression() method of TypeEngine

“给定一个绑定值(即一个BindParameter实例),在它的位置返回一个SQL表达式。

这通常是一个包含语句中现有绑定参数的SQL函数。它用于特殊数据类型,这些数据类型需要文字被封装在某些特殊的数据库函数中,以便将应用程序级别的值强制转换为数据库特定的格式。它是TypeEngine.bind_processor()方法的SQL模拟。

该方法在语句编译时进行评估,而不是语句构建时间。

请注意,此方法在实现时应始终返回完全相同的结构,而不使用任何条件逻辑,因为它可用于针对任意数量的绑定参数集的executemany()调用。

也可以看看:

Applying SQL-level Bind/Result Processing

bind_processor T0> ( T1> 方言 T2> ) T3> ¶ T4>

为给定的Dialect提供绑定值处理功能。

这是实现用于绑定值转换的TypeEngine合同的方法。TypeDecorator will wrap a user-defined implementation of process_bind_param() here.

用户定义的代码可以直接覆盖此方法,尽管它最好使用process_bind_param(),以保持由self.impl提供的处理。

参数: dialect - Dialect实例正在使用中。

此方法与此类的result_processor()方法相反。

coerce_compared_value op

为表达式中的'强制'Python值建议类型。

默认情况下,返回self。如果使用此类型的对象位于表达式的左侧或右侧,而不是指定了SQLAlchemy类型的普通Python对象,则表达式系统将调用此方法:

expr = table.c.somecolumn + 35

Where above, if somecolumn uses this type, this method will be called with the value operator.add and 35. 返回值是任何SQLAlchemy类型应该用于此特定操作的35

coerce_to_is_types =(< type'NoneType>,)

使用==进行比较时指定应该在表达式级别转换为“IS ”的Python类型(对于IS NOT !=结合

对于大多数SQLAlchemy类型,这包括NoneType以及bool

TypeDecorator modifies this list to only include NoneType, as typedecorator implementations that deal with boolean types are common.

Custom TypeDecorator类可以覆盖此属性以返回空元组,在这种情况下,不会将值强制为常量。

..versionadded :: 0.8.2
添加TypeDecorator.coerce_to_is_types以便更容易地控制__eq__() __ne__()操作。
column_expression T0> ( T1> colexpr T2> ) T3> ¶ T4>
inherited from the column_expression() method of TypeEngine

给定一个SELECT列表达式,返回一个包装SQL表达式。

这通常是一个SQL函数,它包装列表达式,并将其呈现在SELECT语句的columns子句中。它用于特殊数据类型,这些数据类型需要将列包装在某些特殊的数据库函数中,以便在将值返回给应用程序之前强制值。它是TypeEngine.result_processor()方法的SQL模拟。

该方法在语句编译时进行评估,而不是语句构建时间。

也可以看看:

Applying SQL-level Bind/Result Processing

compare_against_backend dialectconn_type
inherited from the compare_against_backend() method of TypeEngine

将此类型与给定的后端类型进行比较。

此函数目前尚未针对SQLAlchemy类型实现,对于所有内置类型,此函数将返回None但是,它可以通过用户定义的类型实现,可以通过模式比较工具(如Alembic autogenerate)使用它。

未来的SQLAlchemy版本也可能会对这种内置类型的方法产生影响。

如果此类型与给定类型相同,则该函数应返回True;该类型通常反映在数据库中,因此应该是数据库特定的。使用的方言也通过了。它也可以返回False来声明该类型不相同。

参数:
  • dialect – a Dialect that is involved in the comparison.
  • conn_type - 从后端反射的类型对象。

版本1.0.3中的新功能

比较值 xy

给定两个值,比较他们的平等。

默认情况下,这会调用基础“impl”的TypeEngine.compare_values(),后者通常使用Python等号运算符==

ORM使用该函数将原始加载的值与截获的“已更改”值进行比较,以确定是否发生了净更改。

编译 T0> ( T1> 方言=无 T2> ) T3> ¶ T4>
inherited from the compile() method of TypeEngine

生成此TypeEngine的字符串编译形式。

当不带参数调用时,使用“默认”方言产生字符串结果。

参数: dialect - a Dialect实例。
复制 T0> ( T1> **千瓦 T2> ) T3> ¶ T4>

生成此TypeDecorator实例的副本。

这是一个浅层副本,用于履行TypeEngine合约的一部分。通常不需要重写,除非用户定义的TypeDecorator具有应该被深度复制的本地状态。

dialect_impl T0> ( T1> 方言 T2> ) T3> ¶ T4>

返回该TypeEngine的特定于方言的实现。

evaluates_none T0> ( T1> ) T2> ¶ T3>
inherited from the evaluates_none() method of TypeEngine

返回将should_evaluate_none标志设置为True的此类型的副本。

例如。:

Table(
    'some_table', metadata,
    Column(
        String(50).evaluates_none(),
        nullable=True,
        server_default='no value')
)

ORM使用此标志来指示在INSERT语句中将None的正值传递到列,而不是从INSERT语句中省略列,该列具有触发列级缺省值的效果。它还允许具有与Python None值关联的特殊行为的类型指示该值不一定会转换为SQL NULL;这是一个JSON类型的主要例子,它可能希望保存JSON值'null'

在所有情况下,通过在INSERT语句中使用null SQL构造或与ORM映射属性关联,实际的NULL SQL值可始终保留在任何列中。

版本1.1中的新功能

也可以看看

Forcing NULL on a column with a default - in the ORM documentation

postgresql.JSON.none_as_null - Postgresql与此标志的JSON交互。

TypeEngine.should_evaluate_none - class-level flag

get_dbapi_type T0> ( T1> DBAPI T2> ) T3> ¶ T4>

返回由TypeDecorator表示的DBAPI类型对象。

默认情况下,这会调用基础“impl”的TypeEngine.get_dbapi_type()

literal_processor T0> ( T1> 方言 T2> ) T3> ¶ T4>

为给定的Dialect提供文字处理功能。

此处的子类通常会覆盖TypeDecorator.process_literal_param(),而不是直接使用此方法。

默认情况下,如果实现了该方法,则此方法使用TypeDecorator.process_bind_param(),其中TypeDecorator.process_literal_param()不是。The rationale here is that TypeDecorator typically deals with Python conversions of data that are above the layer of database presentation. With the value converted by TypeDecorator.process_bind_param(), the underlying type will then handle whether it needs to be presented to the DBAPI as a bound parameter or to the database as an inline SQL value.

版本0.9.0中的新功能

load_dialect_impl T0> ( T1> 方言 T2> ) T3> ¶ T4>

返回与方言对应的TypeEngine对象。

这是一个最终用户覆盖挂钩,可以根据给定的方言用于提供不同的类型。它由type_engine()TypeDecorator实现使用,以帮助确定最终返回给定TypeDecorator的类型。

默认返回self.impl

process_bind_param(value, dialect)

接收要转换的绑定参数值。

子类重写此方法以返回应传递给底层TypeEngine对象的值,并从那里返回到DBAPI execute()方法。

该操作可以是执行自定义行为所需的任何操作,例如转换或序列化数据。这也可以用作验证逻辑的钩子。

这个操作的设计应考虑到相反的操作,这将是该类的process_result_value方法。

参数:
  • value – Data to operate upon, of any type expected by this method in the subclass. 可以是None
  • dialect – the Dialect in use.
process_literal_param(value, dialect)

接收要在语句中内联呈现的文字参数值。

编译器在不使用绑定的情况下呈现文字值时,使用此方法,通常位于DDL中,例如列的“服务器默认值”或CHECK约束内的表达式。

返回的字符串将被渲染到输出字符串中。

版本0.9.0中的新功能

process_result_value(value, dialect)

接收要转换的结果行列值。

子类应实现此方法以对从数据库获取的数据进行操作。

给定一个已由底层TypeEngine对象处理的值,最初来自DBAPI游标方法fetchone()

该操作可以是执行自定义行为所需的任何操作,例如转换或序列化数据。这也可以用作验证逻辑的钩子。

参数:
  • value – Data to operate upon, of any type expected by this method in the subclass. 可以是None
  • dialect – the Dialect in use.

这个操作应该被设计成可以通过这个类的“process_bind_param”方法来反转。

python_type T0> ¶ T1>
inherited from the python_type attribute of TypeEngine

如果已知,则返回预期由此类型的实例返回的Python类型对象。

基本上,对于那些强制执行返回类型的类型,或者在所有常见DBAPI(例如int)中都可以这样做的类型,将返回该类型。

如果未定义返回类型,则引发NotImplementedError

请注意,任何类型也可以在SQL中容纳NULL,这意味着您在实践中也可以从任何类型获取None

result_processor dialectcoltype

为给定的Dialect提供结果值处理功能。

这是实现结果值转换的TypeEngine合同的方法。TypeDecorator will wrap a user-defined implementation of process_result_value() here.

用户定义的代码可以直接覆盖此方法,尽管它最好使用process_result_value(),以保持由self.impl提供的处理。

参数:
  • dialect - Dialect实例正在使用中。
  • coltype - SQLAlchemy数据类型

此方法与此类的bind_processor()方法相反。

type_engine(dialect)

TypeDecorator返回一个特定于方言的TypeEngine实例。

在大多数情况下,这返回由self.impl表示的TypeEngine类型的方言适应形式。使用dialect_impl(),但也遍历包装的TypeDecorator实例。行为可以通过覆盖load_dialect_impl()来定制。

with_variant type_dialect_name
inherited from the with_variant() method of TypeEngine

生成一个新的类型对象,将其应用于给定名称的方言时使用给定的类型。

例如。:

from sqlalchemy.types import String
from sqlalchemy.dialects import mysql

s = String()

s = s.with_variant(mysql.VARCHAR(collation='foo'), 'mysql')

TypeEngine.with_variant()的构造始终是从“fallback”类型到特定于方言的。返回的类型是Variant的一个实例,它本身提供了一个可重复调用的Variant.with_variant()

参数:
  • type_ – a TypeEngine that will be selected as a variant from the originating type, when a dialect of the given name is in use.
  • dialect_name – base name of the dialect which uses this type. (即'postgresql''mysql'等)

New in version 0.7.2.

TypeDecorator Recipes

接下来几个关键的TypeDecorator食谱。

将编码字符串强制为Unicode

A common source of confusion regarding the Unicode type is that it is intended to deal only with Python unicode objects on the Python side, meaning values passed to it as bind parameters must be of the form u'some string' if using Python 2 and not 3. 它执行的编码/解码功能仅适用于正在使用的DBAPI,并且主要是私有实现细节。

The use case of a type that can safely receive Python bytestrings, that is strings that contain non-ASCII characters and are not u'' objects in Python 2, can be achieved using a TypeDecorator which coerces as needed:

from sqlalchemy.types import TypeDecorator, Unicode

class CoerceUTF8(TypeDecorator):
    """Safely coerce Python bytestrings to Unicode
    before passing off to the database."""

    impl = Unicode

    def process_bind_param(self, value, dialect):
        if isinstance(value, str):
            value = value.decode('utf-8')
        return value

舍入数字

某些数据库连接器(如SQL Server的数据库连接器)会在小数位数过多的情况下传递Decimal。这是一个让他们满意的食谱:

from sqlalchemy.types import TypeDecorator, Numeric
from decimal import Decimal

class SafeNumeric(TypeDecorator):
    """Adds quantization to Numeric."""

    impl = Numeric

    def __init__(self, *arg, **kw):
        TypeDecorator.__init__(self, *arg, **kw)
        self.quantize_int = - self.impl.scale
        self.quantize = Decimal(10) ** self.quantize_int

    def process_bind_param(self, value, dialect):
        if isinstance(value, Decimal) and \
            value.as_tuple()[2] < self.quantize_int:
            value = value.quantize(self.quantize)
        return value

后端不可知的GUID类型

接收并返回Python uuid()对象。在其他后端使用Postgresql,CHAR(32)时使用PG UUID类型,并以字符串化的十六进制格式存储它们。如果需要,可以修改以在CHAR(16)中存储二进制文件:

from sqlalchemy.types import TypeDecorator, CHAR
from sqlalchemy.dialects.postgresql import UUID
import uuid

class GUID(TypeDecorator):
    """Platform-independent GUID type.

    Uses Postgresql's UUID type, otherwise uses
    CHAR(32), storing as stringified hex values.

    """
    impl = CHAR

    def load_dialect_impl(self, dialect):
        if dialect.name == 'postgresql':
            return dialect.type_descriptor(UUID())
        else:
            return dialect.type_descriptor(CHAR(32))

    def process_bind_param(self, value, dialect):
        if value is None:
            return value
        elif dialect.name == 'postgresql':
            return str(value)
        else:
            if not isinstance(value, uuid.UUID):
                return "%.32x" % uuid.UUID(value).int
            else:
                # hexstring
                return "%.32x" % value.int

    def process_result_value(self, value, dialect):
        if value is None:
            return value
        else:
            return uuid.UUID(value)

Marshal JSON字符串

这种类型使用simplejson将Python数据结构封送到/来自JSON。可以修改为使用Python的内置json编码器:

from sqlalchemy.types import TypeDecorator, VARCHAR
import json

class JSONEncodedDict(TypeDecorator):
    """Represents an immutable structure as a json-encoded string.

    Usage::

        JSONEncodedDict(255)

    """

    impl = VARCHAR

    def process_bind_param(self, value, dialect):
        if value is not None:
            value = json.dumps(value)

        return value

    def process_result_value(self, value, dialect):
        if value is not None:
            value = json.loads(value)
        return value

请注意,默认情况下,ORM不会检测到这种类型的“可变性” - 这意味着,就地更改值不会被检测到,也不会被刷新。如果没有进一步的步骤,您需要用每个父对象上的新值替换现有值以检测更改。请注意,这没有什么问题,因为许多应用程序可能不需要一旦创建值就会发生变化。对于那些确实有此要求的用户,最好使用sqlalchemy.ext.mutable扩展名应用对可变性的支持 - 请参阅Mutation Tracking中的示例。

替换现有类型的绑定/结果处理

使用TypeDecorator实现绑定/结果级别的大部分类型行为增强。对于需要替换由SQLAlchemy在DBAPI级别应用的特定处理的罕见场景,可以直接对SQLAlchemy类型进行子类化,并且bind_processor()result_processor()这样做需要重写adapt()方法。此方法是SQLAlchemy在执行语句期间生成特定于DBAPI的类型行为的机制。覆盖它可以使用自定义类型的副本来代替DBAPI特定的类型。下面我们将types.TIME类型进行子类化以具有自定义结果处理行为。process()函数将直接从DBAPI游标接收value

class MySpecialTime(TIME):
    def __init__(self, special_argument):
        super(MySpecialTime, self).__init__()
        self.special_argument = special_argument

    def result_processor(self, dialect, coltype):
        import datetime
        time = datetime.time
        def process(value):
            if value is not None:
                microseconds = value.microseconds
                seconds = value.seconds
                minutes = seconds / 60
                return time(
                          minutes / 60,
                          minutes % 60,
                          seconds - minutes * 60,
                          microseconds)
            else:
                return None
        return process

    def adapt(self, impltype):
        return MySpecialTime(self.special_argument)

应用SQL级绑定/结果处理

如在Augmenting Existing TypesReplacing the Bind/Result Processing of Existing Types部分所见,SQLAlchemy允许在将参数发送到语句时调用Python函数,如以及从数据库加载结果行时,以及在将数据发送到数据库或从数据库发送时对其应用转换。也可以定义SQL级别的转换。这里的基本原理是,只有关系数据库包含一系列必要的功能,才能在应用程序和持久性格式之间强制传入和传出数据。例子包括使用数据库定义的加密/解密函数,以及处理地理数据的存储过程。Postgis对Postgresql的扩展包括一系列SQL函数,这些函数是将数据强制转换为特定格式所必需的。

任何TypeEngineUserDefinedTypeTypeDecorator子类都可以包含TypeEngine.bind_expression()和/或TypeEngine.column_expression(),当定义为返回非None值时,应返回要注入SQL语句的ColumnElement表达式,参数或列表达式。例如,要构建将所有传入数据应用于Postgis函数ST_GeomFromText的所有传出值和函数ST_AsTextGeometry类型,我们可以创建我们自己的UserDefinedType的子类,它提供这些方法与func结合使用:

from sqlalchemy import func
from sqlalchemy.types import UserDefinedType

class Geometry(UserDefinedType):
    def get_col_spec(self):
        return "GEOMETRY"

    def bind_expression(self, bindvalue):
        return func.ST_GeomFromText(bindvalue, type_=self)

    def column_expression(self, col):
        return func.ST_AsText(col, type_=self)

我们可以将Geometry类型应用到Table元数据中,并将其用于select()结构中:

geometry = Table('geometry', metadata,
              Column('geom_id', Integer, primary_key=True),
              Column('geom_data', Geometry)
            )

print(select([geometry]).where(
  geometry.c.geom_data == 'LINESTRING(189412 252431,189631 259122)'))

结果SQL根据需要嵌入两个函数。ST_AsText is applied to the columns clause so that the return value is run through the function before passing into a result set, and ST_GeomFromText is run on the bound parameter so that the passed-in value is converted:

SELECT geometry.geom_id, ST_AsText(geometry.geom_data) AS geom_data_1
FROM geometry
WHERE geometry.geom_data = ST_GeomFromText(:geom_data_2)

The TypeEngine.column_expression() method interacts with the mechanics of the compiler such that the SQL expression does not interfere with the labeling of the wrapped expression. 例如,如果我们针对表达式的label()呈现select(),则将字符串标签移动到包装表达式的外部:

print(select([geometry.c.geom_data.label('my_data')]))

输出:

SELECT ST_AsText(geometry.geom_data) AS my_data
FROM geometry

对于直接对内置类型进行子类化的示例,我们继承postgresql.BYTEA以提供一个PGPString,它将利用Postgresql pgcrypto透明地扩展到encrpyt /解密值:

from sqlalchemy import create_engine, String, select, func, \
        MetaData, Table, Column, type_coerce

from sqlalchemy.dialects.postgresql import BYTEA

class PGPString(BYTEA):
    def __init__(self, passphrase, length=None):
        super(PGPString, self).__init__(length)
        self.passphrase = passphrase

    def bind_expression(self, bindvalue):
        # convert the bind's type from PGPString to
        # String, so that it's passed to psycopg2 as is without
        # a dbapi.Binary wrapper
        bindvalue = type_coerce(bindvalue, String)
        return func.pgp_sym_encrypt(bindvalue, self.passphrase)

    def column_expression(self, col):
        return func.pgp_sym_decrypt(col, self.passphrase)

metadata = MetaData()
message = Table('message', metadata,
                Column('username', String(50)),
                Column('message',
                    PGPString("this is my passphrase", length=1000)),
            )

engine = create_engine("postgresql://scott:tiger@localhost/test", echo=True)
with engine.begin() as conn:
    metadata.create_all(conn)

    conn.execute(message.insert(), username="some user",
                                message="this is my message")

    print(conn.scalar(
            select([message.c.message]).\
                where(message.c.username == "some user")
        ))

pgp_sym_encryptpgp_sym_decrypt函数应用于INSERT和SELECT语句:

INSERT INTO message (username, message)
  VALUES (%(username)s, pgp_sym_encrypt(%(message)s, %(pgp_sym_encrypt_1)s))
  {'username': 'some user', 'message': 'this is my message',
    'pgp_sym_encrypt_1': 'this is my passphrase'}

SELECT pgp_sym_decrypt(message.message, %(pgp_sym_decrypt_1)s) AS message_1
  FROM message
  WHERE message.username = %(username_1)s
  {'pgp_sym_decrypt_1': 'this is my passphrase', 'username_1': 'some user'}

也可以看看:

PostGIS Integration

重新定义和创建新操作符

SQLAlchemy Core定义了一组可用于所有列表达式的表达式运算符。Some of these operations have the effect of overloading Python’s built in operators; examples of such operators include ColumnOperators.__eq__() (table.c.somecolumn == 'foo'), ColumnOperators.__invert__() (~table.c.flag), and ColumnOperators.__add__() (table.c.x + table.c.y). Other operators are exposed as explicit methods on column expressions, such as ColumnOperators.in_() (table.c.value.in_(['x', 'y'])) and ColumnOperators.like() (table.c.value.like('%ed%')).

在所有情况下,Core表达式结构都会查询表达式的类型,以确定现有运算符的行为,并找出不属于内置集合的其他运算符。The TypeEngine base class defines a root “comparison” implementation TypeEngine.Comparator, and many specific types provide their own sub-implementations of this class. 用户定义的TypeEngine.Comparator实现可以直接构建到特定类型的简单子类中,以覆盖或定义新的操作。下面,我们创建一个覆盖ColumnOperators.__add__()运算符的Integer子类。

from sqlalchemy import Integer

class MyInt(Integer):
    class comparator_factory(Integer.Comparator):
        def __add__(self, other):
            return self.op("goofy")(other)

上面的配置创建了一个新的类MyInt,它将TypeEngine.comparator_factory属性建立为引用新的类,继承TypeEngine.Comparator类的子类与Integer类型相关联。

用法:

>>> sometable = Table("sometable", metadata, Column("data", MyInt))
>>> print(sometable.c.data + 5)
sometable.data goofy :data_1

通过将TypeEngine.Comparator自身实例化为expr属性,通过拥有的SQL表达式查阅ColumnOperators.__add__()的实现。表达式系统的机制是这样的,即操作继续递归直到表达式对象产生一个新的SQL表达式结构。Above, we could just as well have said self.expr.op("goofy")(other) instead of self.op("goofy")(other).

New methods added to a TypeEngine.Comparator are exposed on an owning SQL expression using a __getattr__ scheme, which exposes methods added to TypeEngine.Comparator onto the owning ColumnElement. 例如,要将log()函数添加到整数:

from sqlalchemy import Integer, func

class MyInt(Integer):
    class comparator_factory(Integer.Comparator):
        def log(self, other):
            return func.log(self.expr, other)

使用以上类型:

>>> print(sometable.c.data.log(5))
log(:log_1, :log_2)

一元操作也是可能的。例如,要添加Postgresql阶乘运算符的实现,我们将UnaryExpression结构与custom_op结合起来以产生阶乘表达式:

from sqlalchemy import Integer
from sqlalchemy.sql.expression import UnaryExpression
from sqlalchemy.sql import operators

class MyInteger(Integer):
    class comparator_factory(Integer.Comparator):
        def factorial(self):
            return UnaryExpression(self.expr,
                        modifier=operators.custom_op("!"),
                        type_=MyInteger)

使用以上类型:

>>> from sqlalchemy.sql import column
>>> print(column('x', MyInteger).factorial())
x !

也可以看看:

TypeEngine.comparator_factory

0.8版新增功能:增强了表达式系统,支持按类型级别定制运算符。

创建新类型

The UserDefinedType class is provided as a simple base class for defining entirely new database types. 用它来表示SQLAlchemy不知道的本地数据库类型。如果只需要Python翻译行为,请改用TypeDecorator

class sqlalchemy.types。 UserDefinedType

基础:sqlalchemy.types.TypeEngine

用户定义类型的基础。

这应该是新类型的基础。请注意,对于大多数情况,TypeDecorator可能更合适:

import sqlalchemy.types as types

class MyType(types.UserDefinedType):
    def __init__(self, precision = 8):
        self.precision = precision

    def get_col_spec(self, **kw):
        return "MYTYPE(%s)" % self.precision

    def bind_processor(self, dialect):
        def process(value):
            return value
        return process

    def result_processor(self, dialect, coltype):
        def process(value):
            return value
        return process

一旦这个类型被创建,它就可以立即使用:

table = Table('foo', meta,
    Column('id', Integer, primary_key=True),
    Column('data', MyType(16))
    )

The get_col_spec() method will in most cases receive a keyword argument type_expression which refers to the owning expression of the type as being compiled, such as a Column or cast() construct. 只有当方法接受其参数签名中的关键字参数(例如**kw)时才会发送此关键字;内省是用来检查这个以支持这个功能的遗留形式。

版本1.0.0新增:拥有的表达式通过关键字参数type_expression传递给get_col_spec()方法,如果它接收到**kw签名。

coerce_compared_value op

为表达式中的'强制'Python值建议类型。

UserDefinedType的默认行为与TypeDecorator的默认行为相同。默认情况下它会返回self,假设比较值应该强制为与此类型相同的类型。有关更多详细信息,请参阅TypeDecorator.coerce_compared_value()

在版本0.8中改变: UserDefinedType.coerce_compared_value()现在默认返回self,而不是落在TypeEngine.coerce_compared_value()