On Thu, 2003-05-22 at 11:02, Luke Opperman wrote:
> > What in plain python classes normally goes in __init__ should go in
> > the _init method for SQLObject subclasses. _init seems to be called
> > by SQLObject's new method.
>
> A little misunderstanding here. Off the top of my head this problem will occur
> for any system that may transparently return an internally cached object on
> 'creation'. You're free to do whatever you please in an SQLObject __init__
> method, so long as you realize it will be called whether this is a new object
> (Person.new()), an exisiting row (Person(12)), or an existing object
> (Person(12) that returns a cached value). It seems to me that 'typical' python
> __init__ stuff is only relevant to the first case, and that any ORM system
> should provide ways to override the first two separately (for SO, .new and
> ._init), and probably probably hide the third case from users. But we can
> probably agree that this behavior is not 'normal' python behavior, that it
> would be nice if __init__ could be used for the first case... but what do you
> do for the second case?
Yes, _init is just a workaround for __init__ being called on a cache
hit. I don't know why Python is designed like this -- it seems totally
dumb to me. object.__new__ should call __init__, though maybe for some
reason people wanted to get at the object before __init__, but after
instantiation (which is what you currently can do).
It's just dumb and annoying, and this is the workaround. The only
alternative is to rewrite __init__ to _init in the metaclass, but then
(for instance), calling the superclass's __init__ will fail.
> Note that the call cycle in python (SQLObject) is:
>
> for Person.new():
> new
> __new__ (explicit in new)
> __init__ (implicit after __new__)
> set (explicit in new)
> _init (explicit in new/finishCreate)
Hmmm... maybe that's a little funny.
> > 2. Possible Alternative Approach
> > --------------------------------
> >
> > A possible alternative approach makes a major change in the look and
> > feel inassuch that persistence methods (insert, update, ..) need to be
> > called explicitly.
> >
> > * same goes for resolution of collisions in concurrancy control. I
> > don't see a way of hiding these issues from the application
> > programmer
>
> Agreed. I suppose this directly relates to my problem with any foreignKey
> access possibly causing an SQLObjectNoFound error; with constraints and
> collisions, any attribute access could conceivably need to be safe-guarded.
If you turn off column caching, yes. With caching (_cacheValues), then
potentially all input could be validated/converted when it was fetched.
But I would expect the checks run on input from the database will be
pretty light -- it's setting attributes that's more likely to cause an
exception.
It would be possible to batch setting and getting. Setting, for
instance, is cached on a call to new() creation (based on
_SO_creating). That could be generalized slightly, so that there was a
sync() method (or update() or insert() or something). That wouldn't be
a big change. It might look like:
obj = SomeObject(12)
obj.batch()
obj.a = 10
obj.c = 20
obj.update()
Maybe batch (or probably another name) could take arguments that would
also get it to handle locking.
For getting, the equivalent to obj.update() might be obj.sync(), which
would refetch the object from the database. This all makes sense mostly
if you are using _cacheValues, but not if you are caching instances.
Ian
|