Thank you for detailed answer. Here are any thoughts:
1) The before_insert was being omitted while I was inserting records using an insert statement --that's logical because it was bypassing the ORM--. 2) It's necessary to use *session.commit()* after of each record because else it will have the value of 'instance.admin' of the last record which will be used for all records to commit. 3) I believe that it isn't necessary use *after_insert*. On 21 dic, 17:00, Michael Bayer <mike...@zzzcomputing.com> wrote: > On Dec 21, 2008, at 6:53 AM, Kless wrote: > > I'm trying to build a custom type [1] to manage the bcrypt hashes [2]. > > > --------------- > > from bcrypt_wrap import password > > from sqlalchemy import types > > > class Bcrypt(types.TypeDecorator): > > """Stores a bcrypt hash of a password.""" > > impl = types.String #(60) > > hasher = password.Password() > > > def process_bind_param(self, value, dialect): > > return hasher.create(value) > > --------------- > > > And I've any doubts: > > > 1) Since that the hash length is always 60, is there that use the > > next? > > impl = types.String(60) > > > 2) The bcryptWrap API [3] (line 53) lets call to 'create' with > > arguments 'cost' and 'admin' (boolean). Then, > > > a) I would that the cost could be passed from the column definition, > > i.e. > > password = sqlalchemy.Column(types.Bcrypt, cost=12) > > or > > password = sqlalchemy.Column(types.Bcrypt(cost=12)) > > > b) This would be more hard, but I would to pass the 'admin' argument > > when an object is created > > > u = model.User() > > u.login = u'foo' > > u.password = u'bar' > > u.admin = True > > > And sou could be call: > > return hasher.create(value, admin=True) > > the TypeDecorator's __init__ method just calls the impl class > immediately, so the best approach is like: > > class Bcrypt(types.TypeDecorator): > """Stores a bcrypt hash of a password.""" > impl = types.String > hasher = password.Password() > > def __init__(self, cost): > self.cost = cost > types.TypeDecorator.__init__(self, 60) > > def process_bind_param(self, value, dialect): > return hasher.create(value) > > then you can instantate like: > > Column('foo', Bcrypt(cost=12)) > > For b, the type object and the ExecutionContext which ultimately calls > its process_bind_param method are unaware of the ORM or the ORM- > specific context in which its called during INSERT/UPDATE. If you > wanted to keep the logic within your type like that you'd have to > integrate to a thread-local variable that is configured within an ORM > plugin, something like: > > hasher_status = threading.local() > > class MyMapperExt(MapperExtension): > def before_insert(self, ...): > hasher_status.admin = instance.admin > > def after_insert(self, ...) > del hasher_status.admin > > mapper(MyClass, table, ext=MyMapperExt) > > class Bcrypt(types.TypeDecorator): > ... > > def process_bind_param(self, value, dialect): > return hasher.create(value, getattr(hasher_status, 'admin', > False)) > > Alternatively, you could keep the logic within the ORM using either a > "valdiator" or a descriptor, as described > athttp://www.sqlalchemy.org/docs/05/mappers.html#changing-attribute-beh... > . It depends on if you'd like your Bcrypt type to work with direct > SQL expression language use or not. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~----------~----~----~----~------~----~------~--~---