On Fri, Jun 20, 2014 at 3:46 PM, Ken Lareau <klar...@tagged.com> wrote:
> On Fri, Jun 20, 2014 at 1:23 PM, Mike Bayer <mike...@zzzcomputing.com> > wrote: > >> >> On 6/20/14, 3:38 PM, Ken Lareau wrote: >> >> So in the ongoing improvement of one of our internal databases, we >> created >> a new table named 'environments' whose SQLA code looks something like >> this: >> >> class Environment(Base): >> __tablename__ = 'environments' >> >> id = Column(u'environmentID', INTEGER(), primary_key=True) >> environment = Column(String(length=15), nullable=False, unique=True) >> env = Column(String(length=12), nullable=False, unique=True) >> domain = Column(String(length=32), nullable=False, unique=True) >> prefix = Column(String(length=1), nullable=False) >> >> Two of our tables recently needed conversion to stop using their own >> local >> 'environment' column to using this table. The first part's been put in >> place >> (a new foreign key for 'environment_id'), but to prevent large swaths >> of code >> from needing changes, a thought of using a hybrid property might allow >> the >> change to be hidden (until the code using it had been rewritten at >> least). >> >> My naive attempt was the following (just the relevant snippet): >> >> environment_obj = relationship('Environment') >> >> @hybrid_property >> def environment(self): >> return self.environment_obj.environment >> >> Unfortunately (and in hindsight for obvious reasons), this code doesn't >> work, >> >> what does "doesn't work" mean here? This will work at the instance >> level. At the query level, not so much, that's true, if you truly want no >> code to change you'd need to implement an @expression here that's a little >> inefficient, as it needs to do a correlated subq: >> >> > Yes, the "doesn't work" was specifically related to an attempt to use it in > a query, which of course failed miserably. :) > > >> class HasEnv(Base): >> __tablename__ = 'has_env' >> >> id = Column(INTEGER, primary_key=True) >> environment_id = Column(ForeignKey('environments.environmentID')) >> >> >> environment_obj = relationship('Environment') >> >> @hybrid_property >> def environment(self): >> return self.environment_obj.environment >> >> @environment.expression >> def environment(cls): >> return select([Environment.environment]).\ >> where(Environment.id == >> cls.environment_id).correlate(cls).\ >> as_scalar() >> >> >> s = Session() >> >> print s.query(HasEnv).filter(HasEnv.environment == 'some env') >> >> output: >> >> SELECT has_env.id AS has_env_id, has_env.environment_id AS >> has_env_environment_id >> FROM has_env >> WHERE (SELECT environments.environment >> FROM environments >> WHERE environments."environmentID" = has_env.environment_id) = :param_1 >> >> wont perform well from a SQL perspective but will do the job... >> >> >> >> This worked perfectly, thank you! This is honestly a "stop-gap" measure > to allow much of the code to be rewritten (after which it can be removed), > and for what it's being used for at the moment, it won't be too bad > regarding > performance. > > >> >> but a very brief conversation with someone on the #sqlalchemy channel >> on >> Freenode indicated there was no way to do this and all the relevant code >> must be reworked. While it's only a few dozen places this occurs, I can >> see >> this coming up again in the future as further schema refactorings occur, >> so >> I turn to those with more expertise to find out if there is a way to >> accomplish >> what I desire, or if there's really no hope. :) Any insight would be >> greatly >> appreciated. >> >> I don't know how to fix this issue with IRC and stackoverflow that people >> constantly are getting bad information. >> >> Heh, Sometimes I think I should know better about asking for help > on IRC, but sometimes I get lucky. In this case, I decided I might > have better luck on the mailing list after the answer I got on IRC > was very unsatisfactory. :) > > Thanks for the help! > D'oh, seems like I spoke too soon; there's a specific instance where this fails due to some subquery stuff I'm doing: if apptier: subq = ( Session.query( Package.pkg_name, Package.version, Package.revision, AppDefinition.app_type, AppDeployment.environment ).join(Deployment) .join(AppDeployment) .join(AppDefinition) .filter(Package.pkg_name == package_name) .filter(AppDeployment.environment == env) .filter(AppDeployment.status != 'invalidated')) [...] # The actual column name must be used in the subquery # usage below; DB itself should be corrected versions = (Session.query(subq.c.appType, subq.c.version, subq.c.revision) .group_by(subq.c.appType, subq.c.environment) .all()) The parts in the subquery work fine, but the access of the 'column' in the final query leads to this: Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/home/klareau/repos/git/tagopsdb/tagopsdb/deploy/deploy.py", line 234, in find_deployed_version .group_by(subq.c.appType, subq.c.environment) File "/home/klareau/.virtualenvs/tds/lib/python2.6/site-packages/sqlalchemy/util/_collections.py", line 174, in __getattr__ raise AttributeError(key) AttributeError: environment This is not completely surprising, but I'm uncertain as the best way to fix this... help? :) -- - Ken Lareau -- 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 sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at http://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.