fields.Url φιάλη-restplus δεν λειτουργεί για το έγγραφο mongoengine;

ψήφοι
0

Έχω την εξής Mongoengine 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()

Και τα ακόλουθα model, των πόρων που ορίζονται για αυτό:

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)

Όλα λειτουργούν ΟΚ για όλους τους τομείς, εκτός από την fields.Url, και το ακόλουθο μήνυμα λάθους αυξάνεται:

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

Προσπάθησα να χρησιμοποιήσει flask«s jsonifyλειτουργία:

return jsonify(queryset)

αλλά το ακόλουθο σφάλμα παρουσιαστεί:

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']?

Παρακαλώ να με ενημερώσετε αν θέλετε οποιεσδήποτε άλλες λεπτομέρειες, και ευχαριστώ εκ των προτέρων.

Δημοσιεύθηκε 24/10/2019 στις 12:02
πηγή χρήστη
Σε άλλες γλώσσες...                            


1 απαντήσεις

ψήφοι
1

Προσπάθησα επίλυση του προβλήματός σας με την απλούστευση Documentκαι model. Το πρόβλημα έγκειται στην αντιμετώπιση των πόρων σας:

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

querysetγίνεται κατάλογο των θέσεων [<Post: Post object>, <Post: Post object>]. Όταν marshal_withδιακοσμητή εφαρμόζεται σε απάντηση, αναμένει μεμονωμένο αντικείμενο, DICTS, ή καταλόγους αντικειμένων . Παρά το γεγονός ότι πρέπει να συνεργαστεί με 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"
  }
]

Ελπίζω ότι αυτό καθαρίζει το πρόβλημα.

Απαντήθηκε 27/10/2019 στις 11:19
πηγή χρήστη

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