Embedded Documents issue with MongoEngine

I am using MongoDB with Flask-MongoEngine as my ORM component to my web app.

I have structured the User document schema like so:

from ..core import db

class UserComics(db.EmbeddedDocument):
    favorites = db.SortedListField(db.StringField(), default=None)

class UserSettings(db.EmbeddedDocument):
    display_favs = db.BooleanField(default=False)
    default_cal = db.StringField(default=None)
    show_publishers = db.ListField(db.StringField(), default=None)

class UserTokens(db.EmbeddedDocument):
    refresh_token = db.StringField(default=None)
    access_token = db.StringField(default=None)
    expire_time = db.StringField(default=None)

class User(db.Document, UserMixin):
    # Save User document to this collection
    meta = {'collection': 'users_test'}

    userid = db.StringField()
    full_name = db.StringField()
    first_name = db.StringField()
    last_name = db.StringField()
    gender = db.StringField()
    birthday = db.StringField()
    email = db.EmailField()
    friends = db.ListField(db.StringField())
    date_creation = db.DateTimeField()
    last_login = db.DateTimeField()
    favorites = db.EmbeddedDocumentField(UserComics)
    settings = db.EmbeddedDocumentField(UserSettings)
    tokens = db.EmbeddedDocumentField(UserTokens)

However, When creating a new user like this (I have left out lines…):

def create_new_user(resp):
    newUser = User()
    ....
    newUser.settings.default_cal = resp['calendar']
    ....
    newUser.save()
    return

I run into this error:

AttributeError: ‘NoneType’ object has no attribute ‘default_cal’

It seems to me that I am not using MongoEngines Embedded documents correctly but I do not know where I am going wrong.

Any help would be greatly appreciated!

Best answer

Well you just have to create an embedded document object of the particular class, and then use it with the main document class, like so:

new_user = User()
user_settings = UserSettings()
user_settings.default_cal = resp['calendar']
new_user.settings = user_settings
# more stuff
new_user.save()

Note: Creating a new object only for the main document, does not automatically create the corresponding embedded document object(s), but while reading data ofcourse the case is different.

Edit:

As tbicr mentions below, we can also do this:

settings = db.EmbeddedDocumentField(UserSettings, default=UserSettings)

while declaring the field, that way we won’t need to create the object as given in the first example.