1
votes

Faire fonctionner le schéma imbriqué Flask Marshmallow avec ma route API

Je crée un APi en utilisant Flask, SQLAlchemy et Marshmallow.

Le modèle est défini et la base de données est remplie de données et lorsque la vue est atteinte. J'obtiens tous les champs de contenu JSON de NonProfitSchema.

@api_blueprint.route("/api/orgs/id/<int:id>/", methods=["GET"]) def get_org_by_id(id):
    org = Nonprofit.query.get(id)
    return npschema.jsonify(org)

@api_blueprint.route("/api/orgs/address/<int:id>/", methods=["GET"]) def get_org_by_id_address(id):
    org = Nonprofit.query.get(id)
    return addyschema.jsonify(org)

J'essayais de créer un nouveau schéma à partir de cela et de ne renvoyer qu'un sous-ensemble des données avec donc ci-dessous

class AddressSchema(NonProfitSchema):

    from marshmallow import fields 
    address = fields.Nested(NonprofitSchema(only=("street", "city", "state", "zipcode",)))  

J'avais des routes dans ma vue.py configurées comme suit:

class NonprofitSchema(ma.ModelSchema):
    class Meta:
        model = Nonprofit

        # To specialize fields something like so
        fields = ('id', 'name', 'ein', 'ico', 'street', 'city', 'state', 'zipcode', 'group', 'subsection', 'affiliation', 'classification', 'ruling',
 'deductability', 'foundation', 'activity', 'organization', 'status', 'tax_period', 'asset_cd','income_cd', 'filing_req_cd', 'pf_filing_req_cd',
 'acct_pd', 'asset_amt', 'income_amt', 'revenue_amt', 'ntee', 'sort_name', 'activity_full')

Cependant, lors de l'accès les dans un navigateur. Ils renvoient tous les deux exactement la même chose qui est le modèle de base de données complet de NonprofitSchema

Je suppose qu'il n'est pas possible de faire des sous-ensembles de données avec le schéma, non? P >


1 commentaires

Vous devez spécifier la version de guimauve que vous utilisez.


3 Réponses :


1
votes

Vous pouvez également connecter cette logique directement à l'étape jsonify

org = Nonprofit.query.get(id)
only_these_fields = ["street", "city", "state", "zipcode"]
return addyschema.jsonify({key: value for key, value in org.items() if key in only_these_fields}


2 commentaires

Oui, je pensais que c'était peut-être la seule façon d'y aller moi-même. J'attends toutes les autres méthodes, mais sinon je vais simplement accepter cela comme le meilleur et continuer.


Je connais cette sensation. Je déteste quand des paquets comme Marshmallow rendent les choses plus compliquées que faciles. Il devrait vraiment y avoir un meilleur moyen, mais je ne vois pas non plus pourquoi votre solution ne fonctionne pas. Attendez peut-être quelques jours qu'un expert en guimauve se présente



0
votes

Je n'ai pas la vue d'ensemble mais je trouve étrange d'imbriquer le schéma parent dans l'enfant.

Qu'en est-il à la place (non testé)?

class AddressSchema(NonProfitSchema):

    class Meta:
        fields = ("street", "city", "state", "zipcode",)

p>


0 commentaires

0
votes

Je devrais mettre à jour la réponse avec laquelle je suis allé. Pendant que moi et l'utilisateur c8999c 3f964f64 a essentiellement pensé de la même manière et cela fonctionnera en quelque sorte. Dans mon cas, "jsonify" sur l'objet ne fonctionnerait pas comme dans son exemple j'ai construit une fonction séparée car il n'y a pas d'attribut items . Donc, avec un filtre fait qui utilise l'attribut get comme suit:

@api_blueprint.route("/api/orgs/id/<int:id>/address", methods=["GET"])
def get_org_address_by_id(id):
    org = Nonprofit.query.get(id)
    only_these_fields = ["id", "ein", "name", "street", "city", "state", "zipcode"]
    addyschema = NonprofitSchema(fields=only_these_fields)
    return addyschema.jsonify(org)

Puis en modifiant la fonction pour l'utiliser:

@api_blueprint.route("/api/orgs/id/<int:id>/address", methods=["GET"])
def get_org_address_by_id(id):
    org = Nonprofit.query.get(id)
    only_these_fields = ["id", "ein", "name", "street", "city", "state", "zipcode"]
    return jsonify(jsonfilter(org, only_these_fields))

J'étais capable de le faire fonctionner.

Alternativement et une manière beaucoup plus simple après avoir examiné la documentation Flask et Flask-Marshmallow est simplement d'instancier un nouvel objet de classe du modèle avec des champs passés.

def jsonfilter(obj, attrlist):

    resp = {}
    for attr in attrlist:
        resp[attr] = getattr(obj,attr)
    return resp

J'ai opté contre cette méthode car je préfère n'avoir besoin que d'un seul objet de classe séparé et appeler une méthode de filtrage se sent mieux.


0 commentaires