Hi Luke,
thanks for the explanations. Some responses below..
On Thu, 22 May 2003 11:02:36 -0500
Luke Opperman <lu...@me...> wrote:
> 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'.
I see cases where a _init hook is necessary. Say you store a derived
attribute (that is redundant) but you don't want to put it in the
db--then, everytime you get the object from the db, you have to
recompute that derived one.
But apart from these special cases, I don't necessarily believe that
you really need it... Normal __init__ should do.
> 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).
But what happens if I give it arguments other than self? The only
example that comes to mind quickly is
class Balanace(object):
def __init__(self, amount, currency):
amountInLocalCurrancy=amount * factor(currency)
self.amount = amountInLocalCurrancy
While amount would typically be stored in the db, currency is just for
one time use and thrown out..
> 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?
In the second case I do s.th. along the following lines:
curs.execute('SELECT id, name, age, ... FROM person_table ' +\
'WHERE id = %s', requestedId)
columnVals = curs.fetchone()
p = instanceOfDesiredClass.__new__(instanceOfDesiredClass)
p.name = columnVals[1]
p.age = columnVals[2]
etc.
As I wrote in the separate message, I don't think this calls __init__
> 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)
>
>
> for Person(12) (not cached):
> __new__
> _init (explicit in __new__)
> __init__ (implicit after __new__)
>
> for Person(12) (cached):
> __new__
> __init__ (implicit after __new__)
I must say I'm puzzled about this implicit __init__. Can you
enlighten me on that?
> > 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.
> Not sure how I feel about that. While I initially don't like explicit storage
> commands, I'm also not excited about how to deal with the above.
I imagine that a typical use case is that some piece of code assigns
vlues attribute by attribute and once done, commits the changes.
Since there is no way in knowing automatically, when an application
programmer wants to commit, then there needs to be a
persistence-related command anyhow. Call it storeNcommit or
whatever--but I don't see a way of doing this all implicitly.
This is to say that if you want to do a dbms app without transactions,
it would work. But that kind of beats the purpose of using a dbms in
the first place (at least for me).
> > * I believe (haven't verified) that it should be possible for users
> > to define properties in lieu of just normal __dict__ items without
> > any adverse effects. (I reason that the use of getattr and
> > setattr by the middleware works equally well)
>
> Just to be clear, there's no danger in setting your own properties in
> SQLObject. SQLObject tries to help by letting you just define _get/_set and
> get a property generated, but manually created properties will just be
> ignored.
Agreed, you can do that. But the way you do that is not the normal
python way--and this is exactly my point. If we manage to get
SQLObject work as much as possible in the normal python way, it is
easy to use (some people would call that "no magic") and learn and it
is easy to use SQLObject with all kind of pre-existing code that now
needs persistence. I personally believe that business logic should be
written without a (at least specific) persistence method in mind and
then made persistent in a second step. The more "magic", the more
rewriting and surprises..
> I think the key thing to think about here is how collisions or constraints
> affect using SQLObject at the attribute level.
And probably transactions (see my point above that I don't see that
you get away without explicit persistence commands when using them).
cheers
--b
|