2016-07-12 11 views
1

Ich arbeite an einer grundlegenden CRUD JSON REST API mit Flask-Restless, Flask-SQLAlchemy und Marshmallow.Flask-Restless & Marshmallow: 'dict' Objekt hat kein Attribut '_sa_instance_state'

Ich habe ein Problem mit dieser Kombination von Bibliotheken, aber nur wenn ich die Deserialisierung mit Marshmallow aktivieren.

Ich habe den Fehler ausgiebig gegoogelt, jedoch finde ich nur ähnliche Probleme bei der Verwendung von Datenbankbeziehungen, die ich nicht bin.

Ich habe so viel Code wie möglich aus meiner Anwendung entfernt, während immer noch der gleiche Fehler auftritt. Die folgenden Codebausteine ​​sind 1: 1 was lokal abläuft.

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() 

Versionen im Einsatz:

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 

schließlich die vollständige Stacktrace bei der Ausführung von Tests:

====================================================================== 
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 

Antwort

1

Stellt sich heraus, musste ich hinzufügen a __tablename__ zu der Modelldefinition und erweitern das Schema:

class CaseSchema(Schema): 
    [...] 

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