我试图创建“包装器”,它通过SQLAlchemy ORM与DB一起工作,但返回结果的问题:获取错误“延迟实例没有属性'__ getitem __'”
我如何解决这个问题?
源代码: a)db_decorators.py
from twisted.internet import threads
from sqlalchemy import create_engine, pool
from sqlalchemy.orm import sessionmaker
def toThread(func):
def wrapper(*args, **kwargs):
return threads.deferToThread(func, *args, **kwargs)
return wrapper
class DBDefer(object):
def __init__(self, dsn, poolclass=pool.SingletonThreadPool):
self.engine = create_engine(dsn, poolclass=poolclass)
def __call__(self, func):
@toThread
def wrapper(*args, **kwargs):
session = sessionmaker(bind=self.engine)()
try:
return func(session=session, *args, **kwargs)
except:
session.rollback()
raise
finally:
session.close()
return wrapper
b)connector.py
import sqlalchemy
from twisted.internet.defer import Deferred
from db_decorators import DBDefer
from tables import Users
dbdefer = DBDefer('postgresql://test:test@localhost/testdb')
@dbdefer
def find_user_by_login(user_login, session=None):
return session.execute(sqlalchemy.select([Users]).where(Users.name == user_login)).fetchone()
class DB_API(object):
def find_user_by_login(self, user_login):
d = Deferred()
def _gotResult(user):
if user is None:
d.errback('No such user')
else:
d.callback(dict(user))
return user
find_user_by_login(user_login).addCallbacks(_gotResult, d.errback)
return d
c)server.py中的某个地方(Twisted上的服务器)
def authorization(self, data):
"""
Checking user with DB
"""
log.msg("[AUTH] User=%s trying to auth..." % data['user'])
#session = self.Session()
#result = session.execute(sqlalchemy.select([Users]).where(Users.name == data['user']))
#result = result.fetchone()
#session.close()
result = self.db_api.find_user_by_login(data['user'])
data, result_msg = commands.AUTH(result, data)
log.msg(result_msg)
return data
追溯:
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/twisted/python/log.py", line 88, in callWithLogger
return callWithContext({"system": lp}, func, *args, **kw)
File "/usr/local/lib/python2.7/dist-packages/twisted/python/log.py", line 73, in callWithContext
return context.call({ILogContext: newCtx}, func, *args, **kw)
File "/usr/local/lib/python2.7/dist-packages/twisted/python/context.py", line 118, in callWithContext
return self.currentContext().callWithContext(ctx, func, *args, **kw)
File "/usr/local/lib/python2.7/dist-packages/twisted/python/context.py", line 81, in callWithContext
return func(*args,**kw)
--- <exception caught here> ---
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/posixbase.py", line 614, in _doReadOrWrite
why = selectable.doRead()
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/tcp.py", line 215, in doRead
return self._dataReceived(data)
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/tcp.py", line 221, in _dataReceived
rval = self.protocol.dataReceived(data)
File "/usr/local/lib/python2.7/dist-packages/twisted/protocols/tls.py", line 419, in dataReceived
self._flushReceiveBIO()
File "/usr/local/lib/python2.7/dist-packages/twisted/protocols/tls.py", line 389, in _flushReceiveBIO
ProtocolWrapper.dataReceived(self, bytes)
File "/usr/local/lib/python2.7/dist-packages/twisted/protocols/policies.py", line 120, in dataReceived
self.wrappedProtocol.dataReceived(data)
File "/usr/local/lib/python2.7/dist-packages/autobahn/twisted/websocket.py", line 78, in dataReceived
self._dataReceived(data)
File "/usr/local/lib/python2.7/dist-packages/autobahn/websocket/protocol.py", line 1270, in _dataReceived
self.consumeData()
File "/usr/local/lib/python2.7/dist-packages/autobahn/websocket/protocol.py", line 1286, in consumeData
while self.processData() and self.state != WebSocketProtocol.STATE_CLOSED:
File "/usr/local/lib/python2.7/dist-packages/autobahn/websocket/protocol.py", line 1445, in processData
return self.processDataHybi()
File "/usr/local/lib/python2.7/dist-packages/autobahn/websocket/protocol.py", line 1758, in processDataHybi
fr = self.onFrameEnd()
File "/usr/local/lib/python2.7/dist-packages/autobahn/websocket/protocol.py", line 1887, in onFrameEnd
self._onMessageEnd()
File "/usr/local/lib/python2.7/dist-packages/autobahn/twisted/websocket.py", line 107, in _onMessageEnd
self.onMessageEnd()
File "/usr/local/lib/python2.7/dist-packages/autobahn/websocket/protocol.py", line 734, in onMessageEnd
self._onMessage(payload, self.message_is_binary)
File "/usr/local/lib/python2.7/dist-packages/autobahn/twisted/websocket.py", line 110, in _onMessage
self.onMessage(payload, isBinary)
File "server.py", line 80, in onMessage
json_data = self.commands_handlers['AUTH'](json_data)
File "server.py", line 64, in authorization
data, result_msg = commands.AUTH(result, data)
File "/home/relrin/code/Helenae/helenae/commands.py", line 68, in AUTH
if result['name'] == data['user']:
exceptions.AttributeError: Deferred instance has no attribute '__getitem__'
答案 0 :(得分:3)
self.db_api.find_user_by_login(data['user'])
会返回Deferred
。
使用它的代码 - data, result_msg = commands.AUTH(result, data)
- 忽略这一事实并将其视为结果。
问题中的一半代码正确使用Deferred
。例如,这是正确的:
find_user_by_login(user_login).addCallbacks(_gotResult, d.errback)
但是发生错误的代码不会尝试定义或设置任何回调。它试图使用Deferred
,就好像它是一个结果 - 而事实并非如此。
您需要使用addCallback
等。
如果你想一起使用SQLAlchemy和Twisted,还可以考虑查看alchimia。