Mongoengine 0.8.0在模型中打破了我的自定义setter属性

问题描述 投票:8回答:4

在Mongoengine 0.7.10中,我仍然可以做以下事情:

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')

但是,上面的代码在0.8.0中断:ValidationError: ValidationError (User:None) (_password.Field is required: ['User'])

似乎MongoEngine在启动期间无法识别我的自定义密码设置器。我必须手动编写这些来修复它:

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

这可能是由于以下变化(来自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:

我想知道这是有意还是MongoEngine中的错误?在我的模型中编写自定义属性setter的最佳做法是什么?

python mongoengine
4个回答
5
投票

试试这段代码:

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')

这个对我有用。


1
投票

它不是一个错误 - 它可以清除其他一些错误,并且是升级文档中提到的预期操作。但是,这对这种情况没有好处!

我认为创建密码哈希的自定义方法会更好,例如:set_password check_password等...

过去有过PasswordField实现,我将添加到extras-mongoengine中。


1
投票

您应该使用Document clean函数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()

每次调用user.save()时,它现在将检查您的密码是否类似于散列值,如果没有,则在更新数据库之前对其进行散列。


0
投票

这不是一个优雅的解决方案,但我真的希望在模型级别上使用安全密码散列而不是在一个或多个视图中将我的表单直接推送到模型中。只需将password重命名为_password,运行mongoengine文档验证并设置self._password

class User(db.Document):
    """User model."""

    username = db.StringField(max_length=50, required=True, unique=True)
    _password = db.StringField(max_length=255, required=True)

    def __init__(self, *args, **kwargs):
        kwargs['_password'] = kwargs.pop('password')
        db.Document.__init__(self, *args, **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)
© www.soinside.com 2019 - 2024. All rights reserved.