On Jul 25, 2013, at 2:44 AM, Matthew Pounsett <[email protected]> wrote:
>
> I have a class with 'start' and 'finish' attributes which are DateTime
> columns. I'm trying to create a hybrid property 'duration' which returns the
> delta as a datetime.timedelta object. This is working fine for the instance
> attribute, but I can't seem to get it to work for the class expression.
>
> This is close, and works, except that the clas expression returns an integer:
>
> @hybrid_property
> def duration(self):
> if self.finish:
> return self.finish - self.start
> else:
> return timedelta(0)
>
> @duration.expression
> def duration(cls):
> return func.strftime('%s', func.coalesce(cls.finish, cls.start)) -\
> func.strftime('%s', cls.start)
>
> As soon as I try to wrap that to convert it to the python object, I get an
> exception:
>
> @duration.expression
> def duration(cls):
> return timedelta(
> func.strftime('%s', func.coalesce(cls.finish, cls.start)) -
> func.strftime('%s', cls.start)
> )
>
> TypeError: unsupported type for timedelta days component: _BinaryExpression
"func.xyz() - func.qpr()" doesn't provide an integer in Python, it is a SQL
construct that can be evaluated by the database, not unlike if you just had a
"duration" column on your table, you'd say "Column('duration', Interval)".
"Interval" here is actually the SQL datatype we'd be looking to deal with.
So in theory, if relational backends were consistent about date arithmetic
you'd want to say:
from sqlalchemy import type_coerce, Interval
type_coerce(
func.strftime('%s', func.coalesce(cls.finish, cls.start)) -
func.strftime('%s', cls.start),
Interval
)
But your backend isn't doing this; if you were using Postgresql for example, it
should be returning a timedelta() already. So perhaps this is MySQL. you'd
need to make a TypeDecorator that receives this integer and does what you want
with it. You'd emulate the "Epoch" decorator currently illustrated at
http://docs.sqlalchemy.org/en/rel_0_8/core/types.html#sqlalchemy.types.TypeDecorator:
class MyIntervalType(types.TypeDecorator):
impl = types.Integer
def process_bind_param(self, value, dialect):
return value.days
def process_result_value(self, value, dialect):
return datetime.timedelta(days=value)
so fully:
from sqlalchemy import type_coerce, Interval
type_coerce(
func.strftime('%s', func.coalesce(cls.finish, cls.start)) -
func.strftime('%s', cls.start),
MyIntervalType
)
>
> Is there something I need to do to convert the return value from func() in
> order to be able to work with it? Or, is what I'm attempting even possible?
>
> Thanks!
>
> --
> You received this message because you are subscribed to the Google Groups
> "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> To post to this group, send email to [email protected].
> Visit this group at http://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>
--
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.