【问题标题】:TypeError: key <built-in function id> is not a stringTypeError: key <built-in function id> 不是字符串
【发布时间】:2015-07-12 00:44:33
【问题描述】:

我正在使用 flask 及其 flask-restful 扩展来制作一个简单的 restful-api。我无法将数据填充到带有用户 ID(参考)的问题表中。

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

抱歉,代码行太长了。我只是不知道是什么导致了问题。

【问题讨论】:

  • 您的错误消息中提到了&lt;built-in function id&gt;。您认为内置的id 函数应该参与您的代码吗?如果没有,也许你不小心在某个地方使用了它。当然有很多地方你可以写id 而不是'id'user_id 或类似的东西。在您的代码中搜索id;你会发现一些相关的东西。此外,下一次,您应该能够查看您的错误消息并认识到您应该采取这些步骤。
  • 我的猜测是您在某个名为 id 的函数中有一个局部变量,但您正试图从一个 不同 函数中使用它,而该函数没有这样一个局部变量,因此它获取的是该名称的内置函数。或者,您可能有一个名为id属性,而您只是忘记在某处使用self.id,而是使用了内置函数。或类似的。

标签: python flask flask-sqlalchemy flask-restful


【解决方案1】:

你的问题出在这一行:

return {id:marshal(question, questionlist_fields)}

我想你想要这个:

return {'id': marshal(question, questionlist_fields)}

在某些语言中,尤其是 JavaScript,所有 dict 键都是字符串,并且语法允许您去掉引号。

在 Python 中,dict 键可以是任何你想要的。* 如果你想要一个字符串,你需要引号。如果你只是传递id,你只是说你希望密钥是变量id中的任何东西。由于您没有名为 id 的局部变量,因此您得到的是内置变量。

这仍然是完全有效的,即使它不是你想要的,也不是很有用。

但是,当您从 JSON API 上的 Flask post 方法返回 dict 时,它会被编码为 JSON。 JSON 只允许 dict 键的字符串,而不是函数。因此出现错误。


* 嗯,不完全是。它们可以是任何hashable,不包括像list 这样的可变类型,以及出于其他原因不想用作键的一些其他类型。

【讨论】:

    猜你喜欢
    • 2012-11-07
    • 1970-01-01
    • 2011-11-20
    • 2021-04-14
    • 2018-05-02
    • 2022-01-11
    • 2012-12-14
    • 2015-11-01
    • 2020-01-18
    相关资源
    最近更新 更多