Search code examples
pythonmongoengineflask-mongoengine

MongoEngine - Call function only when document is being created or specific field being set?


I'm not sure what is the best/pythonic way of having a User document that automatically hashes its password upon creating.

Consider the following mongoengine model :

class User(Document):
    email = EmailField(required=True, primary_key=True)
    name = StringField(required=True)
    pswd = StringField(required=True)

    def check_pswd(self, password):
        return verify_password(password, self.pswd)

    def hash_pswd(self, password):
        return hash_password(password):

    def save(self, *args, **kwargs):
        self.pswd = self.hash_pswd(self.pswd)
        super().save(*args, **kwargs)

When I create a user, it works fine :

user = User()
user.email = '[email protected]'
user.pswd = 'password'
user.name = 'User'
user.save()

Buf if I update it, it will double hash its password, I don't want that.

#User wants to change his name
user = User.objects(email='[email protected]')
user.name = 'User 2'
user.save()

Is there a way for me to hash its password only when creating or changing the password?

Or maybe I should delegate the responsibility of hashing the password to the View/Controller?


Solution

  • I am not giving you the code sample, you can use Document.update() method which will update the fields that only has changed.

    If you still wanna use the save method, Then you can create a logic along the following lines.

    1. Check if the user has changed the password(by comparing the existing stored hash and new hash if any)
    2. If the new hash is different then user has changed the password in that case you can push an Document.update method.
    3. If not, don't call update on that field.

    Alternatively update in Mongoengine accepts a iterable, so you can simply create a list or a dictionary object and convinently choose to Remove the password hash field from it.

    As for who should execute this i.e View / Controller, its a Design decision but I would rather keep Representation (GUI / Front End) seperate from logic, so I would delegate this to the controller or even more Intrinsically to the Object who is responsible for handling all database/network related tasks, this way it would be isolated and easy to modify. And would not complexify or slow the View objects process / thread

    Link for update using an iterable like Dict. stackoverflow question for Mongoengine update using iterable

    Link discussing save methods deprecation (The Maintainer Has commented below as save method not being deprecated, so trust him/her and proceed at will on this link) Mongoengine save method deprecated?

    Link for update method in mongoengine. Mongoengine Atomic Update