Please see my comments below.

Regards,
Rob


On 3 August 2010 14:05, Michael Bayer <mike...@zzzcomputing.com> wrote:

>
> On Aug 3, 2010, at 7:47 AM, Robert Sudwarts wrote:
>
> Hi Michael,
>
> I'm guilty of two over-simplifications in the code used in my example...
>
> Firstly, the substring property/column (with which I had a problem) applies
> to a subclass (using "joined table inheritance") and the variable to which
> it applies is specified in its parent class.  Hence, I started by assuming
> that I'd need something along the lines of:
>
> class Parent(Base):
>        my_string
>
> class Child(Parent):
>        ....
>        @classproperty/@property/ some other decorator
>        def my_substr(cls):
>               return  column_property ( .... cls.my_string .... )
>
> However, trying this (ie the classproperty/column_property within Child),
> returned   <sqlalchemy.orm.properties.ColumnProperty object ...> (the error
> I referred to in my original question)
> I'm confused about why I'm not able to get this (or some variation of it)
> to work.  Is this indeed possible?
>
>
>
> Just yesterday, in response to this, I added a line of code such that if
> you specifically use @classproperty on the declarative class (i.e. not a
> mixin), declarative will call it to figure out what it returns and configure
> it normally- previously, if the attribute were not directly a
> MapperProperty, it would be ignored.    However, I couldn't think of any use
> case that this is actually useful for.  I thought that, it might be a way to
> establish a column-oriented property "late", so that you could get around
> imports not being available.   At the moment, it's not useful for that,
> because declarative calls the attribute as soon as the class is created, and
> whatever imports that werent available to the class declaration are still
> not present.
>

Ah!  Right!! I hadn't understood that ... I assumed (wrongly) that I'd have
to 'instantitate'  'cls' somehow using a decorator+function: def blah(cls):
...

I didn't realise that I could simply use "Parent.my_str"

>
> So what are you gaining above, if it were working in 0.6.3, by using
> @classproperty instaed of "my_substr = column_property()" ?  Anywhere you
> reference "cls" in your function, you'd just reference whatever is local, or
> part of Parent.
>
>
> Looking at the documentation (as a consequence of the error), my I was
> drawn to the syntax used in the section on 'mixins' (ie, the column_property
> defined externally).
>
> My second over-simplification regards the the function itself.  The
> function I'm trying to use [which I'm aware doesn't translate easily to
> sqlite], is:
>   func.substr(cls.my_str, func.instr(cls.my_str, " ")+1, 2)
>
> Now, thanks to your response, I now actually have the following *working*
> (using mysql):
>
> class MySubStr(object):
>  @classproperty
> def my_substr(cls):
> return column_property(
>                         func.substr(cls.my_string,
> func.instr(cls.my_string, " ")+1, 2)
>                        )
>
> However, replacing:
>     func.substr(cls.my_string, func.instr(cls.my_string, " ")+1, 2)
> with (in order to attach a label to the column):
>     select([func.substr(cls.my_string, func.instr(cls.my_string, " ")+1,
> 2)]).label('exch_code')
>
> Gives me -- AttributeError: 'NoneType' object has no attribute '_keymap'
>  (full traceback below).
>
>
> That's a really weird error.   It suggests that the result is not one that
> returns any rows, not like its a SELECT with zero rows, rather, it is
> perceived by SQLite as something like an INSERT that isn't meant to return
> any rows, and there's no cursor.description.   The ResultProxy is then
> failing ungracefully which is surprising (looking at the current source it
> appears we need to cover this situation).     It would be interesting to try
> out the raw SQL to see what is produced, since the statement is definitely a
> SELECT - pysqlite should raise an error if it doesn't like the SQL, or give
> us a cursor.description.
>

Just to be clear -- this error/traceback was produced with MySQL as the
database....

