TypeError: key <built-in function id> is not a string
TypeError: key <built-in function id> is not a string
我正在使用 flask 及其 flask-restful 扩展来制作一个简单的 restful-api。我在使用用户 ID(参考)将数据填充到问题 table 时遇到问题。
model.py 文件如下:
class User(UserMixin, SurrogatePK, Model):
__tablename__ = 'users'
username = Column(db.String(80), unique=True, nullable=False)
email = Column(db.String(80), unique=True, nullable=False)
#: The hashed password
password = Column(db.String(128), nullable=True)
created_at = Column(db.DateTime, nullable=False, default=dt.datetime.utcnow)
def __init__(self, username, email, password=None, **kwargs):
db.Model.__init__(self, username=username, email=email, **kwargs)
if password:
self.set_password(password)
else:
self.password = None
def set_password(self, password):
self.password = bcrypt.generate_password_hash(password)
def check_password(self, value):
return bcrypt.check_password_hash(self.password, value)
def generate_auth_token(self, expiration = 600):
s = Serializer('secret_key', expires_in = expiration)
return s.dumps({ 'id': self.id })
@staticmethod
def verify_auth_token(token):
s = Serializer('secret_key')
try:
data = s.loads(token)
except SignatureExpired:
return None # valid token, but expired
except BadSignature:
return None # invalid token
user = User.query.get(data['id'])
return user
def __repr__(self):
return '<User({username!r})>'.format(username=self.username)
class Question(SurrogatePK, Model):
__tablename__ = 'questions'
text = Column(db.String(400), nullable=True)
created_at = Column(db.DateTime, nullable=True, default=dt.datetime.utcnow)
user_id = ReferenceCol('users', nullable=True)
user = db.relationship('User', backref='question_users')
def __init__(self, text, created_at, user, **kwargs):
db.Model.__init__(self, text=text, user=user, **kwargs)
def __repr__(self):
return '<Question({text})>'.format(text=self.text)
我使用 flask-httpauth 的 HTTPBasicAuth 来验证用户并使用以下装饰器将用户信息存储到全局变量 g:
@auth.verify_password
def verify_password(username_or_token, password):
# first try to authenticate by token
user = User.verify_auth_token(username_or_token)
if not user:
# try to authenticate with username/password
user = User.query.filter_by(username = username_or_token).first()
if not user or not user.check_password(password):
return False
g.user = user
return True
最后,我的视图文件。
视图文件如下所示:
questionlist_fields = {
'text':fields.String,
'uri':fields.Url
}
class QuestionListAPI(Resource):
decorators = [auth.login_required]
def __init__(self):
self.reqparse = reqparse.RequestParser()
self.reqparse.add_argument('text', type=str, required=True,
help='No Question Title Provided', location='json')
super(QuestionListAPI, self).__init__()
def post(self):
args = self.reqparse.parse_args()
#----------the code causing error-----------------#
question = Question.create(text=args.text,
created_at=datetime.utcnow(),
user=g.user)
#-------------------------------------------------#
return {id:marshal(question, questionlist_fields)}
api.add_resource(QuestionListAPI, '/api/questions', endpoint='questions')
错误日志如下:
Traceback (most recent call last):
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask\app.py", line 1836, in __call__
return self.wsgi_app(environ, start_response)
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask\app.py", line 1820, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask_restful\__init__.py", line 265, in error_router
return original_handler(e)
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask\app.py", line 1403, in handle_exception
reraise(exc_type, exc_value, tb)
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask\_compat.py", line 32, in reraise
raise value.with_traceback(tb)
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask\app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask\app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask_restful\__init__.py", line 265, in error_router
return original_handler(e)
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask\app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask\_compat.py", line 32, in reraise
raise value.with_traceback(tb)
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask\app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask_debugtoolbar\__init__.py", line 124, in dispatch_request
return view_func(**req.view_args)
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask_restful\__init__.py", line 450, in wrapper
return self.make_response(data, code, headers=headers)
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask_restful\__init__.py", line 474, in make_response
resp = self.representations[mediatype](data, *args, **kwargs)
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask_restful\representations\json.py", line 24, in output_json
dumped = dumps(data, **local_settings)
File "C:\Python34\Lib\json\__init__.py", line 237, in dumps
**kw).encode(obj)
File "C:\Python34\Lib\json\encoder.py", line 194, in encode
chunks = list(chunks)
File "C:\Python34\Lib\json\encoder.py", line 422, in _iterencode
yield from _iterencode_dict(o, _current_indent_level)
File "C:\Python34\Lib\json\encoder.py", line 368, in _iterencode_dict
raise TypeError("key " + repr(key) + " is not a string")
TypeError: key <built-in function id> is not a string
抱歉代码行太长。我只是不知道是什么导致了这个问题。
您的问题出在这一行:
return {id:marshal(question, questionlist_fields)}
我想你想要这个:
return {'id': marshal(question, questionlist_fields)}
在某些语言中,特别是 JavaScript,所有字典键都是字符串,语法允许您省略引号。
在Python中,字典键可以是任何你想要的。*如果你想要一个字符串,你需要引号。如果你只是传递 id
,你只是说你希望密钥是变量 id
中的任何内容。由于您没有名为 id
的局部变量,因此您得到的是内置变量。
这仍然是完全有效的,即使它不是您想要的,也不是很有用。
但是,当您 return 来自 JSON API 上的 Flask post
方法的字典时,它会被编码为 JSON。并且 JSON 只允许字典键的字符串,而不是函数。因此错误。
* 嗯,不完全是。它们可以是任何 hashable,不包括像 list
这样的可变类型,以及其他一些出于其他原因不想用作键的类型。
我正在使用 flask 及其 flask-restful 扩展来制作一个简单的 restful-api。我在使用用户 ID(参考)将数据填充到问题 table 时遇到问题。
model.py 文件如下:
class User(UserMixin, SurrogatePK, Model):
__tablename__ = 'users'
username = Column(db.String(80), unique=True, nullable=False)
email = Column(db.String(80), unique=True, nullable=False)
#: The hashed password
password = Column(db.String(128), nullable=True)
created_at = Column(db.DateTime, nullable=False, default=dt.datetime.utcnow)
def __init__(self, username, email, password=None, **kwargs):
db.Model.__init__(self, username=username, email=email, **kwargs)
if password:
self.set_password(password)
else:
self.password = None
def set_password(self, password):
self.password = bcrypt.generate_password_hash(password)
def check_password(self, value):
return bcrypt.check_password_hash(self.password, value)
def generate_auth_token(self, expiration = 600):
s = Serializer('secret_key', expires_in = expiration)
return s.dumps({ 'id': self.id })
@staticmethod
def verify_auth_token(token):
s = Serializer('secret_key')
try:
data = s.loads(token)
except SignatureExpired:
return None # valid token, but expired
except BadSignature:
return None # invalid token
user = User.query.get(data['id'])
return user
def __repr__(self):
return '<User({username!r})>'.format(username=self.username)
class Question(SurrogatePK, Model):
__tablename__ = 'questions'
text = Column(db.String(400), nullable=True)
created_at = Column(db.DateTime, nullable=True, default=dt.datetime.utcnow)
user_id = ReferenceCol('users', nullable=True)
user = db.relationship('User', backref='question_users')
def __init__(self, text, created_at, user, **kwargs):
db.Model.__init__(self, text=text, user=user, **kwargs)
def __repr__(self):
return '<Question({text})>'.format(text=self.text)
我使用 flask-httpauth 的 HTTPBasicAuth 来验证用户并使用以下装饰器将用户信息存储到全局变量 g:
@auth.verify_password
def verify_password(username_or_token, password):
# first try to authenticate by token
user = User.verify_auth_token(username_or_token)
if not user:
# try to authenticate with username/password
user = User.query.filter_by(username = username_or_token).first()
if not user or not user.check_password(password):
return False
g.user = user
return True
最后,我的视图文件。 视图文件如下所示:
questionlist_fields = {
'text':fields.String,
'uri':fields.Url
}
class QuestionListAPI(Resource):
decorators = [auth.login_required]
def __init__(self):
self.reqparse = reqparse.RequestParser()
self.reqparse.add_argument('text', type=str, required=True,
help='No Question Title Provided', location='json')
super(QuestionListAPI, self).__init__()
def post(self):
args = self.reqparse.parse_args()
#----------the code causing error-----------------#
question = Question.create(text=args.text,
created_at=datetime.utcnow(),
user=g.user)
#-------------------------------------------------#
return {id:marshal(question, questionlist_fields)}
api.add_resource(QuestionListAPI, '/api/questions', endpoint='questions')
错误日志如下:
Traceback (most recent call last):
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask\app.py", line 1836, in __call__
return self.wsgi_app(environ, start_response)
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask\app.py", line 1820, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask_restful\__init__.py", line 265, in error_router
return original_handler(e)
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask\app.py", line 1403, in handle_exception
reraise(exc_type, exc_value, tb)
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask\_compat.py", line 32, in reraise
raise value.with_traceback(tb)
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask\app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask\app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask_restful\__init__.py", line 265, in error_router
return original_handler(e)
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask\app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask\_compat.py", line 32, in reraise
raise value.with_traceback(tb)
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask\app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask_debugtoolbar\__init__.py", line 124, in dispatch_request
return view_func(**req.view_args)
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask_restful\__init__.py", line 450, in wrapper
return self.make_response(data, code, headers=headers)
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask_restful\__init__.py", line 474, in make_response
resp = self.representations[mediatype](data, *args, **kwargs)
File "C:\Users\NI\Envs\nektime\lib\site-packages\flask_restful\representations\json.py", line 24, in output_json
dumped = dumps(data, **local_settings)
File "C:\Python34\Lib\json\__init__.py", line 237, in dumps
**kw).encode(obj)
File "C:\Python34\Lib\json\encoder.py", line 194, in encode
chunks = list(chunks)
File "C:\Python34\Lib\json\encoder.py", line 422, in _iterencode
yield from _iterencode_dict(o, _current_indent_level)
File "C:\Python34\Lib\json\encoder.py", line 368, in _iterencode_dict
raise TypeError("key " + repr(key) + " is not a string")
TypeError: key <built-in function id> is not a string
抱歉代码行太长。我只是不知道是什么导致了这个问题。
您的问题出在这一行:
return {id:marshal(question, questionlist_fields)}
我想你想要这个:
return {'id': marshal(question, questionlist_fields)}
在某些语言中,特别是 JavaScript,所有字典键都是字符串,语法允许您省略引号。
在Python中,字典键可以是任何你想要的。*如果你想要一个字符串,你需要引号。如果你只是传递 id
,你只是说你希望密钥是变量 id
中的任何内容。由于您没有名为 id
的局部变量,因此您得到的是内置变量。
这仍然是完全有效的,即使它不是您想要的,也不是很有用。
但是,当您 return 来自 JSON API 上的 Flask post
方法的字典时,它会被编码为 JSON。并且 JSON 只允许字典键的字符串,而不是函数。因此错误。
* 嗯,不完全是。它们可以是任何 hashable,不包括像 list
这样的可变类型,以及其他一些出于其他原因不想用作键的类型。