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
-~----------~----~----~----~------~----~------~--~---

Reply via email to