On Jan 27, 5:08 pm, Ole Martin Maeland <[email protected]> wrote:
> instead of default=now use default = request.now
>
> also change default = now in modified_on to update=request.now
>
> regards
> Martin
>
You are right - that works because request.now is a datetime value.
The point is that it should be possible to pass a function as a
field's default that yields a new value for each insert (see other
ORMS, e.g. Django).
uuid.uuid4 is a good example and it actually works out of the box:
...
Field('uuid', length=64, default=uuid.uuid4),
...
Multiple inserts for the same request should get unique uuids of
course, so we need a function here.
Some other functions like "datetime.datetime.now" and most probably
others don't work the same way leading to inconsistent behaviour.
Cheers,
Bernd
> On Wed, Jan 26, 2011 at 1:36 AM, Bernd Rothert <[email protected]>wrote:
>
>
>
>
>
>
>
>
>
> > A table definition from the DAL chapter of the Web2py book:
>
> > db.define_table('person',
> > Field('uuid', length=64, default=uuid.uuid4()),
> > Field('modified_on', 'datetime', default=now),
> > Field('name'),
> > format='%(name)s')
>
> > "now" usually contains the current datetime from request.now and
> > that's fine but the default for "uuid" would be identical for all
> > inserts. Although the example doesn't use the default so it is not a
> > problem there.
>
> > If you omit the parenthesis behind "default=uuid.uuid4()" and simple
> > pass the uuid4 function as the default it works as expected - the
> > default is evaluated at insert time and yields a fresh uuid for each
> > new record. I assume this is the intended behaviour although I
> > couldn't find it documented(!?).
>
> > Strangely replacing "default=now" in the same way with e.g.
> > "default=datetime.datetime.now" does not work:
>
> > now=datetime.datetime.now
> > db.define_table('person',
> > Field('uuid', length=64, default=uuid.uuid4),
> > Field('modified_on', 'datetime', default=now),
> > Field('name'),
> > format='%(name)s')
>
> > db.person.insert(name='Ernie')
> > db.person.insert(name='Bert')
>
> > db(db.person).select()
> > >>> ValueError: invalid literal for int() with base 10: '<built'
>
> > Umm,...
>
> > db.executesql(db(db.person)._select())
> > >>> [(1,
> > u'b35cc052-3800-42a9-b7eb-bb9bc8ada271',
> > u'<built-in method now of type object at 0x37c520>',
> > u'Ernie'),
> > (2,
> > u'003ab438-f3aa-4474-8c24-b07d85406930',
> > u'<built-in method now of type object at 0x37c520>',
> > u'Bert')]
>
> > (only works with Sqlite - MySQL would throw an error earlier)
>
> > I think this check in BaseAdapter.represent (dal.py) is the culprit:
>
> > def represent(self, obj, fieldtype):
> > if type(obj) in (types.LambdaType, types.FunctionType):
> > obj = obj()
>
> > print type(datetime.datetime.now) in (types.LambdaType,
> > types.FunctionType)
> > >>> False
>
> > This version lets you use any callable for generating "dynamic"
> > default values (plus it's 3-4 times faster):
>
> > def represent(self, obj, fieldtype):
> > if callable(obj):
> > obj = obj()
>
> > I hope this doesn't cause any side effects - at least I could not find
> > any (at this late/early hour)...
>
> > Thanks
>
> --
> Hilsen
> Ole Martin
> Mob: 95227471