this is probably more of a Pyramid question.

I'm pretty allergic to traversal myself :)


On Sep 3, 2014, at 2:58 PM, Milo Toor <milo.t...@gmail.com> wrote:

> Hi.
> 
> I am trying to wrap a polymorphic model so that it can act as a traversal 
> node in a Pyramid application:
> 
> from sqlalchemy import Column, Integer, String, create_engine
> from sqlalchemy.orm import sessionmaker
> from sqlalchemy.ext.declarative import declarative_base
> 
> 
> Base = declarative_base()
> engine = create_engine('sqlite:///:memory:', echo=True)
> Session = sessionmaker(bind=engine)
> 
> 
> # This is the class we wish to wrap
> class Employee(Base):
>     __tablename__ = 'employee'
>     id = Column(Integer, primary_key=True)
>     name = Column(String(50))
>     type = Column(String(20))
> 
> 
>     __mapper_args__ = {
>         'polymorphic_on': type,
>         'polymorphic_identity': 'employee'
>     }
> 
> 
> 
> class Manager(Employee):
>     __mapper_args__ = {
>         'polymorphic_identity': 'manager'
>     }
> 
> 
> 
> class Engineer(Employee):
>     __mapper_args__ = {
>         'polymorphic_identity': 'engineer'
>     }
> 
> 
> 
> class EmployeeInTraversal(Employee):
>     """
>     Wraps the Employee class. This is to keep our models and our application
>     logic decoupled.
>     """
>     def __getitem__(self, key):
>         """
>         Make the employee behave like a traversal node.
> 
>         :param key:
>             The traversal key. If asked for tasks return the appropriate root
>             factory
>         """
>         if key == 'tasks':
>             return 'TasksRootFactory()'
>         raise KeyError
> 
> 
> # Create the tables
> Base.metadata.create_all(engine)
> 
> 
> # Create both a Manager and an Engineer
> manager = Manager(name='Taylor')
> engineer = Engineer(name='Sam')
> 
> 
> session = Session()
> session.add_all([manager, engineer])
> session.commit()
> 
> 
> # somewhere a request is made for /employee/1/tasks...
> 
> 
> # Query for the engineer, somewhere in the EmployeeRootFactory
> wrapped_engineer = session.query(EmployeeInTraversal).get(1)
> 
> 
> # Traversal doing its thing. Here lies the trouble.
> engineer_tasks = wrapped_engineer['tasks']
> 
> The last line of this code throws a TypeError with the message 'NoneType' 
> object has no attribute '__getitem__'. Nothing is turned up by the query to 
> EmployeeInTraversal. If the query is instead made with the Employee class, we 
> get a similar TypeError: 'Manager' object has no attribute '__getitem__'. So 
> in other words, querying EmployeeInTraversal returns nothing, but querying 
> Employee returns the object, although unwrapped.
> 
> The reason for this, near as I can tell, is that the EmployeeInTraversal 
> class is being interpreted as a subtype of Employee rather than as a wrapper 
> for the class. I attribute this to the polymorphic nature of the Employee 
> class, but at this point I'm really just banging my head against the wall. We 
> would very much like to keep our models and application logic separate, and 
> not embed traversal logic in the schema classes... Is there any way to wrap a 
> polymorphic class without the wrapper being interpreted as a sub-type?
> 
> -- 
> 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.

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

Reply via email to