Mysql Python Sqlalchemy二进制列类型HEX()和UNHEX()
我正在尝试学习Sqlalchemy并使用ORM。我的一列将文件哈希存储为二进制。在SQL中,select将是Mysql Python Sqlalchemy二进制列类型HEX()和UNHEX(),mysql,python-2.7,sqlalchemy,Mysql,Python 2.7,Sqlalchemy,我正在尝试学习Sqlalchemy并使用ORM。我的一列将文件哈希存储为二进制。在SQL中,select将是 从hash=UNHEX('somehash')的表中选择类型、列。 如何使用我的ORM实现这样的选择(理想情况下还有一个插入示例)?我已经开始阅读有关列覆盖的内容,但我不清楚/不确定这是否是我真正想要的 乙二醇 res=session.query.filter(Model.hash==\uuuuu something\uuuuuu?) 想法?仅适用于选择和插入 那么,对于select,您
从hash=UNHEX('somehash')的表中选择类型、列。
如何使用我的ORM实现这样的选择(理想情况下还有一个插入示例)?我已经开始阅读有关列覆盖的内容,但我不清楚/不确定这是否是我真正想要的
乙二醇
res=session.query.filter(Model.hash==\uuuuu something\uuuuuu?)
想法?仅适用于选择和插入
那么,对于select,您可以使用:
>>> from sqlalchemy import func
>>> session = (...)
>>> (...)
>>> engine = create_engine('sqlite:///:memory:', echo=True)
>>> q = session.query(Model.id).filter(Model.some == func.HEX('asd'))
>>> print q.statement.compile(bind=engine)
SELECT model.id
FROM model
WHERE model.some = HEX(?)
插入:
>>> from sqlalchemy import func
>>> session = (...)
>>> (...)
>>> engine = create_engine('sqlite:///:memory:', echo=True)
>>> m = new Model(hash=func.HEX('asd'))
>>> session.add(m)
>>> session.commit()
INSERT INTO model (hash) VALUES (HEX(%s))
更好的方法:使用sql函数转换数据的自定义列
但是,我认为最适合你的是使用any,看看这个
检查下面的代码,它将创建一个我认为适合您需要的自定义列:
from sqlalchemy.types import VARCHAR
from sqlalchemy import func
class HashColumn(VARCHAR):
def bind_expression(self, bindvalue):
# convert the bind's type from String to HEX encoded
return func.HEX(bindvalue)
def column_expression(self, col):
# convert select value from HEX encoded to String
return func.UNHEX(col)
您可以将表格建模为:
from sqlalchemy import Column, types
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Model(Base):
__tablename__ = "model"
id = Column(types.Integer, primary_key=True)
col = Column(HashColumn(20))
def __repr__(self):
return "Model(col=%r)" % self.col
一些用法:
>>> (...)
>>> session = create_session(...)
>>> (...)
>>> model = Model(col='Iuri Diniz')
>>> session.add(model)
>>> session.commit()
这将发出以下查询:
INSERT INTO model (col) VALUES (HEX(?)); -- ('Iuri Diniz',)
SELECT
model.id AS model_id, UNHEX(model.col) AS model_col
FROM model
LIMIT ? ; -- (1,)
SELECT
model.id AS model_id, UNHEX(model.col) AS model_col
FROM model
WHERE model.col = HEX(?)
LIMIT ? ; -- ('Iuri Diniz', 1)
更多用法:
>>> session.query(Model).first()
Model(col='Iuri Diniz')
这将发出以下查询:
INSERT INTO model (col) VALUES (HEX(?)); -- ('Iuri Diniz',)
SELECT
model.id AS model_id, UNHEX(model.col) AS model_col
FROM model
LIMIT ? ; -- (1,)
SELECT
model.id AS model_id, UNHEX(model.col) AS model_col
FROM model
WHERE model.col = HEX(?)
LIMIT ? ; -- ('Iuri Diniz', 1)
还有一点:
>>> session.query(Model).filter(Model.col == "Iuri Diniz").first()
Model(col='Iuri Diniz')
这将发出以下查询:
INSERT INTO model (col) VALUES (HEX(?)); -- ('Iuri Diniz',)
SELECT
model.id AS model_id, UNHEX(model.col) AS model_col
FROM model
LIMIT ? ; -- (1,)
SELECT
model.id AS model_id, UNHEX(model.col) AS model_col
FROM model
WHERE model.col = HEX(?)
LIMIT ? ; -- ('Iuri Diniz', 1)
额外:使用python类型转换数据的自定义列
也许您想使用一些漂亮的自定义类型,并希望在python和数据库之间进行转换
在下面的示例中,我在python和数据库之间转换UUID(代码基于此):
由于以下错误,我无法使@iuridiniz的自定义列解决方案正常工作:
sqlalchemy.exc.StatementError: (builtins.TypeError) encoding without a string argument
对于以下表达式:
m = Model(col='FFFF')
session.add(m)
session.commit()
我通过重写处理参数的process\u bind\u param
解决了这个问题
在将其传递给bind_expression
以插入查询语言之前
from sqlalchemy.types import VARCHAR
from sqlalchemy import func
class HashColumn(VARCHAR):
def process_bind_param(self, value, dialect):
# encode value as a binary
if value:
return bytes(value, 'utf-8')
def bind_expression(self, bindvalue):
# convert the bind's type from String to HEX encoded
return func.HEX(bindvalue)
def column_expression(self, col):
# convert select value from HEX encoded to String
return func.UNHEX(col)
然后定义表是一样的:
from sqlalchemy import Column, types
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Model(Base):
__tablename__ = "model"
id = Column(types.Integer, primary_key=True)
col = Column(HashColumn(20))
def __repr__(self):
return "Model(col=%r)" % self.col
我真的很喜欢一种更好的方法:使用sql函数转换数据的自定义列,但在MySQL 5.7中使用BINARY和VARBINARY存储十六进制字符串时,我遇到了一些问题。我尝试了不同的方法,但SQLAlchemy一直在抱怨编码,和/或在无法使用它们的上下文中使用func.HEX
和func.UNHEX
。使用python3和SQLAlchemy 1.2.8,我成功地扩展了基类并替换了它的处理器,因此SQLAlchemy不需要数据库中的函数来绑定数据和计算结果,而是在python中完成,如下所示:
import codecs
from sqlalchemy.types import VARBINARY
class VarBinaryHex(VARBINARY):
"""Extend VARBINARY to handle hex strings."""
impl = VARBINARY
def bind_processor(self, dialect):
"""Return a processor that decodes hex values."""
def process(value):
return codecs.decode(value, 'hex')
return process
def result_processor(self, dialect, coltype):
"""Return a processor that encodes hex values."""
def process(value):
return codecs.encode(value, 'hex')
return process
def adapt(self, impltype):
"""Produce an adapted form of this type, given an impl class."""
return VarBinaryHex()
我们的想法是用python函数代替需要DBMS干预的HEX
和UNHEX
,python函数的作用与HEX和UNHEX一样,对十六进制字符串进行编码和解码。如果您直接连接到数据库,则可以使用HEX和UNHEX,但从SQLAlchemy开始,codecs.enconde
和codecs.decode
函数可以为您工作
我敢打赌,如果有人对编写适当的处理器感兴趣,甚至可以从python的角度将十六进制值作为整数进行管理,从而允许存储大于BIGINT的整数
一些考虑:
- 如果十六进制字符串的长度已知,则可以使用
代替BINARY
VARBINARY
- 根据您将要执行的操作,在将要使用此类列的类的构造函数上取消/大写字符串可能是值得的,这样您就可以在对象初始化时使用一致的大写。i、 例如,
但'aa'!='AA'
0xaa==0xaa
- 如前所述,您可以考虑将DB二进制十六进制值转换为PRYthon整数的处理器。
- 使用
时要小心,因为VARBINARY
'aa'!='00aa'
- 如果使用
,假设您的列是BINARY
,请考虑您提供的小于col=column(BinaryHex(length=4))
字节的任何值都将以零完成。我是说,如果你这样做了length
并提交它,当您稍后从Database中检索它时,您将得到的是obj.col='aabb'
,这是完全不同的obj.col=='aabb0000'