У меня есть моя модель, которая представляет 4 таблицы: пользователь, тест, область, проблема. Один пользователь имеет несколько тестов. Каждый тест имеет несколько областей, и каждая область имеет несколько проблем. Я хочу реорганизовать код (который работает нормально), чтобы использовать зефир для сериализовать мои объекты SLQ-Alchemy
Первый метод с использованием зефира работает нормально. Однако у меня возникают проблемы при попытке вернуть один тест со всеми его областями и проблемами.
Итак, подробности:
Это мой файл 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')
Итак, вот Ресурс, который отлично работает с зефиром. Это возвращает все тесты БЕЗ его областей и БЕЗ его проблем. Это работает нормально:
# 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))
Почему я получаю пустой словарь в
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 и превращала ее в объект Python.
getAllTestsForUser()
иgetTestWithAreasAndIssues()
? Во втором фрагменте кода, где вы получаете пустой словарь, в предыдущей строкеtestWithAreasAndIssues
тоже содержит пустой словарь? - person CloC   schedule 28.09.2018getTestWithAreasAndIssues()
нельзя сопоставить сTestSchema
, он имеет другую структуру. Подумайте о другой схеме для этого конкретного запроса. - person CloC   schedule 28.09.2018