简体   繁体   中英

Flask-PyMongo - Object of type InsertOneResult is not JSON serializable

i have an api and i am trying to store/post a user object using Flask-Pymongo.

but, i get the following error

File "/home/kay/.local/share/virtualenvs/server-iT4jZt3h/lib/python3.7/site-packages/flask/json/ i│ nit .py", line 321, in jsonify
│ dumps(data, indent=indent, separators=separators) + '\\n', │ File "/home/kay/.local/share/virtualenvs/server-iT4jZt3h/lib/python3.7/site-packages/flask/json/ i│ nit .py", line 179, in dumps
│ rv = _json.dumps(obj, **kwargs) │ File "/usr/lib/python3.7/json/ init .py", line 238, in dumps
│ **kw).encode(obj) │ File "/usr/lib/python3.7/json/encoder.py", line 201, in encode
│ chunks = list(chunks) │ File "/usr/lib/python3.7/json/encoder.py", line 438, in _iterencode │ o = _default(o) │ File "/home/kay/link/server/src/run.py", line 18, in default
│ return json.JSONEncoder.default(self, o) │ File "/usr/lib/python3.7/json/encoder.py", line 179, in default
│ raise TypeError(f'Object of type {o. class . name } ' │ TypeError: Object of type InsertOneResult is not JSON serializable

app/users/resource.py

from flask_restful import Resource
from flask import jsonify, request
from .repository import UsersRepository
from db import mongo


class UsersResource(Resource):

    def __init__(self):

        self.repository = UsersRepository()

    def get(self):

        data = {"Users": "Resource"}
        res = data, 200
        return res

    def post(self):

        req = request.get_json()

        user = {
            "email": req.get("email"),
            "password": req.get("password")
        }

        result = mongo.db.users.insert_one(user)

        return jsonify(result)

run.py

from flask import Flask
from app import api_bp
from db import mongo
from bson.objectid import ObjectId
import json
import datetime
import os

class JSONEncoder(json.JSONEncoder):

    def default(self, o):
        if isinstance(o, ObjectId):
            return str(o)
        if isinstance(o, set):
            return list(o)
        if isinstance(o, datetime.datetime):
            return str(o)
        return json.JSONEncoder.default(self, o)



def create_app(config_filename):

    app = Flask(__name__)
    app.config.from_object(config_filename)
    app.register_blueprint(api_bp, url_prefix='/api')

    mongo.init_app(app)

    app.json_encoder = JSONEncoder

    return app


# def logger():


# def database():


if __name__ == "__main__":
    app = create_app("config")
    app.run(host='0.0.0.0', port=8080, debug=True)

I believe that following previous suggestion you can find the answers. But I would like to provide another solution that simplifies it.

The solution assumes that pymongo and flask packages are installed:

from flask import Flask
from flask.json import JSONEncoder

from bson import json_util

from . import resources

# define a custom encoder point to the json_util provided by pymongo (or its dependency bson)
class CustomJSONEncoder(JSONEncoder):
    def default(self, obj): return json_util.default(obj)

application = Flask(__name__)
application.json_encoder = CustomJSONEncoder

if __name__ == "__main__":
    application.run()

  1. from bson.objectid import ObjectId
  2. from bson import json_util

    • use pymongo json_util bson to handle BSON types
  3. use force=true when getting json input :

    • req = request.get_json(force=true)
  4. use default values when getting dict fields like :
    • req.get("email", "")

you can check if fields are empty or not before inserting into mongo.

Simple Solution I found from here is

TypeError: ObjectId('') is not JSON serializable

Response -> bson dumps (searlization) -> json loads (deserialization)

Code is as follows :

from bson.json_util import dumps,RELAXED_JSON_OPTIONS
import json


def post(self,name):
        dream = {'name':name , 'price' : 12.00 }
        dreams.append(dream)
        dreamDao.addDream(dream) #MongoDB Call to Insert Data 
        bs = dumps(dream,json_options=RELAXED_JSON_OPTIONS) #Now dream has Response Which will have ObjectId
        return json.loads(bs) , 201

The line TypeError: Object of type InsertOneResult is not JSON serializable describes the problem. insert_one() returns an InsertOneResult object , which contains the inserted ID (as @styvane's comment suggested) as well as a flag indicating whether the write was ack'd by the database. Other operations have similar result objects, and none of them are JSON serializable.

A future version of Flask-PyMongo may add helpers to support this, you can follow https://github.com/dcrosta/flask-pymongo/issues/62 to add ideas and suggestions.

from flask_pymongo import Pymongo
import json
import pandas as pd

user = pd.DataFrame(user)

mongo.db.users.insert_one({'email':json.loads(user[0].to_json(orient='index')),                            
                       'password':json.loads(user[1].to_json(orient='index'))})

This will throw up errors if your objects are already json. If they aren't though, it'll turn them into json and load them all in one go.

It seems that what you post to server is not a valid json object. So you should debug what you got.

class UsersResource(Resource):

    def post(self):
        # debug
        print("request.args is {}".format(request.args))
        print("request.form is {}".format(request.form))
        print("request.data is {}".format(request.data))

        req = request.get_json()

        user = {
            "email": req.get("email"),
            "password": req.get("password")
        }

        result = mongo.db.users.insert_one(user)

        return jsonify(result)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM