قارورة مريحة:كائن معقد مارشال إلى json
-
21-12-2019 - |
سؤال
لدي سؤال بخصوص تمديد قارورة مريحة.لقد بدأت للتو في استخدامه وواجهت مشكلة واحدة.أملك flask-sqlalchemy
الكيانات المرتبطة بعلاقة متعددة لواحد وأريد أن تقوم نقطة النهاية المريحة بإرجاع الكيان الأصلي مع جميع أبنائه json
باستخدام المنظم.في حالتي Set يحتوي على العديد من المعلمات.نظرت إلى قارورة مريحة مستندات ولكن لم يكن هناك أي تفسير لكيفية حل هذه القضية.
يبدو أنني أفتقد شيئًا واضحًا ولكن لا يمكنني اكتشاف أي حل.هنا هو الكود الخاص بي:
# entities
class Set(db.Model):
id = db.Column("id", db.Integer, db.Sequence("set_id_seq"), primary_key=True)
title = db.Column("title", db.String(256))
parameters = db.relationship("Parameters", backref="set", cascade="all")
class Parameters(db.Model):
id = db.Column("id", db.Integer, db.Sequence("parameter_id_seq"), primary_key=True)
flag = db.Column("flag", db.String(256))
value = db.Column("value", db.String(256))
set_id = db.Column("set_id", db.Integer, db.ForeignKey("set.id"))
# marshallers
from flask.ext.restful import fields
parameter_marshaller = {
"flag": fields.String,
"value": fields.String
}
set_marshaller = {
'id': fields.String,
'title': fields.String,
'parameters': fields.List(fields.Nested(parameter_marshaller))
}
# endpoint
class SetApi(Resource):
@marshal_with(marshallers.set_marshaller)
def get(self, set_id):
entity = Set.query.get(set_id)
return entity
restful_api = Api(app)
restful_api.add_resource(SetApi, "/api/set/<int:set_id>")
الآن عندما أتصل /api/set/1
أحصل على خطأ في الخادم:
TypeError: 'Set' object is unsubscriptable
لذلك أحتاج إلى طريقة لتحديد set_marshaller بشكل صحيح حيث تقوم نقطة النهاية بإرجاع json هذا:
{
"id": : "1",
"title": "any-title",
"parameters": [
{"flag": "any-flag", "value": "any-value" },
{"flag": "any-flag", "value": "any-value" },
.....
]
}
وأنا أقدر أي مساعدة.
المحلول
لقد وجدت الحل لهذه المشكلة بنفسي.
بعد اللعب مع flask-restful
اكتشفت أنني ارتكبت بعض الأخطاء:
أولاً set_marshaller
يجب أن يبدو مثل هذا:
blob_marshaller = {
'id': fields.String,
'title': fields.String,
'parameters': fields.Nested(parameter_marshaller)
}
يمكن للمنظم المضطرب التعامل مع الحالة إذا كانت المعلمة قائمة والمنظمين إليها json
قائمة.
هناك مشكلة أخرى وهي أن المعلمات في API Set بها تحميل بطيء، لذلك عندما أحاول تنظيم مجموعة حصلت عليها KeyError: 'parameters'
, ، لذلك أحتاج إلى تحميل المعلمات بشكل صريح مثل هذا:
class SetApi(Resource):
@marshal_with(marshallers.set_marshaller)
def get(self, set_id):
entity = Set.query.get(set_id)
entity.parameters # loads parameters from db
return entity
أو خيار آخر هو تغيير علاقة النموذج:
parameters = db.relationship("Parameters", backref="set", cascade="all" lazy="joined")
نصائح أخرى
هذه إضافة إلى زيجيمانتاس'س إجابة:
أنا أستخدم Flask-RESTful وهذا حل لتحميل الخصائص المتداخلة.
يمكنك تمرير عنصر قابل للاستدعاء إلى مصمم الديكور:
class OrgsController(Resource):
@marshal_with(Organization.__json__())
def get(self):
return g.user.member.orgs
ثم قم بتحديث النماذج لإرجاع حقول الموارد للكيان الخاص بها.وبالتالي، ستقوم الكيانات المتداخلة بإرجاع حقول الموارد لكيانها نسبيًا.
class Organization(db.Model):
id = db.Column(db.Integer, primary_key=True)
...
@staticmethod
def __json__(group=None):
_json = {
'id': fields.String,
'login': fields.String,
'description': fields.String,
'avatar_url': fields.String,
'paid': fields.Boolean,
}
if group == 'flat':
return _json
from app.models import Repository
_json['repos'] = fields.Nested(Repository.__json__('flat'))
return _json
class Repository(db.Model):
id = db.Column(db.Integer, primary_key=True)
owner_id = db.Column(db.Integer, db.ForeignKey('organization.id'))
owner = db.relationship('Organization', lazy='select', backref=db.backref('repos', lazy='select'), foreign_keys=[owner_id])
...
@staticmethod
def __json__(group=None):
_json = {
'id': fields.String,
'name': fields.String,
'updated_at': fields.DateTime(dt_format='iso8601'),
}
if group == 'flat':
return _json
from app.models import Organization
_json['owner'] = fields.Nested(Organization.__json__('flat'))
return _json
وهذا يعطي التمثيل الذي أبحث عنه، ويحترم التحميل البطيء:
[
{
"avatar_url": "https://avatars.githubusercontent.com/u/18945?v=3",
"description": "lorem ipsum.",
"id": "1805",
"login": "foobar",
"paid": false,
"repos":
[
{
"id": "9813",
"name": "barbaz",
"updated_at": "2014-01-23T13:51:30"
},
{
"id": "12860",
"name": "bazbar",
"updated_at": "2015-04-17T11:06:36"
}
]
}
]
انا يعجبني
1) كيف يسمح لي هذا الأسلوب بتحديد حقول الموارد الخاصة بي لكل كيان وهو متاح لجميع مسارات الموارد الخاصة بي عبر التطبيق.
2) كيف تسمح لي حجة المجموعة بتخصيص التمثيل حسب رغبتي.لدي فقط "مسطح" هنا، ولكن يمكن كتابة أي منطق وتمريره إلى كائنات متداخلة أعمق.
3) يتم تحميل الكيانات فقط عند الضرورة.