Reputation: 651
When building a Pyramid app (SQLAlchemy as ORM) I'm hit with a problem I can't seem to figure out.
Project built with SQLAlchemy scaffold, so all the setup is proper.
When I use DBSession variable in views or like it works properly.
Example :
from pabsite.models import DBSession
....
@view_config(route_name='admin_class', renderer='admin_class.mako')
def admin_class(request):
db_class = eval(request.matchdict['db_class'])
class_objects = DBSession.query(db_class).all()
return {'db_class':db_class, 'class_objects':class_objects, "db_class_name":request.matchdict['db_class']}
Now the problem arises when I try to create a new, non-SQLAlchemy class like :
from pabsite.models import DBSession
.....
class AdminPost(colander.MappingSchema):
tester = DBSession.query(Post).all()
title = colander.SchemaNode(colander.String(),
validator=colander.Length(max=100),
widget = get_inputbox(),
description='Tytuł')
The moment I want to run the app I'm hit with :
File "/media/stuff/Projects/current/web/PabsiteProject/pabsite/pabsite/__init__.py", line 1, in <module>
from pabsite.admin.views import admin_routes
File "/media/stuff/Projects/current/web/PabsiteProject/pabsite/pabsite/admin/views.py", line 9, in <module>
from models import getAdminPost
File "/media/stuff/Projects/current/web/PabsiteProject/pabsite/pabsite/admin/models.py", line 13, in <module>
class AdminPost(colander.MappingSchema, Base):
File "/media/stuff/Projects/current/web/PabsiteProject/pabsite/pabsite/admin/models.py", line 14, in AdminPost
tester = DBSession.query(Post).all()
.....
sqlalchemy.exc.UnboundExecutionError: Could not locate a bind configured on mapper Mapper|Post|posts, SQL expression or this Session
It must be something trivial but I can't seem to make that class aware of the DBSession binding. Can somebody please point me to some solution / docs.
EDIT :
Sorry, I've posted a stupid example which I've ended up when trying different things.
Proper example :
class AdminPost(colander.MappingSchema):
title = colander.SchemaNode(colander.String(),
validator=colander.Length(max=10),
widget = get_inputbox(),
description='Tytuł')
category = colander.SchemaNode(colander.String(),
widget = get_select_widget(),
description='Kategoria')
def getForm(self):
schema = self
admin_form = Form(schema, buttons=('submit',))
return admin_form
Now I define the select widget (I want them to be reused in other classes) as :
def get_select_widget():
get_categories = DBSession.query(Category).all()
select_widget = deform.widget.SelectWidget(values=get_categories())
And here get_categories throws the error I mentioned earlier. It maybe my misconception of using Python, but I don't know how to get DBSession be aware of the app engine configuration.
EDIT 2
Category is a db model while AdminPost class server as a deform model.
Here's the def
class Category(Base):
__tablename__ = 'categories'
id = Column(Integer, primary_key=True)
name = Column(String(150))
slug = Column(String(150))
name_en = Column(String(150))
slug_en = Column(String(150))
def __init__(self,name=''):
self.name = name
def __repr__(self):
return self.name
How can they share the same parent as they're meant for different things.
EDIT 4
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
Base = declarative_base()
They're defined as the pyramid scaffold makes them - in models.py in app root. That's where I import them from, and they do work, but in views, not in a class which I prepared on deform.
Upvotes: 1
Views: 2064
Reputation: 7564
Your problem lies with the way python works and what you are trying to achieve here. I assume you want AdminPost.tester
to always contain an up-to-date list of all items in the Post
table?
Let's address the problems one-by-one. First, the statement
class AdminPost(colander.MappingSchema):
tester = DBSession.query(Post).all()
will be executed at import time. Check this out:
print "Before import"
import some_module
print "After import"
some_module.SomeClass()
And let some_module
look like this:
class A(object):
print "Inside A"
def __init__(self):
print "New instance of A"
This is the output you will get:
Before import
Inside A
After import
New instance of A
The reason for this is the way python parses the code: It executes each of the statements it finds, but on encountering a def
it will not evaluate anything that is indented. (This is a rough description!)
So now that you have seen this, you know that your query is executed (most likely) when you start your program. At this point, sqlalchemy has not found all its tables and made the configuration for it. Furthermore, you most likely don't have an engine bound yet.
But your problem actually isn't really SQLAlchemy related. It is a common misconception of how to define values that every instance of a class should as a default. In Python you do this inside an __init__
:
class AdminPost(colander.MappingSchema):
def __init__(self, *args, **kwargs):
tester = DBSession.query(Post).all()
colander.MappingSchema.__init__(self, *args, **kwargs)
The last line makes sure the default constructor is called afterwards.
Upvotes: 1