Sergey Kucheryavski | 31 Jul 2012 17:42
Picon

aliased in mixins

I would like to use Mixin to make a base class for MPTT trees, just as an example


class MPTT(object):
    <at> declared_attr
    def __tablename__(cls):
        return cls.__name__.lower()

    id = db.Column(db.Integer, primary_key = True)
    level = db.Column(db.Integer, nullable = False)
    lft = db.Column(db.Integer, nullable = False)
    rgt = db.Column(db.Integer, nullable = False)

    <at> declared_attr
    def parent_id(cls):
        return db.Column(db.Integer, db.ForeignKey(cls.id))

    <at> declared_attr
    def num_children(cls):
        mptt2 = aliased(cls)
        return column_property(select([func.count(cls.id)]).where(cls.parent_id == mptt2.id))

And then use it like:

class Node(MPTT, Base):
    __tablename__ = 'node'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(150), nullable = False)
    urlname = db.Column(db.String(150), nullable = False)
    is_visible = db.Column(db.Boolean, default = True)

    def __repr__(self):
        return '%r (%r - %r)' % (self.name, self.lft, self.rgt)

    def __init__(self, name, urlname, parent = None):
        super(Node, self).__init__(parent)
        self.name = name
        self.urlname = urlname

However I have problem using aliased in the mixin getting an error: 

  File "./app/ext_mptt/models.py", line 24, in ordernum
    mptt2 = aliased(cls)
  File "./venv/lib/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 "./venv/lib/python2.7/site-packages/sqlalchemy/orm/util.py", line 298, in __init__
    self.__mapper = _class_to_mapper(cls)
  File "./venv/lib/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 'app.cms.models.Node' is not mapped

I thought the num_children method should be called when Node is mapped. Will be grateful for any hints!

--
You received this message because you are subscribed to the Google Groups "sqlalchemy" group.
To view this discussion on the web visit https://groups.google.com/d/msg/sqlalchemy/-/qWZAyf0r82kJ.
To post to this group, send email to sqlalchemy <at> googlegroups.com.
To unsubscribe from this group, send email to sqlalchemy+unsubscribe <at> googlegroups.com.
For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.
Michael Bayer | 1 Aug 2012 03:46
Gravatar

Re: aliased in mixins


On Jul 31, 2012, at 11:42 AM, Sergey Kucheryavski wrote:

I would like to use Mixin to make a base class for MPTT trees, just as an example

class MPTT(object):
    <at> declared_attr
    def __tablename__(cls):
        return cls.__name__.lower()

    id = db.Column(db.Integer, primary_key = True)
    level = db.Column(db.Integer, nullable = False)
    lft = db.Column(db.Integer, nullable = False)
    rgt = db.Column(db.Integer, nullable = False)

    <at> declared_attr
    def parent_id(cls):
        return db.Column(db.Integer, db.ForeignKey(cls.id))

    <at> declared_attr
    def num_children(cls):
        mptt2 = aliased(cls)
        return column_property(select([func.count(cls.id)]).where(cls.parent_id == mptt2.id))


yeah num_children() is evaluated within declarative's metaclass, before MPTT is mapped.  So you have to set that attribute on after the fact:

mptt2 = aliased(cls)
MPTT.num_children = column_property(....)

docs (see the last example):



--
You received this message because you are subscribed to the Google Groups "sqlalchemy" group.
To post to this group, send email to sqlalchemy <at> googlegroups.com.
To unsubscribe from this group, send email to sqlalchemy+unsubscribe <at> googlegroups.com.
For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.
Sergey Kucheryavski | 1 Aug 2012 13:20
Picon

Re: aliased in mixins

Thanks Michael, I greatly appreciate your help. But I am still a bit confused. To set the attribute I need to have the alias for MPTT (or, actually any class that inherits MPTT mixin class) table. But I can not use aliased() neither inside the MPTT definition nor after it — in both cases I get the mapping error. 

On Wednesday, August 1, 2012 3:46:56 AM UTC+2, Michael Bayer wrote:


On Jul 31, 2012, at 11:42 AM, Sergey Kucheryavski wrote:

I would like to use Mixin to make a base class for MPTT trees, just as an example

class MPTT(object):
    <at> declared_attr
    def __tablename__(cls):
        return cls.__name__.lower()

    id = db.Column(db.Integer, primary_key = True)
    level = db.Column(db.Integer, nullable = False)
    lft = db.Column(db.Integer, nullable = False)
    rgt = db.Column(db.Integer, nullable = False)

    <at> declared_attr
    def parent_id(cls):
        return db.Column(db.Integer, db.ForeignKey(cls.id))

    <at> declared_attr
    def num_children(cls):
        mptt2 = aliased(cls)
        return column_property(select([func.count(cls.id)]).where(cls.parent_id == mptt2.id))


yeah num_children() is evaluated within declarative's metaclass, before MPTT is mapped.  So you have to set that attribute on after the fact:

mptt2 = aliased(cls)
MPTT.num_children = column_property(....)

docs (see the last example):



--
You received this message because you are subscribed to the Google Groups "sqlalchemy" group.
To view this discussion on the web visit https://groups.google.com/d/msg/sqlalchemy/-/3tDxuZQ9VbwJ.
To post to this group, send email to sqlalchemy <at> googlegroups.com.
To unsubscribe from this group, send email to sqlalchemy+unsubscribe <at> googlegroups.com.
For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.
Michael Bayer | 1 Aug 2012 16:20
Gravatar

