Search code examples
pythonserializationpickleumongo

How to serialize umongo documents


Let's say I have the following example:

from datetime import datetime
import dill
from pymongo import MongoClient
from umongo import Instance, Document, fields, validate

db = MongoClient().test
instance = Instance(db)

@instance.register
class User(Document):
    email = fields.EmailField(required=True, unique=True)
    birthday = fields.DateTimeField(validate=validate.Range(min=datetime(1900, 1, 1)))
    friends = fields.ListField(fields.ReferenceField("User"))

    class Meta:
        collection = db.user

User.ensure_indexes()

goku = User(email='[email protected]', birthday=datetime(1984, 11, 20))
goku.commit()

found_goku = User.find_one({"email": '[email protected]'})
with open("dumped.dil", "wb") as out_file:
    dill.dump(found_goku, out_file)

This results in the following error on dill.dump:

_pickle.PicklingError: Can't pickle <Implementation class 'tests.test_serialize_umongo.User'>: it's not found as tests.test_serialize_umongo.User

I understand that I can not simply pickle a User because I can not pickle the database instance. I want to pickle a user to a Dict using umongo's dump and overriding __getstate__, but I do not know how to get around this it's not found aserror.


Solution

  • If I understand you correctly, I believe what you're looking for is the following. In essence, we're using the document's own dump() method to pass the serialized document as the user to be pickled. The only difference here is the last line: dill.dump(found_goku.dump(), out_file):

    from datetime import datetime
    import dill
    from pymongo import MongoClient
    from umongo import Instance, Document, fields, validate
    
    db = MongoClient().test
    instance = Instance(db)
    
    @instance.register
    class User(Document):
        email = fields.EmailField(required=True, unique=True)
        birthday = fields.DateTimeField(validate=validate.Range(min=datetime(1900, 1, 1)))
        friends = fields.ListField(fields.ReferenceField("User"))
    
        class Meta:
            collection = db.user
    
    User.ensure_indexes()
    
    goku = User(email='[email protected]', birthday=datetime(1984, 11, 20))
    goku.commit()
    
    found_goku = User.find_one({"email": '[email protected]'})
    with open("dumped.dil", "wb") as out_file:
        dill.dump(found_goku.dump(), out_file)