2015-05-02 39 views
-1

我正在使用燒瓶和燒瓶寧靜的擴展來製作簡單的restful-api。我無法將數據填充到帶有用戶標識(參考)的問題表中。TypeError:key <內置函數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) 

我用的燒瓶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 

對不起的代碼長行。我只是不知道是什麼導致了這個問題。

+0

您的錯誤消息提及'<內建函數ID>'。你認爲內置的'id'函數應該與你的代碼有關嗎?如果沒有,也許你不小心在某個地方使用過它。肯定有很多地方你可以寫'id'而不是'id''或'user_id'或類似的東西。搜索你的代碼'id';你會發現一些相關的東西。另外,下次您應該可以查看您的錯誤消息,並確認您應該採取這些措施。 – user2357112

+0

我的猜測是你在一個名爲'id'的函數中有一個局部變量,但是你想從一個_different_函數中使用它,它沒有這個局部變量,所以相反它得到了這個函數的內建函數名稱。或者,可能你有一個_attribute_名爲'id',並且你忘記了在某處使用'self.id',而是使用了內建函數。或類似。 – abarnert

回答

4

您的問題是在這條線:

return {id:marshal(question, questionlist_fields)} 

我想你想的:

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

在某些語言,尤其是JavaScript中,所有字典鍵是字符串,和語法允許將引號關閉。

在Python中,dict鍵可以是任何你想要的。 *如果你想要一個字符串,你需要引號。如果你只是通過id,你只是說你想要的密鑰是變量id。由於您沒有名爲id的本地變量,因此您得到的是內置的。

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

但是,當您從JSON API上的Flask post方法返回字典時,它將被編碼爲JSON。而JSON只允許字典的字典鍵,而不是函數。因此錯誤。


*好吧,不完全。它們可以是任何可以排列的,其中不包括像list這樣的可變類型,以及其他一些不想用作其他原因的鍵的類型。

+0

哇謝謝!這非常有幫助! –