Re: aliased in mixins

oh, sorry, that's a mixin.  this combination of variables is not supported at this time.  You need to use an event:

from sqlalchemy import event
from sqlalchemy.orm import mapper
<at> event.listens_for(mapper, "mapper_configured")
def set_num_children(mapper, cls):
    if not issubclass(cls, MPTT):
        return

    mptt2 = aliased(cls)
    cls.num_children = column_property(
                select([func.count(cls.id)]).where(cls.parent_id == mptt2.id))




On Aug 1, 2012, at 7:20 AM, Sergey Kucheryavski wrote:

Thanks Michael, I greatly appreciate your help. But I am still a bit confused. To set the attribute I need to have the alias for MPTT (or, actually any class that inherits MPTT mixin class) table. But I can not use aliased() neither inside the MPTT definition nor after it — in both cases I get the mapping error. 

On Wednesday, August 1, 2012 3:46:56 AM UTC+2, Michael Bayer wrote:

On Jul 31, 2012, at 11:42 AM, Sergey Kucheryavski wrote:

I would like to use Mixin to make a base class for MPTT trees, just as an example

class MPTT(object):
    <at> declared_attr
    def __tablename__(cls):
        return cls.__name__.lower()

    id = db.Column(db.Integer, primary_key = True)
    level = db.Column(db.Integer, nullable = False)
    lft = db.Column(db.Integer, nullable = False)
    rgt = db.Column(db.Integer, nullable = False)

    <at> declared_attr
    def parent_id(cls):
        return db.Column(db.Integer, db.ForeignKey(cls.id))

    <at> declared_attr
    def num_children(cls):
        mptt2 = aliased(cls)
        return column_property(select([func.count(cls.id)]).where(cls.parent_id == mptt2.id))


yeah num_children() is evaluated within declarative's metaclass, before MPTT is mapped.  So you have to set that attribute on after the fact:

mptt2 = aliased(cls)
MPTT.num_children = column_property(....)

docs (see the last example):




--
You received this message because you are subscribed to the Google Groups "sqlalchemy" group.
To view this discussion on the web visit https://groups.google.com/d/msg/sqlalchemy/-/3tDxuZQ9VbwJ.
To post to this group, send email to sqlalchemy <at> googlegroups.com.
To unsubscribe from this group, send email to sqlalchemy+unsubscribe <at> 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 sqlalchemy <at> googlegroups.com.
To unsubscribe from this group, send email to sqlalchemy+unsubscribe <at> googlegroups.com.
For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.
Sergey Kucheryavski | 1 Aug 2012 19:52
Picon

Re: aliased in mixins

Thank you very much!

On Wednesday, August 1, 2012 4:20:23 PM UTC+2, Michael Bayer wrote:

oh, sorry, that's a mixin.  this combination of variables is not supported at this time.  You need to use an event:

from sqlalchemy import event
from sqlalchemy.orm import mapper
<at> event.listens_for(mapper, "mapper_configured")
def set_num_children(mapper, cls):
    if not issubclass(cls, MPTT):
        return

    mptt2 = aliased(cls)
    cls.num_children = column_property(
                select([func.count(cls.id)]).where(cls.parent_id == mptt2.id))




On Aug 1, 2012, at 7:20 AM, Sergey Kucheryavski wrote:

Thanks Michael, I greatly appreciate your help. But I am still a bit confused. To set the attribute I need to have the alias for MPTT (or, actually any class that inherits MPTT mixin class) table. But I can not use aliased() neither inside the MPTT definition nor after it — in both cases I get the mapping error. 

On Wednesday, August 1, 2012 3:46:56 AM UTC+2, Michael Bayer wrote:

On Jul 31, 2012, at 11:42 AM, Sergey Kucheryavski wrote:

I would like to use Mixin to make a base class for MPTT trees, just as an example

class MPTT(object):
    <at> declared_attr
    def __tablename__(cls):
        return cls.__name__.lower()

    id = db.Column(db.Integer, primary_key = True)
    level = db.Column(db.Integer, nullable = False)
    lft = db.Column(db.Integer, nullable = False)
    rgt = db.Column(db.Integer, nullable = False)

    <at> declared_attr
    def parent_id(cls):
        return db.Column(db.Integer, db.ForeignKey(cls.id))

    <at> declared_attr
    def num_children(cls):
        mptt2 = aliased(cls)
        return column_property(select([func.count(cls.id)]).where(cls.parent_id == mptt2.id))


yeah num_children() is evaluated within declarative's metaclass, before MPTT is mapped.  So you have to set that attribute on after the fact:

mptt2 = aliased(cls)
MPTT.num_children = column_property(....)

docs (see the last example):




--
You received this message because you are subscribed to the Google Groups "sqlalchemy" group.
To view this discussion on the web visit https://groups.google.com/d/msg/sqlalchemy/-/3tDxuZQ9VbwJ.
To post to this group, send email to sqlalchemy <at> googlegroups.com.
To unsubscribe from this group, send email to sqlalchemy+unsubscribe <at> 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 view this discussion on the web visit https://groups.google.com/d/msg/sqlalchemy/-/xpFtuJ5a6YcJ.
To post to this group, send email to sqlalchemy <at> googlegroups.com.
To unsubscribe from this group, send email to sqlalchemy+unsubscribe <at> googlegroups.com.
For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.

Gmane