>
> Anyway, your column_property() doesn't need the select() here, you can just
> call .label() on the func.substr() result, but also, you don't really need
> the label() in here either (unless I'm missing something? )
>
> Again ... I hadn't realised that I could apply .label() to the directly to
'func' ... I've changed this and it works.

>
> Apologies for my earlier over-simplification (and my late response!).  And
> I hope that what I've responded with is clear!!
>
> Regards,
> Rob
>
>
>
>
>
> -------------------------------------------------------------------------------------------------------------------------
> /home/robertsudwarts/tg2env/lib/python2.6/site-packages/SQLAlchemy-0.6.3-py2.6.egg/sqlalchemy/orm/query.pyc
> in one(self)
>    1520
>    1521         """
> -> 1522         ret = list(self)
>    1523
>    1524         l = len(ret)
>
> /home/robertsudwarts/tg2env/lib/python2.6/site-packages/SQLAlchemy-0.6.3-py2.6.egg/sqlalchemy/orm/query.pyc
> in instances(self, cursor, _Query__context)
>    1667                     break
>    1668             else:
> -> 1669                 fetch = cursor.fetchall()
>    1670
>    1671             if custom_rows:
>
> /home/robertsudwarts/tg2env/lib/python2.6/site-packages/SQLAlchemy-0.6.3-py2.6.egg/sqlalchemy/engine/base.pyc
> in fetchall(self)
>    2381
>    2382         try:
> -> 2383             l = self.process_rows(self._fetchall_impl())
>    2384             self.close()
>    2385             return l
>
> /home/robertsudwarts/tg2env/lib/python2.6/site-packages/SQLAlchemy-0.6.3-py2.6.egg/sqlalchemy/engine/base.pyc
> in process_rows(self, rows)
>    2364         process_row = self._process_row
>    2365         metadata = self._metadata
> -> 2366         keymap = metadata._keymap
>    2367         processors = metadata._processors
>    2368         if self._echo:
>
> AttributeError: 'NoneType' object has no attribute '_keymap'
>
>
>
>
>
>
>
>
>
> On 2 August 2010 19:42, Michael Bayer <mike...@zzzcomputing.com> wrote:
>
>>
>> On Aug 2, 2010, at 1:40 PM, Michael Bayer wrote:
>>
>> >
>> > On Aug 2, 2010, at 12:19 PM, Robert Sudwarts wrote:
>> >
>> >> Hi,
>> >>
>> >> I'm having trouble understanding the correct syntax to be used with
>> Declarative and a column property.
>> >> The select statement I'm using is:
>>  select([func.substr(my_table.c.my_string, 2, 3)]).label(my_substr'),
>> deferred=True
>> >> And (as per the docs using the expanded syntax, this works as expected.
>> >>
>> >> With the Declarative syntax, I've tried:
>> >>
>> >> from sqlalchemy.util                 import classproperty
>> >> from sqlalchemy.orm                ..., column_property
>> >>
>> >> class MySubstr(object):
>> >>      @classproperty
>> >>      def my_substr(cls):
>> >>              return column_property(
>> >>
>> select([func.substr(cls.my_str, 2, 3)]).label('my_substr')
>> >>                                                )
>> >>
>> >> class MyTable(Base, MySubstr):
>> >>    .....
>> >>
>> >> and then expect to be able to call a record in MyTable and return its
>> "my_substr", however, all I'm getting is a representation of the object ...
>> >> eg <sqlalchemy.orm.properties.ColumnProperty object at 0xa4951cc>  and
>> no apparent way of seeing its value.
>> >
>>
>> oh and also, you don't need the select() here either:
>>
>> class MyTable(Base):
>>   __tablename__ = 'foo'
>>   id = Column(Integer, primary_key=True)
>>   my_str = Column('my_str', String)
>>    my_substr = column_property(func.substr(cls.my_str, 2, 3))
>>
>>
>>
>>
>> > I see nothing wrong with the example, the only potential glitch is that
>> "my_str" needs to have a name assigned up front.  You didn't illustrate that
>> part here, so FYI it would be extremely helpful if you could attach fully
>> working examples.  In this case the example is:
>> >
>> > from sqlalchemy import *
>> > from sqlalchemy.ext.declarative import declarative_base
>> > from sqlalchemy.util                 import classproperty
>> > from sqlalchemy.orm import column_property, sessionmaker
>> >
>> > Base = declarative_base()
>> >
>> > engine = create_engine('sqlite://', echo=True)
>> >
>> > class MySubstr(object):
>> >    @classproperty
>> >    def my_substr(cls):
>> >        return column_property(
>> >                               select([func.substr(cls.my_str, 2,
>> 3)]).label('my_substr')
>> >                          )
>> >
>> > class MyTable(Base, MySubstr):
>> >    __tablename__ = 'foo'
>> >    id = Column(Integer, primary_key=True)
>> >    my_str = Column('my_str', String)
>> >
>> >
>> > Base.metadata.create_all(engine)
>> >
>> > sess = sessionmaker(engine)()
>> > m1 = MyTable(my_str='some string')
>> > sess.add(m1)
>> > sess.commit()
>> >
>> > print m1.my_substr
>> >
>> > and it works fine.
>> >
>> >
>> >
>> >>
>> >> Should the @classproperty sit within the "MyTable(Base)" itself (ie is
>> there a need for the separate object --
>> >
>> > @classproperty is typically specific to the mixin use case, which is why
>> its only discussed in the "mixins" section of the declarative documentation.
>>  It's a useful construct in other situations but you certainly don't need it
>> if you aren't using mixins.
>> >
>> >
>> >> and have I been confused by the section on 'mixins' )?
>> >
>> > I'm not sure why you're choosing to use a mixin here, as your
>> column_property appears to be pretty specific to the MyTable class.   if the
>> documentation led you to believe that you needed one, I am extremely curious
>> why that is the case as mixins are absolutely optional and that would be a
>> serious documentation bug.     Without the mixin, it is:
>> >
>> > class MyTable(Base):
>> >    __tablename__ = 'foo'
>> >    id = Column(Integer, primary_key=True)
>> >    my_str = Column('my_str', String)
>> >    my_substr = column_property(
>> >                           select([func.substr(my_str, 2,
>> 3)]).label('my_substr')
>> >                      )
>> >
>> >
>> >
>> > --
>> > You received this message because you are subscribed to the Google
>> Groups "sqlalchemy" group.
>> > To post to this group, send email to sqlalch...@googlegroups.com.
>> > To unsubscribe from this group, send email to
>> sqlalchemy+unsubscr...@googlegroups.com<sqlalchemy%2bunsubscr...@googlegroups.com>
>> .
>> > For more options, visit this group at
>> http://groups.google.com/group/sqlalchemy?hl=en.
>> >
>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "sqlalchemy" group.
>> To post to this group, send email to sqlalch...@googlegroups.com.
>> To unsubscribe from this group, send email to
>> sqlalchemy+unsubscr...@googlegroups.com<sqlalchemy%2bunsubscr...@googlegroups.com>
>> .
>> For more options, visit this group at
>> http://groups.google.com/group/sqlalchemy?hl=en.
>>
>>
>
> --
> You received this message because you are subscribed to the Google Groups
> "sqlalchemy" group.
> To post to this group, send email to sqlalch...@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.
>
>
>  --
> You received this message because you are subscribed to the Google Groups
> "sqlalchemy" group.
> To post to this group, send email to sqlalch...@googlegroups.com.
> To unsubscribe from this group, send email to
> sqlalchemy+unsubscr...@googlegroups.com<sqlalchemy%2bunsubscr...@googlegroups.com>
> .
> For more options, visit this group at
> http://groups.google.com/group/sqlalchemy?hl=en.
>

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalch...@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