Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoengine 0.8.0 breaks my custom setter property in models

in Mongoengine 0.7.10, I can still do things like:

class User(db.Document):
    email = db.EmailField(unique=True, required=True)
    _password = db.StringField(max_length=255, required=True)

    @property
    def password(self):
        return self._password

    @password.setter
    def password(self, password):
        self._password = bcrypt.generate_password_hash(password)
user = User(email='[email protected]', password='12345')

However, the above code breaks in 0.8.0: ValidationError: ValidationError (User:None) (_password.Field is required: ['User'])

It seems that MongoEngine doesn't recognised my custom password setter during initiation. I have to manually write these to fix it:

user = User(email='[email protected]')
user.password='12345'

This is probably due to the below changes(from Mongonengine 0.8 upgrading notes):

Previously, if you had data the database that wasn’t defined in the Document definition, it would set it as an attribute on the document. This is no longer the case and the data is set only in the document._data dictionary:

I would like to know if this is intended or is it a bug in MongoEngine? What is the best practice to write the custom property setter in my model?

like image 274
Jeffery Li Avatar asked Jun 02 '13 09:06

Jeffery Li


2 Answers

Try this code:

class User(db.Document):
    email = db.EmailField(unique=True, required=True)
    _password = db.StringField(max_length=255, required=True, db_field='password')

    def __init__(self, *args, **kwargs):
            db.Document.__init__(self, *args, **kwargs)

            if 'password' in kwargs:
                self.password = kwargs['password']

    @property
    def password(self):
        return self._password

    @password.setter
    def password(self, password):
        self._password = bcrypt.generate_password_hash(password)
user = User(email='[email protected]', password='12345')

It works for me.

like image 100
hamidfzm Avatar answered Oct 17 '22 07:10

hamidfzm


You should use the Document clean function, described in the mongoengine documentation.

class User(db.Document):
    email = db.EmailField(unique=True, required=True)
    password = db.StringField(max_length=255, required=True)

    def clean(self):
        if not hashed(self.password):
            self.password = bcrypt.generate_password_hash(self.password)

    def hashed(self, password):
        return  # boolean check of whether the password is already hashed

user = User(email='[email protected]', password='12345')
user.save()

Every time you call user.save(), it will now check if your password resembles a hashed value, and if not, hash it before updating the database.

like image 24
Tristan Brown Avatar answered Oct 17 '22 06:10

Tristan Brown