【发布时间】:2020-04-11 18:08:00
【问题描述】:
我阅读了很多类似的问题,但没有一个明确回答我的问题。
我在 mysql 表列上使用 sqlalchemy-utils EncryptedType。
表创建和插入都可以,但是当我尝试进行查询时接收:
Traceback (most recent call last):
File "workspace/bin/test.py", line 127, in <module>
result = session.query(Tester).all()
File "workspace\ERP\venv\lib\site-packages\sqlalchemy\orm\query.py", line 3244, in all
return list(self)
File "workspace\venv\lib\site-packages\sqlalchemy\orm\loading.py", line 101, in instances
cursor.close()
File "workspace\venv\lib\site-packages\sqlalchemy\util\langhelpers.py", line 69, in __exit__
exc_value, with_traceback=exc_tb,
File "workspace\venv\lib\site-packages\sqlalchemy\util\compat.py", line 178, in raise_
raise exception
File "workspace\venv\lib\site-packages\sqlalchemy\orm\loading.py", line 81, in instances
rows = [proc(row) for row in fetch]
File "workspace\venv\lib\site-packages\sqlalchemy\orm\loading.py", line 81, in <listcomp>
rows = [proc(row) for row in fetch]
File "workspace\venv\lib\site-packages\sqlalchemy\orm\loading.py", line 642, in _instance
populators,
File "workspace\venv\lib\site-packages\sqlalchemy\orm\loading.py", line 779, in _populate_partial
dict_[key] = getter(row)
File "workspace\venv\lib\site-packages\sqlalchemy\engine\result.py", line 107, in __getitem__
return processor(self._row[index])
File "workspace\venv\lib\site-packages\sqlalchemy\sql\sqltypes.py", line 944, in process
value = bytes(value)
TypeError: string argument without an encoding
我发现这个错误只发生在使用 python 3,而不是使用 python 2。
而且问题出在 sqlalchemy bynary 类型上,因为我在 Binary、Varbinary 和 Blob 列上遇到了同样的错误。
由于python3中的bytes需要对字符串进行编码,我将第944行的sqlalchemy\sql\sqltypes.py的代码更改为value = bytes(value, 'utf-8),效果很好,所以我的问题是:
为什么我需要更改 sqlalchemy 代码? sqlalchemy 完全可以与 python3 一起使用吗?更改包的代码是否安全?
这里有一个代码示例供您尝试:
from sqlalchemy import MetaData, Integer, Column, Table, Binary, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, scoped_session
DB_CONFIG = {
'user': 'user_test',
'password': 'PSW_test',
'host': '127.0.0.1',
'database': 'db_test',
}
if __name__ == '__main__':
Base = declarative_base()
engine = create_engine("mysql+mysqlconnector://%(user)s:%(password)s@%(host)s/%(database)s" % DB_CONFIG,
echo=False)
Base.metadata.bind = engine
db_sessionmaker = sessionmaker(bind=engine)
Session = scoped_session(db_sessionmaker)
# create the table
meta = MetaData()
tests = Table(
'test', meta,
Column('id', Integer, primary_key=True),
Column('attr', Binary)
)
meta.create_all(engine)
class Test(Base):
__tablename__ = 'test'
id = Column(Integer, primary_key=True)
attr = Column(Binary)
new_test = Test(attr='try'.encode('utf-8'))
session = Session()
session.add(new_test)
session.commit()
result = session.query(Test).all()
for a in result:
print(a, a.id, a.attr)
Session.remove()
【问题讨论】:
-
SQLA 在 Python 3 中已完全可用多年。我认为还有其他问题。您的数据库似乎返回的是文本而不是二进制数据。
-
如果我使用
mysql.connector方法connect(**DB_CONFIG)查询数据,我可以正确获取数据。所以也许我错过了一些 SQLA 配置。 -
但是您的 DB-API 查询是否为相关列返回
bytes或str?mysql.connector仅使用 DB 提供的类型信息。 -
@IljaEverilä,你是对的,光标中“attr”列的类型是
str。我还注意到,如果在插入语句中我输入了一些像'try'.encode('utf-8')这样的数据,则使用mysql.connector 的查询可以正常工作,返回一个字符串,但是如果我输入像base64.b64decode('data'.encode('utf-8'))这样的数据,则会出现以下错误UnicodeDecodeError: 'utf-8' codec can't decode byte 0xab in position 1: invalid start byte。跨度> -
很遗憾,我还是找不到解决办法
标签: python mysql python-3.x sqlalchemy sqlalchemy-utils