سؤال

لدي سؤال بخصوص تمديد قارورة مريحة.لقد بدأت للتو في استخدامه وواجهت مشكلة واحدة.أملك 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) يتم تحميل الكيانات فقط عند الضرورة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top