使用带有 sqlalchemy 的 postgresql xml 数据类型

Posted

技术标签:

【中文标题】使用带有 sqlalchemy 的 postgresql xml 数据类型【英文标题】:Using postgresql xml data type with sqlalchemy 【发布时间】:2013-04-22 17:50:47 【问题描述】:

SqlAlchemy 通过方言支持大多数特定于数据库的数据类型,但我找不到任何可以使用 postgresql xml 列类型的东西。有人知道可行的解决方案吗?理想情况下,它不应该需要我自己实现自定义列类型。

【问题讨论】:

我没有看到它在 sqlalchemy 0.8 的 postgresql 方言中实现。您可以尝试使用反射来加载具有 XML 列的现有 psql 模式,并查看 sqlalchemy 如何优雅地处理它。但即使在最好的情况下,我也不认为你会得到像 XPATH 索引这样的好东西,即使反射确实做了一些优雅的事情,比如将列公开为文本类型。尝试在 sqlalchemy 问题跟踪器中提交增强请求。 还可以看看 zzzeek 使用邻接表存储 XML 数据的示例:bitbucket.org/sqlalchemy/sqlalchemy/src/… 对于这些类型,我们尽量依赖 psycopg2,虽然它们支持 JSON 和 HSTORE,但它们没有 XML 类型:initd.org/psycopg/docs/extras.html#additional-data-types。也就是说,您仍然可以使用docs.sqlalchemy.org/en/rel_0_8/core/types.html#types-custom 的技术在这里获得很多功能,我们当然会接受完整代码的拉取请求。 【参考方案1】:

如果你需要在 postgresql 数据库中有 native 'xml' 数据类型,你需要编写继承自 UserDefinedType 而非 TypeDecorator 的自定义类型。 Documentation

这是我在其中一个项目中使用的:

import xml.etree.ElementTree as etree
import sqlalchemy

class XMLType(sqlalchemy.types.UserDefinedType):
    def get_col_spec(self):
        return 'XML'

    def bind_processor(self, dialect):
        def process(value):
            if value is not None:
                if isinstance(value, str):
                    return value
                else:
                    return etree.tostring(value)
            else:
                return None
        return process

    def result_processor(self, dialect, coltype):
        def process(value):
            if value is not None:
                value = etree.fromstring(value)
            return value
        return process

【讨论】:

在python 3中,将etree.tostring(value)替换为etree.tostring(value, encoding="unicode")【参考方案2】:

见:SQLAlchemy TypeDecorator doesn't work

这是修改后的相同解决方案,用于处理具有任意 xml 长度的 oracle 的 XMLTYPE,并允许在类列之间进行 lxml etree 分配(无需从容器类中解析/重新解析 xml)

# coding: utf-8
from sqlalchemy import Column, DateTime, Float, ForeignKey, Index, Numeric, String, Table, Text, CLOB
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base

from sqlalchemy.sql.functions import GenericFunction
class XMLTypeFunc(GenericFunction):
    type=CLOB
    name='XMLType'
    identifier='XMLTypeFunc'


from sqlalchemy.types import TypeDecorator
from lxml import etree #you can use built-in etree if you want
class XMLType(TypeDecorator):

    impl = CLOB
    type = 'XMLTYPE' #etree.Element

    def get_col_spec(self):
        return 'XMLTYPE'

    def bind_processor(self, dialect):
        def process(value):
            if value is not None:
                return etree.tostring(value, encoding='UTF-8', pretty_print='True')
                #return etree.dump(value)
            else:
                return None
        return process

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

    def bind_expression(self, bindvalue):
        return XMLTypeFunc(bindvalue)

【讨论】:

以上是关于使用带有 sqlalchemy 的 postgresql xml 数据类型的主要内容,如果未能解决你的问题,请参考以下文章

使用带有 sqlalchemy 的 postgresql xml 数据类型

如何使用 Postgres 在 SQLAlchemy 中创建表?

sqlalchemy.exc.NoSuchModuleError:无法加载插件:sqlalchemy.dialects:postgres

在 Postgres 上使用 sqlalchemy 创建部分唯一索引

Python - 使用 sqlalchemy 的 Postgres 查询返回“空数据框”

Postgres 模式的 SQLAlchemy 支持