oh, yeah for that recipe you'd have to use a flag on the mapper()  
called "batch=False".    But don't use that, its inefficient.

So you can also create your type to detect a special value from the  
mapper extension:

def before_insert(self, ....):
        instance.password = (instance.password, True)

class MyType(...):
        ...

        def process_bind_param(self, value, dialect):
                if isinstance(value, tuple):
                        return hasher.create(value[0], value[1])
                ....


But since this is really an instance-level business rule, a straight  
descriptor and no custom type is definitely how I'd go on this one.



On Dec 21, 2008, at 6:47 PM, Kless wrote:

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