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.

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.

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? )


> 
> 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.
> > 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.
> 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