Hi,

Using declarative here, and I'm trying to create a column_property with a 
correlated subquery that returns a count of records with a matching value 
in some other column. Here's what I've tried. Option 1 is the best, option 
2 is ugly but second best, option 3 is not a good option since there are 
many other classes involved and the place where I'd need to put that code 
is far away from where it logically belongs.

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import *
from sqlalchemy.ext.declarative import declared_attr

Base = declarative_base()
option = 1

class Foo(Base):
    __tablename__ = 'foo'
    id = Column(Integer, primary_key=True)
    bar_id = Column(Integer, ForeignKey("bar.id"))
    name = Column(String)

    if option == 1:
        # does not work (see first traceback below)
        @declared_attr
        def name_count(cls):
            clx = aliased(cls)
            return column_property(
                select(func.count([clx.id]))
                    .where(clx.name == cls.name)
                    .correlate(cls.__table__))

if option == 2:
    # does not work (see second traceback below)
    _foo = aliased(Foo)
    Foo.name_count = column_property(
            select([func.count(_foo.id)])
                .where(_foo.name == Foo.name)
                .correlate(Foo.__table__))


class Bar(Base):
    __tablename__ = 'bar'
    id = Column(Integer, primary_key=True)
    name = Column(String)


if option == 3:
    # works, but really not where I want to put this code
    _foo = aliased(Foo)
    Foo.name_count = column_property(
            select([func.count(_foo.id)])
                .where(_foo.name == Foo.name)
                .correlate(Foo.__table__))


Option 1 traceback:

Traceback (most recent call last):
  File "temp/example.py", line 8, in <module>
    class Foo(Base):
  File ".../python2.7/site-packages/sqlalchemy/ext/declarative.py", line 
1348, in __init__
    _as_declarative(cls, classname, cls.__dict__)
  File ".../python2.7/site-packages/sqlalchemy/ext/declarative.py", line 
1181, in _as_declarative
    value = getattr(cls, k)
  File ".../python2.7/site-packages/sqlalchemy/ext/declarative.py", line 
1554, in __get__
    return desc.fget(cls)
  File "temp/example.py", line 15, in name_count
    clx = aliased(cls)
  File ".../python2.7/site-packages/sqlalchemy/orm/util.py", line 385, in 
aliased
    return AliasedClass(element, alias=alias, name=name, 
adapt_on_names=adapt_on_names)
  File ".../python2.7/site-packages/sqlalchemy/orm/util.py", line 298, in 
__init__
    self.__mapper = _class_to_mapper(cls)
  File ".../python2.7/site-packages/sqlalchemy/orm/util.py", line 673, in 
_class_to_mapper
    raise exc.UnmappedClassError(class_or_mapper)
sqlalchemy.orm.exc.UnmappedClassError: Class '__main__.Foo' is not mapped


Option 2 traceback:

Traceback (most recent call last):
  File "temp/example.py", line 16, in <module>
    select([func.count(_foo.id)])
  File ".../python2.7/site-packages/sqlalchemy/sql/expression.py", line 
1229, in __call__
    return func(*c, **o)
  File ".../python2.7/site-packages/sqlalchemy/sql/functions.py", line 16, 
in __call__
    args = [_literal_as_binds(c) for c in args]
  File ".../python2.7/site-packages/sqlalchemy/sql/expression.py", line 
1440, in _literal_as_binds
    return element.__clause_element__()
  File ".../python2.7/site-packages/sqlalchemy/orm/attributes.py", line 
117, in __clause_element__
    return self.comparator.__clause_element__()
  File ".../python2.7/site-packages/sqlalchemy/util/langhelpers.py", line 
506, in oneshot
    result = self.fget(obj, *args, **kw)
  File ".../python2.7/site-packages/sqlalchemy/orm/properties.py", line 
156, in __clause_element__
    return self.adapter(self.prop.columns[0])
  File ".../python2.7/site-packages/sqlalchemy/orm/util.py", line 334, in 
__adapt_element
    return self.__adapter.traverse(elem).\
  File ".../python2.7/site-packages/sqlalchemy/sql/visitors.py", line 185, 
in traverse
    return replacement_traverse(obj, self.__traverse_options__, replace)
  File ".../python2.7/site-packages/sqlalchemy/sql/visitors.py", line 281, 
in replacement_traverse
    obj = clone(obj, **opts)
  File ".../python2.7/site-packages/sqlalchemy/sql/visitors.py", line 270, 
in clone
    newelem = replace(elem)
  File ".../python2.7/site-packages/sqlalchemy/sql/visitors.py", line 182, 
in replace
    e = v.replace(elem)
  File ".../python2.7/site-packages/sqlalchemy/sql/util.py", line 720, in 
replace
    return self._corresponding_column(col, True)
  File ".../python2.7/site-packages/sqlalchemy/sql/util.py", line 695, in 
_corresponding_column
    require_embedded=require_embedded)
  File ".../python2.7/site-packages/sqlalchemy/sql/expression.py", line 
2492, in corresponding_column
    if self.c.contains_column(column):
  File ".../python2.7/site-packages/sqlalchemy/util/langhelpers.py", line 
485, in __get__
    obj.__dict__[self.__name__] = result = self.fget(obj)
  File ".../python2.7/site-packages/sqlalchemy/sql/expression.py", line 
2558, in columns
    self._populate_column_collection()
  File ".../python2.7/site-packages/sqlalchemy/sql/expression.py", line 
3704, in _populate_column_collection
    col._make_proxy(self)
  File ".../python2.7/site-packages/sqlalchemy/schema.py", line 1103, in 
_make_proxy
    fk = [ForeignKey(f.column) for f in self.foreign_keys]
  File ".../python2.7/site-packages/sqlalchemy/util/langhelpers.py", line 
485, in __get__
    obj.__dict__[self.__name__] = result = self.fget(obj)
  File ".../python2.7/site-packages/sqlalchemy/schema.py", line 1392, in 
column
    tname)
sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 
'foo.bar_id' could not find table 'bar' with which to generate a foreign 
key to target column 'id'


It looks like the problem is that mapper state is not being initialized 
properly prior to setting up the column_property in the first two options. 
Is there another type of property similar to declared_attr that will allow 
me to add the column_property some place in the initialization sequence 
where mappers have been sufficiently initialized to allow constructing a 
select statement?

~ Daniel

-- 
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?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to