Я пытался решить вашу проблему, упрощая Document
и model
. Проблема заключается в ответе вашего ресурса:
def get(self):
queryset = Post.objects
return list(queryset)
queryset
становится списком сообщений как [<Post: Post object>, <Post: Post object>]
. Когда к ответу применяется marshal_with
декоратор, он ожидает один объект, указания или списки объектов . Хотя он должен работать с объектом Post
, я не совсем уверен, что вызывает ошибку при применении объекта URI
к Post
. Как-то кажется, что метод url_for
вызывается с его собственными аргументами внутри и пытается распаковать Post
объект как **post
.
Небольшой пример:
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)
Решениепреобразовать каждый Post
объект в dict
, используя .to_mongo().to_dict()
на нем. Кроме того, чтобы представить URI объекта Post
с идентификатором, мы должны создать для него маршрут ресурса.
Полный пример:
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)
Обратите внимание, что _id
представляет id
записи в документе. Mongoengine возвращает это так, не уверен почему. Возможно, первичный ключ представлен подчеркиванием перед ним.
Ответ http://127.0.0.1:5000/posts
должен быть ( URI из моего примера здесь ):
[
{
"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"
}
]
Iнадеюсь, что это решит проблему.