烧瓶棉花糖表序列化失败
flask marshmallow tables serialization failing
我有代表 4 个表的模型:用户、测试、区域、问题
一个用户有多个 Test.Each 测试有多个区域,每个区域有多个问题
我想重构代码(工作正常)以使用棉花糖序列化我的 SLQ-Alchemy 对象
第一种方法用棉花糖就可以了。
但是,我在尝试 return 一项测试时遇到问题,涉及所有领域和问题。
详情如下:
这是我的 model.py 文件
db = SQLAlchemy()
ma = Marshmallow()
class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(250), nullable=False)
email = db.Column(db.String(250), nullable=False)
class Test(db.Model):
__tablename__ = 'test'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, ForeignKey('user.id'))
user = relationship(User, backref=backref('tests'))
class Area(db.Model):
__tablename__ = 'area'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(30), nullable=False)
test_id = db.Column(db.Integer, ForeignKey('test.id'))
test = relationship(Test,
backref=backref('areas', cascade='all, delete-orphan')
)
user_id = db.Column(db.Integer, ForeignKey('user.id'))
user = relationship(User, backref=backref('areas'))
class Issue(db.Model):
__tablename__ = 'issue'
name = db.Column(db.String(80), nullable=False)
id = db.Column(db.Integer, primary_key=True)
area_id = db.Column(db.Integer, ForeignKey('area.id'))
area = relationship(Area,
backref=backref('issues', cascade='all, delete-orphan')
)
user_id = db.Column(db.Integer, ForeignKey('user.id'))
user = relationship(User, backref=backref('issues'))
class UserSchema(ma.ModelSchema):
class Meta:
model = User
# A User has a list of tests
test = ma.Nested('TestSchema', many=True)
class TestSchema(ma.ModelSchema):
class Meta:
model = Test
# Each test belongs to one user
user = ma.Nested('UserSchema')
# Each test has a list of areas
area = ma.Nested('AreaSchema', many=True)
class AreaSchema(ma.ModelSchema):
class Meta:
model = Area
# Each Area belongs to one test
test = ma.Nested('TestSchema')
# Each Area has a list of issues
issue = ma.Nested('IssueSchema', many=True)
class IssueSchema(ma.ModelSchema):
class Meta:
model = Issue
# Each issue belongs to one area
area = ma.Nested('AreaSchema')
所以现在这里是使用棉花糖完美工作的资源。
这 return 是所有测试,没有它的领域,没有它的问题
这工作正常:
# This works perfectly .
# It returns all tests for the user without its Areas and without Issues
# See line 26 the use of tests = tests_schema.dump(results).data
tests_schema = TestSchema(many=True)
class Tests(Resource):
""" This method return the list of tests for the user
We expect a valid JWT token from the user that was already
validated thorugh the decorator we created: token_required"""
@token_required
def get(self, *args, **kwargs):
jwt_data = kwargs['jwt_data']
if jwt_data:
# The JWT payload contains the "user"
user_name = jwt_data["user"]
logger.info("User from JWT payload data is %s" % user_name)
userId = modelUser.getUserIDFromName(user_name)
user = modelUser.getUserInfo(userId)
results = modelTest.getAllTestsForUser(userId)
logger.info(results)
tests = tests_schema.dump(results).data
logger.info(tests)
if tests:
return jsonify(tests)
else:
response = make_response(json.dumps(
'You do not have any test'), 204)
response.headers['Content-Type'] = 'application/json'
return response
这是我遇到的问题
我在 :
中得到一个空字典
结果 = test_schema.dump(testWithAreasAndIssues).data
# This returns just one test with ALL its Areas and ALL ISSUES
# The value returned from the DB is correct.I'm just refactoring to use Marshmallow
# line 19 returns empty
class Test(Resource):
""" GET DELETE AND PUT(modifies) a Test /api/test/<int:test_id>"""
@token_required
def get(self, test_id, *args, **kwargs):
logger.info("GET for /api/test/test_id= %s" % test_id)
jwt_data = kwargs['jwt_data']
test = getTestForJWT(jwt_data, test_id)
logger.info('test.id= %s for jwt=%s is %s' % (test_id, jwt_data, test))
logger.info('test= %s' % test)
logger.info('Calling getTestWithAreasAndIssues')
testWithAreasAndIssues = modelTest.getTestWithAreasAndIssues(
test.id)
logger.info('FullTest for testid =%s is %s' % (
test.id, testWithAreasAndIssues))
result = test_schema.dump(testWithAreasAndIssues).data
logger.info(jsonify(result))
为什么我在
中得到一个空字典
结果 = test_schema.dump(testWithAreasAndIssues).data
?
这是模型中的函数,它得到了所有区域和问题的测试。
def getTestWithAreasAndIssues(id):
""" This method will return a table containing a test
with all its areas and each areas with all its issues.
The result are unserialized object in a table with 3 columns
So we need to later serialize them and convert them
to a herarquick view using a python dictionary"""
test = (db.session.query(Test, Area, Issue)
.join(Area)
.join(Issue)
.options(
joinedload(Test.areas)
.joinedload(Area.issues)
)
.filter(Test.id == id)
.filter(Test.id == Area.test_id)
.filter(Area.id == Issue.area_id)
).all()
return test
这是这个函数的输出:
[(<Test 4>, <Area 28>, <Issue 17>),
(<Test 4>, <Area 29>, <Issue 18>),
(<Test 4>, <Area 36>, <Issue 19>),
(<Test 4>, <Area 36>, <Issue 20>),
(<Test 4>, <Area 36>, <Issue 21>)]
在使用 marshmallow 之前,我创建了一个函数,该函数将此 SQLAlchemy table 转换为 python 对象。
您应该使用 getTestWithAreasAndIssues()
使用的不同架构。
从拥有与您的 Test
型号正确对应的 TestSchema
开始:
class TestSchema(ma.ModelSchema):
class Meta:
model = Test
我还建议您检查您的模型,您的 User
模型不包含与 Test
、Area
或 Issue
的关系。查看 here 以正确定义与 SQLAlchemy 的关系。
然后您可以为 getTestWithAreasAndIssues()
:
返回的结果创建一个 Schema
class TestSchema(ma.ModelSchema):
test = ma.Nested('TestSchema')
user = ma.Nested('UserSchema')
area = ma.Nested('AreaSchema')
我设法通过在模型中进行一些更改来创建与我想要的类似的东西(我在模型中添加了一个反向引用和从 Issue 到 Test 的关系)。所以现在这是我的模式
class UserSchema(ma.ModelSchema):
class Meta:
model = User
class TestSchema(ma.ModelSchema):
class Meta:
model = Test
class AreaSchema(ma.ModelSchema):
class Meta:
model = Area
class IssueSchema(ma.ModelSchema):
class Meta:
model = Issue
class Test_DetailedSchema(ma.ModelSchema):
test = ma.Nested('self')
areas = ma.Nested('AreaSchema', many=True, exclude=('test', 'user',))
issues = ma.Nested('IssueSchema', many=True,
include=('name', 'id', 'reference_number', 'status',))
所以现在在我看来我是
from models.model import TestSchema
from models.model import IssueSchema
from models.model import AreaSchema
from models.model import Test_DetailedSchema
# Schemas
test_detailed_schema = Test_DetailedSchema()
test_schema = TestSchema(exclude=('user',))
areas_schema = AreaSchema(many=True, exclude=('test', 'user',))
issues_schema = IssueSchema(many=True)
在路线中我做了这样的事情:
class Test(Resource):
""" GET DELETE AND PUT(modifies) a Test /api/test/<int:test_id>"""
@token_required
def get(self, test_id, *args, **kwargs):
test_result = modelTest.getTest(test_id)
test_details, error = test_detailed_schema.dump(test_result)
pprint.pprint({'test_details': test_details})
这是我得到的输出:
{'test': {'areas': [
{'id': 10, 'issues': [7, 8], 'name': 'Name1'},
{'id': 11, 'issues': [9], 'name': 'NameX'},
{'id': 12, 'issues': [], 'name': 'Name2'},
{'id': 13,'issues': [],'name': 'Name3'},
{'id': 14, 'issues': [], 'name': 'Name4'},
{'id': 15,'issues': [],'name': 'Name5'},
{'id': 16, 'issues': [], 'name': 'Name6'},
{'id': 17, 'issues': [], 'name': 'Name7'},
{'id': 18,'issues': [10, 11],'name': 'Name8'}],
'issues': [{
'area': 10,
'id': 7,
'name': 'This is the issueX',
'open_date': None,
'reference_number': '701',
'status': 'N',
'test': 2,
'user': 1},
{'area': 10,
'id': 8,
'name': 'This is the issueY',
'open_date': None,
'reference_number': '702',
'status': 'N',
'test': 2,
'user': 1},
{'area': 11,
'id': 9,
'name': 'This is the issueZ',
'open_date': None,
'reference_number': '703',
'status': 'N',
'test': 2,
'user': 1},
{'area': 18,
'id': 10,
'name': 'This is the issueZZ',
'open_date': None,
'reference_number': '786',
'status': 'N',
'test': 2,
'user': 1},
{'area': 18,
'id': 11,
'name': 'This is the issueXXC',
'open_date': None,
'reference_number': '787',
'status': 'N',
'test': 2,
'user': 1}]}}
那么我应该怎么做才能扩大区域内的Issues并避免:
'id': 10, 'issues': [7, 8], 'name': 'Name1'}
取而代之的是
{'test': {'areas': [
{ 'id': 10,
'name': 'Name1'
'issues':[
{'area': 10,
'id': 7,
'name': 'This is the issueX',
'open_date': None,
'reference_number': '701',
'status': 'N',
'test': 2,
'user': 1},
{'area': 10,
'id': 8,
'name': 'This is the issueY',
'open_date': None,
'reference_number': '702',
'status': 'N',
'test': 2,
'user': 1}
]
为什么问题没有在区域内扩展?
我得到了我想要的:
test_schema = TestSchema(exclude=('user',))
areas_schema = AreaSchema(many=True, exclude=('test', 'user',))
issues_schema = IssueSchema(many=True, exclude=('test', 'user',))
及以后:
test, error = test_schema.dump(test_result)
areas, error = areas_schema.dump(test_result.areas)
issues, error = issues_schema.dump(test_result.issues)
return jsonify({'test': test, 'areas': areas, 'issues': issues})
如果有人知道为什么
test_detailed_schema = Test_DetailedSchema()
与
class Test_DetailedSchema(ma.ModelSchema):
test = ma.Nested('TesSchema')
areas = ma.Nested('AreaSchema', many=True, exclude=('test', 'user',))
issues = ma.Nested('IssueSchema', many=True, exclude=('test', 'user',))
不要return相同的结果,请在这里回复
我有代表 4 个表的模型:用户、测试、区域、问题 一个用户有多个 Test.Each 测试有多个区域,每个区域有多个问题 我想重构代码(工作正常)以使用棉花糖序列化我的 SLQ-Alchemy 对象
第一种方法用棉花糖就可以了。 但是,我在尝试 return 一项测试时遇到问题,涉及所有领域和问题。
详情如下:
这是我的 model.py 文件
db = SQLAlchemy()
ma = Marshmallow()
class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(250), nullable=False)
email = db.Column(db.String(250), nullable=False)
class Test(db.Model):
__tablename__ = 'test'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, ForeignKey('user.id'))
user = relationship(User, backref=backref('tests'))
class Area(db.Model):
__tablename__ = 'area'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(30), nullable=False)
test_id = db.Column(db.Integer, ForeignKey('test.id'))
test = relationship(Test,
backref=backref('areas', cascade='all, delete-orphan')
)
user_id = db.Column(db.Integer, ForeignKey('user.id'))
user = relationship(User, backref=backref('areas'))
class Issue(db.Model):
__tablename__ = 'issue'
name = db.Column(db.String(80), nullable=False)
id = db.Column(db.Integer, primary_key=True)
area_id = db.Column(db.Integer, ForeignKey('area.id'))
area = relationship(Area,
backref=backref('issues', cascade='all, delete-orphan')
)
user_id = db.Column(db.Integer, ForeignKey('user.id'))
user = relationship(User, backref=backref('issues'))
class UserSchema(ma.ModelSchema):
class Meta:
model = User
# A User has a list of tests
test = ma.Nested('TestSchema', many=True)
class TestSchema(ma.ModelSchema):
class Meta:
model = Test
# Each test belongs to one user
user = ma.Nested('UserSchema')
# Each test has a list of areas
area = ma.Nested('AreaSchema', many=True)
class AreaSchema(ma.ModelSchema):
class Meta:
model = Area
# Each Area belongs to one test
test = ma.Nested('TestSchema')
# Each Area has a list of issues
issue = ma.Nested('IssueSchema', many=True)
class IssueSchema(ma.ModelSchema):
class Meta:
model = Issue
# Each issue belongs to one area
area = ma.Nested('AreaSchema')
所以现在这里是使用棉花糖完美工作的资源。 这 return 是所有测试,没有它的领域,没有它的问题 这工作正常:
# This works perfectly .
# It returns all tests for the user without its Areas and without Issues
# See line 26 the use of tests = tests_schema.dump(results).data
tests_schema = TestSchema(many=True)
class Tests(Resource):
""" This method return the list of tests for the user
We expect a valid JWT token from the user that was already
validated thorugh the decorator we created: token_required"""
@token_required
def get(self, *args, **kwargs):
jwt_data = kwargs['jwt_data']
if jwt_data:
# The JWT payload contains the "user"
user_name = jwt_data["user"]
logger.info("User from JWT payload data is %s" % user_name)
userId = modelUser.getUserIDFromName(user_name)
user = modelUser.getUserInfo(userId)
results = modelTest.getAllTestsForUser(userId)
logger.info(results)
tests = tests_schema.dump(results).data
logger.info(tests)
if tests:
return jsonify(tests)
else:
response = make_response(json.dumps(
'You do not have any test'), 204)
response.headers['Content-Type'] = 'application/json'
return response
这是我遇到的问题 我在 :
中得到一个空字典结果 = test_schema.dump(testWithAreasAndIssues).data
# This returns just one test with ALL its Areas and ALL ISSUES
# The value returned from the DB is correct.I'm just refactoring to use Marshmallow
# line 19 returns empty
class Test(Resource):
""" GET DELETE AND PUT(modifies) a Test /api/test/<int:test_id>"""
@token_required
def get(self, test_id, *args, **kwargs):
logger.info("GET for /api/test/test_id= %s" % test_id)
jwt_data = kwargs['jwt_data']
test = getTestForJWT(jwt_data, test_id)
logger.info('test.id= %s for jwt=%s is %s' % (test_id, jwt_data, test))
logger.info('test= %s' % test)
logger.info('Calling getTestWithAreasAndIssues')
testWithAreasAndIssues = modelTest.getTestWithAreasAndIssues(
test.id)
logger.info('FullTest for testid =%s is %s' % (
test.id, testWithAreasAndIssues))
result = test_schema.dump(testWithAreasAndIssues).data
logger.info(jsonify(result))
为什么我在
中得到一个空字典
结果 = test_schema.dump(testWithAreasAndIssues).data
?
这是模型中的函数,它得到了所有区域和问题的测试。
def getTestWithAreasAndIssues(id):
""" This method will return a table containing a test
with all its areas and each areas with all its issues.
The result are unserialized object in a table with 3 columns
So we need to later serialize them and convert them
to a herarquick view using a python dictionary"""
test = (db.session.query(Test, Area, Issue)
.join(Area)
.join(Issue)
.options(
joinedload(Test.areas)
.joinedload(Area.issues)
)
.filter(Test.id == id)
.filter(Test.id == Area.test_id)
.filter(Area.id == Issue.area_id)
).all()
return test
这是这个函数的输出:
[(<Test 4>, <Area 28>, <Issue 17>),
(<Test 4>, <Area 29>, <Issue 18>),
(<Test 4>, <Area 36>, <Issue 19>),
(<Test 4>, <Area 36>, <Issue 20>),
(<Test 4>, <Area 36>, <Issue 21>)]
在使用 marshmallow 之前,我创建了一个函数,该函数将此 SQLAlchemy table 转换为 python 对象。
您应该使用 getTestWithAreasAndIssues()
使用的不同架构。
从拥有与您的 Test
型号正确对应的 TestSchema
开始:
class TestSchema(ma.ModelSchema):
class Meta:
model = Test
我还建议您检查您的模型,您的 User
模型不包含与 Test
、Area
或 Issue
的关系。查看 here 以正确定义与 SQLAlchemy 的关系。
然后您可以为 getTestWithAreasAndIssues()
:
class TestSchema(ma.ModelSchema):
test = ma.Nested('TestSchema')
user = ma.Nested('UserSchema')
area = ma.Nested('AreaSchema')
我设法通过在模型中进行一些更改来创建与我想要的类似的东西(我在模型中添加了一个反向引用和从 Issue 到 Test 的关系)。所以现在这是我的模式
class UserSchema(ma.ModelSchema):
class Meta:
model = User
class TestSchema(ma.ModelSchema):
class Meta:
model = Test
class AreaSchema(ma.ModelSchema):
class Meta:
model = Area
class IssueSchema(ma.ModelSchema):
class Meta:
model = Issue
class Test_DetailedSchema(ma.ModelSchema):
test = ma.Nested('self')
areas = ma.Nested('AreaSchema', many=True, exclude=('test', 'user',))
issues = ma.Nested('IssueSchema', many=True,
include=('name', 'id', 'reference_number', 'status',))
所以现在在我看来我是
from models.model import TestSchema
from models.model import IssueSchema
from models.model import AreaSchema
from models.model import Test_DetailedSchema
# Schemas
test_detailed_schema = Test_DetailedSchema()
test_schema = TestSchema(exclude=('user',))
areas_schema = AreaSchema(many=True, exclude=('test', 'user',))
issues_schema = IssueSchema(many=True)
在路线中我做了这样的事情:
class Test(Resource):
""" GET DELETE AND PUT(modifies) a Test /api/test/<int:test_id>"""
@token_required
def get(self, test_id, *args, **kwargs):
test_result = modelTest.getTest(test_id)
test_details, error = test_detailed_schema.dump(test_result)
pprint.pprint({'test_details': test_details})
这是我得到的输出:
{'test': {'areas': [
{'id': 10, 'issues': [7, 8], 'name': 'Name1'},
{'id': 11, 'issues': [9], 'name': 'NameX'},
{'id': 12, 'issues': [], 'name': 'Name2'},
{'id': 13,'issues': [],'name': 'Name3'},
{'id': 14, 'issues': [], 'name': 'Name4'},
{'id': 15,'issues': [],'name': 'Name5'},
{'id': 16, 'issues': [], 'name': 'Name6'},
{'id': 17, 'issues': [], 'name': 'Name7'},
{'id': 18,'issues': [10, 11],'name': 'Name8'}],
'issues': [{
'area': 10,
'id': 7,
'name': 'This is the issueX',
'open_date': None,
'reference_number': '701',
'status': 'N',
'test': 2,
'user': 1},
{'area': 10,
'id': 8,
'name': 'This is the issueY',
'open_date': None,
'reference_number': '702',
'status': 'N',
'test': 2,
'user': 1},
{'area': 11,
'id': 9,
'name': 'This is the issueZ',
'open_date': None,
'reference_number': '703',
'status': 'N',
'test': 2,
'user': 1},
{'area': 18,
'id': 10,
'name': 'This is the issueZZ',
'open_date': None,
'reference_number': '786',
'status': 'N',
'test': 2,
'user': 1},
{'area': 18,
'id': 11,
'name': 'This is the issueXXC',
'open_date': None,
'reference_number': '787',
'status': 'N',
'test': 2,
'user': 1}]}}
那么我应该怎么做才能扩大区域内的Issues并避免:
'id': 10, 'issues': [7, 8], 'name': 'Name1'}
取而代之的是
{'test': {'areas': [
{ 'id': 10,
'name': 'Name1'
'issues':[
{'area': 10,
'id': 7,
'name': 'This is the issueX',
'open_date': None,
'reference_number': '701',
'status': 'N',
'test': 2,
'user': 1},
{'area': 10,
'id': 8,
'name': 'This is the issueY',
'open_date': None,
'reference_number': '702',
'status': 'N',
'test': 2,
'user': 1}
]
为什么问题没有在区域内扩展?
我得到了我想要的:
test_schema = TestSchema(exclude=('user',))
areas_schema = AreaSchema(many=True, exclude=('test', 'user',))
issues_schema = IssueSchema(many=True, exclude=('test', 'user',))
及以后:
test, error = test_schema.dump(test_result)
areas, error = areas_schema.dump(test_result.areas)
issues, error = issues_schema.dump(test_result.issues)
return jsonify({'test': test, 'areas': areas, 'issues': issues})
如果有人知道为什么
test_detailed_schema = Test_DetailedSchema()
与
class Test_DetailedSchema(ma.ModelSchema):
test = ma.Nested('TesSchema')
areas = ma.Nested('AreaSchema', many=True, exclude=('test', 'user',))
issues = ma.Nested('IssueSchema', many=True, exclude=('test', 'user',))
不要return相同的结果,请在这里回复