3

I am creating SQLAlchemy class that represents user credentials.

I want to have field password that stores hashed value of password. Therefore I would like to override its behavior the following way:

  1. When assigned credentials.password = value it actually stores hash of the value

  2. When comparing credentials.password == value it actually compares with hash of the value

I have read the following part of SQLAlchemy documentation http://docs.sqlalchemy.org/en/rel_0_7/orm/mapper_config.html#using-descriptors-and-hybrids

And I think I do understand how to solve the issue number 1.

I am however unsure, how to do second point. Is there a way to do it the safe way (without breaking SQLAlchemy)?

Here is the example model:

class Credentials(Base):
    __tablename__ = 'credentials'

    id = Column(Integer, primary_key=True)

    _password = Column('password', String)

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

    @password.setter(self):
        self._password = hash(self._password)
Samuel Hapak
  • 6,950
  • 3
  • 35
  • 58
  • Could you post your current model and small testcase? – plaes Aug 31 '12 at 09:35
  • By testcase I mean a small self-contained script, like here http://stackoverflow.com/questions/9140015/how-to-get-rows-which-match-a-list-of-3-tuples-conditions-with-sqlalchemy/9140163#9140163 – plaes Sep 01 '12 at 06:06

1 Answers1

2

For comparing, since you can't un-hash the password, you would need to create a custom type for the Column class, that over-rides the eq operator:

class MyPasswordType(String):
    class comparator_factory(String.Comparator):
        def __eq__(self, other):
            return self.operate(operators.eq, hash(other))

Have a look at: http://docs.sqlalchemy.org/en/latest/core/types.html#types-operators

And http://docs.sqlalchemy.org/en/latest/core/types.html#sqlalchemy.types.TypeEngine.comparator_factory

To set you just need to pass in the value:

@password.setter
def password(self, value):
    self._password = hash(value)    
Adam Morris
  • 8,265
  • 12
  • 45
  • 68