2016-07-12 3 views
1

Je travaille sur une API REST JSON REST de base utilisant Flask-Restless, Flask-SQLAlchemy et Marshmallow.Flask-Restless & Marshmallow: l'objet 'dict' n'a pas d'attribut '_sa_instance_state'

Je rencontre un problème lors de l'utilisation de cette combinaison de bibliothèques, mais uniquement lorsque j'active la désérialisation à l'aide de Marshmallow.

J'ai largement recherché l'erreur, mais je ne trouve que des problèmes similaires lors de l'utilisation de relations de base de données, ce que je ne suis pas.

J'ai supprimé autant de code que possible de mon application tout en obtenant toujours la même erreur. Les blocs de code suivants sont 1: 1 ce qui s'exécute localement.

models.py:

from flask_sqlalchemy import SQLAlchemy 
db = SQLAlchemy() 

class Case(db.Model): 
    __tablename__ = 'case' 
    id = db.Column(db.Integer, primary_key=True) 
    amount = db.Column(db.Integer, nullable=False) 

serializers.py:

from marshmallow import Schema 


class CaseSchema(Schema): 
    pass # for simplicity - nothing works 

case_schema = CaseSchema() 


def case_serializer(instance): 
    return case_schema.dump(instance).data 


def case_deserializer(data): 
    return case_schema.load(data).data 

main.py:

from flask import Flask 
import flask_restless 

import models 
import serializers 

app = Flask(__name__) 
app.config['DEBUG'] = True  
models.db.init_app(app) 


def init_db(): 
    with app.app_context(): 
     models.db.create_all() 


def init_api(): 
    init_db() 

    with app.app_context(): 
     api_manager = flask_restless.APIManager(app, flask_sqlalchemy_db=models.db) 
     api_manager.create_api(models.Case, methods=['GET', 'POST', 'PUT'], 
           serializer=serializers.case_serializer, 
           deserializer=serializers.case_deserializer) # <- stuff breaks when enabling this line 


if __name__ == "__main__": 
    init_db() 
    init_api() 
    app.run() 

tests.py:

import json 
import os 
import myapp 
import unittest 
import tempfile 


with myapp.app.app_context(): 
    myapp.init_api() 


class MyappTestCase(unittest.TestCase): 
    def setUp(self): 
     self.db_fd, myapp.app.config['DATABASE'] = tempfile.mkstemp() 
     myapp.app.config['TESTING'] = True 
     self.app = myapp.app.test_client() 

    def tearDown(self): 
     os.close(self.db_fd) 
     os.unlink(myapp.app.config['DATABASE']) 

    def test_create_case(self): 
     msg = { 
      "amount": 1038, 
     } 

     post_response = self.app.post("/api/case", data=json.dumps(msg), 
             content_type="application/json") 
     assert post_response.status_code == 201 

if __name__ == '__main__': 
    unittest.main() 

Versions utilisées:

Flask==0.11 
Flask-SQLAlchemy==2.1 
Flask-Restless==0.17.0 
mysqlclient==1.3.7 
SQLAlchemy-Utils==0.32.8 
marshmallow==2.9.0 

Enfin, la pleine STACKTRACE lorsque les tests en cours d'exécution:

====================================================================== 
ERROR: test_create_case (__main__.myappTestCase) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "/Users/myuser/.virtualenvs/myenv/lib/python3.5/site-packages/sqlalchemy/orm/session.py", line 1584, in add 
    state = attributes.instance_state(instance) 
AttributeError: 'dict' object has no attribute '_sa_instance_state' 

During handling of the above exception, another exception occurred: 

