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.