fields.Url de flacon-restplus ne fonctionne pas pour mongoengine document?

voix
0

J'ai la Mongoengine suivante Doeument:

class Post(mongo_db.Document):
    id = mongo_db.UUIDField(max_length=300, required=True, primary_key=True)
    content = mongo_db.StringField(max_length=300, required=False,)
    notes = mongo_db.ListField(mongo_db.StringField(max_length=2000), required=False)
    category = mongo_db.ReferenceField('Category', required=True)
    creation_date = mongo_db.DateTimeField()

Et ce qui suit modeldéfini, des ressources pour elle:

post_fields = ns.model(
    'Post', 
    {
        'content': fields.String,
        'creation_date': fields.DateTime,
        'notes': fields.List(fields.String),
        'category': fields.Nested(category_fields),
        'URI': fields.Url('my_endpoint')
    }
)


class PostResource(Resource):

    @ns.marshal_with(post_fields)
    def get(self):
        queryset = Post.objects
        return list(queryset)

Tout fonctionne bien pour tous les domaines, à l'exception du fields.Url, et l'erreur suivante est soulevée:

flask_restplus.fields.MarshallingError: url_for() argument after ** must be a mapping, not Post

J'ai essayé d'utiliser flaskde » jsonifyfonction:

return jsonify(queryset)

mais l'erreur se produit suivant:

werkzeug.routing.BuildError: Could not build url for endpoint 'my_endpoint' with values ['_on_close', '_status', '_status_code', 'direct_passthrough', 'headers', 'response']. Did you forget to specify values ['id']?

S'il vous plaît me faire savoir si vous voulez d'autres détails, et merci à l'avance.

Créé 24/10/2019 à 12:02
source utilisateur
Dans d'autres langues...                            


1 réponses

voix
1

J'ai essayé résoudre votre problème en simplifiant Documentet model. Le problème réside dans la réponse de votre ressource:

def get(self):
        queryset = Post.objects
        return list(queryset)

querysetdevient liste des postes que [<Post: Post object>, <Post: Post object>]. Lorsque marshal_withdécorateur est appliqué à la réponse, il attend seul objet, dicts ou listes d'objets . Bien qu'il devrait travailler avec l' Postobjet, je ne suis pas directement sûr de ce que provoque une erreur lors de l' application URIde l' Postobjet. Il semble en quelque sorte que la url_forméthode est appelée avec ses arguments propres à l' interne, et essaie de déballer l' Postobjet comme **post.

Petit exemple:

def url_for(endpoint, *args, **kwargs):
    print(endpoint, args, kwargs)

class Post:

    def __init__(self):
        self.content = "Dummy content"

post1 = Post()  # Instance of Post class
post2 = {"content": "This dummy content works !"} # Dictionary

# This won't work, returns TypeError: url_for() argument after ** must be a mapping, not Post
url_for("my_endpoint", 1, 2, **post1)

# This works since it's able to unpack dictionary.
url_for("my_endpoint", 1, 2, **post2)

La solution est de convertir tous les Postobjets à dictl'aide .to_mongo().to_dict()sur elle. En outre, pour représenter URI d'un objet Postavec ID, nous devons créer la route des ressources pour elle.

Exemple complet:

from flask import Flask
from flask_restplus import Api, fields, Resource, marshal_with
from flask_mongoengine import MongoEngine

import uuid

app = Flask(__name__)
api = Api(app)

app.config['MONGODB_SETTINGS'] = {
    'db': 'test',
    'host': 'localhost',
    'port': 27017
}

mongo_db = MongoEngine(app)

class Post(mongo_db.Document):
    id = mongo_db.UUIDField(max_length=300, required=True, primary_key=True)
    content = mongo_db.StringField(max_length=300, required=False)
    notes = mongo_db.ListField(mongo_db.StringField(max_length=2000), required=False)

#post1 = Post(id=uuid.uuid4(), content="abacdcad", notes=["a", "b"])
#post2 = Post(id=uuid.uuid4(), content="aaaaa", notes=["a", "bc"])

#post1.save()
#post2.save()

post_fields = {
    'content': fields.String,
    'notes': fields.List(fields.String),
    'URI': fields.Url('my_endpoint')
}

class PostResource(Resource):
    @marshal_with(post_fields)
    def get(self):
        queryset = [obj.to_mongo().to_dict() for obj in Post.objects]
        return queryset


class PostEndpoint(Resource):

    def get(self, _id):
        # Query db for this entry.
        return None


api.add_resource(PostResource, '/posts')
api.add_resource(PostEndpoint, '/post/<string:_id>', endpoint='my_endpoint')

if __name__ == '__main__':
    app.run(debug=True)

Note ci - dessus qui _idreprésente idl'entrée dans le document. Mongoengine il revient comme ça, ne sais pas pourquoi. Peut - être la clé primaire est représentée par underscore devant elle.

Réponse http://127.0.0.1:5000/postsdoit être ( URI est de mon exemple ici ):

[
  {
    "content": "Dummy content 1",
    "notes": [
      "a",
      "b"
    ],
    "URI": "/post/0b689467-41cc-4bb7-a606-881f6554a6b7"
  },
  {
    "content": "Dummy content 2",
    "notes": [
      "c",
      "d"
    ],
    "URI": "/post/8e8c1837-fdd2-4891-90cf-72edc0f4c19a"
  }
]

J'espère que cela efface le problème.

Créé 27/10/2019 à 11:19
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more