Traceback (most recent call last): 
    File "myapp_tests.py", line 37, in test_create_case 
    content_type="application/json") 
    File "/Users/myuser/.virtualenvs/myenv/lib/python3.5/site-packages/werkzeug/test.py", line 788, in post 
    return self.open(*args, **kw) 
    File "/Users/myuser/.virtualenvs/myenv/lib/python3.5/site-packages/flask/testing.py", line 113, in open 
    follow_redirects=follow_redirects) 
    File "/Users/myuser/.virtualenvs/myenv/lib/python3.5/site-packages/werkzeug/test.py", line 751, in open 
    response = self.run_wsgi_app(environ, buffered=buffered) 
    File "/Users/myuser/.virtualenvs/myenv/lib/python3.5/site-packages/werkzeug/test.py", line 668, in run_wsgi_app 
    rv = run_wsgi_app(self.application, environ, buffered=buffered) 
    File "/Users/myuser/.virtualenvs/myenv/lib/python3.5/site-packages/werkzeug/test.py", line 871, in run_wsgi_app 
    app_rv = app(environ, start_response) 
    File "/Users/myuser/.virtualenvs/myenv/lib/python3.5/site-packages/flask/app.py", line 2000, in __call__ 
    return self.wsgi_app(environ, start_response) 
    File "/Users/myuser/.virtualenvs/myenv/lib/python3.5/site-packages/flask/app.py", line 1991, in wsgi_app 
    response = self.make_response(self.handle_exception(e)) 
    File "/Users/myuser/.virtualenvs/myenv/lib/python3.5/site-packages/flask/app.py", line 1567, in handle_exception 
    reraise(exc_type, exc_value, tb) 
    File "/Users/myuser/.virtualenvs/myenv/lib/python3.5/site-packages/flask/_compat.py", line 33, in reraise 
    raise value 
    File "/Users/myuser/.virtualenvs/myenv/lib/python3.5/site-packages/flask/app.py", line 1988, in wsgi_app 
    response = self.full_dispatch_request() 
    File "/Users/myuser/.virtualenvs/myenv/lib/python3.5/site-packages/flask/app.py", line 1641, in full_dispatch_request 
    rv = self.handle_user_exception(e) 
    File "/Users/myuser/.virtualenvs/myenv/lib/python3.5/site-packages/flask/app.py", line 1544, in handle_user_exception 
    reraise(exc_type, exc_value, tb) 
    File "/Users/myuser/.virtualenvs/myenv/lib/python3.5/site-packages/flask/_compat.py", line 33, in reraise 
    raise value 
    File "/Users/myuser/.virtualenvs/myenv/lib/python3.5/site-packages/flask/app.py", line 1639, in full_dispatch_request 
    rv = self.dispatch_request() 
    File "/Users/myuser/.virtualenvs/myenv/lib/python3.5/site-packages/flask/app.py", line 1625, in dispatch_request 
    return self.view_functions[rule.endpoint](**req.view_args) 
    File "/Users/myuser/.virtualenvs/myenv/lib/python3.5/site-packages/flask_restless/views.py", line 157, in decorator 
    return func(*args, **kw) 
    File "/Users/myuser/.virtualenvs/myenv/lib/python3.5/site-packages/mimerender.py", line 244, in wrapper 
    result = target(*args, **kwargs) 
    File "/Users/myuser/.virtualenvs/myenv/lib/python3.5/site-packages/flask/views.py", line 84, in view 
    return self.dispatch_request(*args, **kwargs) 
    File "/Users/myuser/.virtualenvs/myenv/lib/python3.5/site-packages/flask/views.py", line 149, in dispatch_request 
    return meth(*args, **kwargs) 
    File "/Users/myuser/.virtualenvs/myenv/lib/python3.5/site-packages/flask_restless/views.py", line 189, in wrapped 
    return func(*args, **kw) 
    File "/Users/myuser/.virtualenvs/myenv/lib/python3.5/site-packages/flask_restless/views.py", line 1449, in post 
    self.session.add(instance) 
    File "/Users/myuser/.virtualenvs/myenv/lib/python3.5/site-packages/sqlalchemy/orm/scoping.py", line 157, in do 
    return getattr(self.registry(), name)(*args, **kwargs) 
    File "/Users/myuser/.virtualenvs/myenv/lib/python3.5/site-packages/sqlalchemy/orm/session.py", line 1586, in add 
    raise exc.UnmappedInstanceError(instance) 
sqlalchemy.orm.exc.UnmappedInstanceError: Class 'builtins.dict' is not mapped 

Répondre

1

Il s'avère que je devais ajouter __tablename__ à la définition du modèle et étendre le schéma:

class CaseSchema(Schema): 
    [...] 

    @post_load 
    def make_case(self, data): 
     return Case(**data)