MongoEngine/mongoengine

Document not working well with Fastapi & Pydantic

Opened this issue · 0 comments

I am trying to integrate Mongoengine ORM with Fastapi but am experiencing an issue when trying to return routes:

demo model:

class ModelName(Document):
    name = StringField(required=True)
    title = StringField(required=True)

route integration:

router = APIRouter()

@router.get("")
def some_route():
    return ModelName.objects()

what is returned:

{
  "_cls": "ModelName"
}

When trying to fix the issue, I realized that pydantic tries serializing the document returned but fails due to the __dict__ method not returning serialized data properly. I also tried working with `.to_mongo()', but pydantic failed to serialize the ObjectID fields.

I read some posts on stack overflow and the suggested solution was to return .to_json() which can be returned as a JSON string, but due to the number of routes making use of this, it would be a hassle to update every single route to return .to_json, also the frontend dev would have to then parse all responses from the API back to JSON which is unnecessary

I ended up having to create an abstract document with a fix to the __dict__ method:

class CustomDocument(Document):
    meta = {"abstract": True}

    @property
    def __dict__(self):
        data = {}  # initialize an empty dictionary to store the converted data

        # iterate over key-value pairs in the to_mongo() result
        for key, value in self.to_mongo().items():
            # check if the value is an ObjectId and convert it to a string if necessary
            value = str(value) if isinstance(value, ObjectId) else value

            # update the dictionary with the key-value pair
            data.update({key: value})

        return data

class ModelName(CustomDocument):
    name = StringField(required=True)
    title = StringField(required=True)

returned:

[
    {
        "_id": "659be429314d05a57b5e7dad"
        "name": "some text",
        "title": "some text"
    }
]

I'd love to know if there is already a solution for this, or possibly one already being worked on. If there isn't, I'll create a pull request with a possible fix to make things easier.

Thank you.