I have set up a simple system for adding comments to items in my database using a one-to-many relation (one item can have many comments), but I can't seem to get it to work. It should be simple, I know. It's probably something simple that I've overlooked. I would very much appriciate a second set of eyes on this. Can anyone help?
I have a model defined with SQLAlchemy that looks like this:
class Item(Base):
__tablename__ = 'items' # Parent
id = Column(Integer, primary_key=True)
comments = relationship("Comment", backref='items')
class Comment(Base):
__tablename__ = 'comments' # Child
id = Column(Integer, primary_key=True)
comment_text = Column(Text, nullable=False)
item_id = Column(Integer, ForeignKey('items.id'), nullable=False)
def __init__(self, comment_text, item_id):
self.comment_text = comment_text
self.item_id = item_id
In my view, I do some work, then try to add a comment object:
item = DBSession.query(Item).filter(Item.id == item_id).first()
try:
print('Item id:', item.id, 'Comment text:', comment)
print('Item Comments:', item.comments)
cm = Comment(comment_text=comment,
item_id=item.id)
print('a')
item.comments.append(cm)
#DBSession.add(cm)
print('b')
DBSession.commit()
except:
DBSession.rollback()
print('c')
Note that I tried both item.comments.append(cm) and DBSession.add(cm) with identical results. That's why one of the two is commented out in the above code block. I also tried item.comments.append(Comment(...)) with identical results.
Now, when I try to add a comment, I get a stacktrace, culminating in:
sqlalchemy.exc.ResourceClosedError: This transaction is closed
The whole trace, including the debug prints, look like this:
Item id: 1 Comment text: test
Item Comments: []
a
c
Traceback (most recent call last):
File "C:\Python33\lib\wsgiref\handlers.py", line 137, in run
self.result = application(self.environ, self.start_response)
File "C:\Users\[user]\PYTHON~1.5\lib\site-packages\pyramid\router.py", line 251, in __call__
response = self.invoke_subrequest(request, use_tweens=True)
File "C:\Users\[user]\PYTHON~1.5\lib\site-packages\pyramid\router.py", line 227, in invoke_subrequest
response = handle_request(request)
File "C:\Users\[user]\PYTHON~1.5\lib\site-packages\pyramid\tweens.py", line 21, in excview_tween
response = handler(request)
File "C:\Users\[user]\PYTHON~1.5\lib\site-packages\pyramid_tm\__init__.py", line 82, in tm_tween
reraise(*exc_info)
File "C:\Users\[user]\PYTHON~1.5\lib\site-packages\pyramid_tm\compat.py", line 13, in reraise
raise value
File "C:\Users\[user]\PYTHON~1.5\lib\site-packages\pyramid_tm\__init__.py", line 70, in tm_tween
manager.commit()
File "C:\Users\[user]\PYTHON~1.5\lib\site-packages\transaction\_manager.py", line 111, in commit
return self.get().commit()
File "C:\Users\[user]\PYTHON~1.5\lib\site-packages\transaction\_transaction.py", line 280, in commit
reraise(t, v, tb)
File "C:\Users\[user]\PYTHON~1.5\lib\site-packages\transaction\_compat.py", line 55, in reraise
raise value
File "C:\Users\[user]\PYTHON~1.5\lib\site-packages\transaction\_transaction.py", line 271, in commit
self._commitResources()
File "C:\Users\[user]\PYTHON~1.5\lib\site-packages\transaction\_transaction.py", line 417, in _commitResources
reraise(t, v, tb)
File "C:\Users\[user]\PYTHON~1.5\lib\site-packages\transaction\_compat.py", line 55, in reraise
raise value
File "C:\Users\[user]\PYTHON~1.5\lib\site-packages\transaction\_transaction.py", line 394, in _commitResources
rm.tpc_vote(self)
File "C:\Users\[user]\PYTHON~1.5\lib\site-packages\zope\sqlalchemy\datamanager.py", line 100, in tpc_vote
self.tx.commit()
File "C:\Users\[user]\PYTHON~1.5\lib\site-packages\sqlalchemy\orm\session.py", line 352, in commit
self._assert_active(prepared_ok=True)
File "C:\Users\[user]\PYTHON~1.5\lib\site-packages\sqlalchemy\orm\session.py", line 203, in _assert_active
raise sa_exc.ResourceClosedError(closed_msg)
sqlalchemy.exc.ResourceClosedError: This transaction is closed
Well, turns out the problem was a few corrupt files, not a programming error. Sigh. Well, problem solved. :)
Related
This question already has an answer here:
IntegrityError when inserting data in an association table using SQLAlchemy
(1 answer)
Closed 5 years ago.
I just switched from MySQL to SQLalchemy and I have to say that it is more difficult to get my head around sqlalchemy than I thought. Currently I have some trouble with a many-to-many relationship. I have users and queries in my model. A user can have many queries and a query offers a new article to read every day. I want to store which user read which query on what date. My models.py looks like this
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
read_dates = db.relationship("ReadIndex", backref="user")
def __repr__(self):
return '<User %r>' % (self.id)
class Queries(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
def __repr__(self):
return '<Queries %r>' % (self.id)
class ReadIndex(db.Model):
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True)
query_id = db.Column(db.Integer, db.ForeignKey('queries.id'), primary_key=True)
read_datetime = db.Column(db.DateTime)
read_query = db.relationship("Queries", backref="user_assocs")
def __repr__(self):
return '<ReadIndex>'
so I have users and queries. To store which user read which query on what date I have the class ReadIndex, which has an extra field called read_datetime, where I store the date of a user-query association. I than want to add such an association like
user = models.User.query.filter_by(id=user_id).first()
query = models.Queries.query.filter_by(id=query_id).first()
a = models.ReadIndex(read_datetime=dt.utcnow())
a.read_query = query
user.read_dates.append(a)
db.session.commit()
where query_id and user_id are the corresponding ids to select my objects. If I run this I get an error
sqlalchemy.exc.IntegrityError
IntegrityError: (sqlite3.IntegrityError) NOT NULL constraint failed:
read_index.query_id [SQL: u'INSERT INTO read_index (user_id, read_datetime)
VALUES (?, ?)'] [parameters: (1, '2015-07-29 20:55:50.898366')]
I am not sure what the problem is? I don't seem to violate any NOT NULL
edit: I noticed that I assigned query=None to a.read_query. Correcting this slightly changed the error
IntegrityError: (raised as a result of Query-invoked autoflush;
consider using a session.no_autoflush block if this flush is occurring prematurely)
(sqlite3.IntegrityError) NOT NULL constraint failed: read_index.user_id
[SQL: u'INSERT INTO read_index (query_id, read_datetime) VALUES (?, ?)']
[parameters: (1, '2015-07-29 23:11:11.934038')]
here is exactly what happens:
>>> from app import app, db, models
>>> user = models.User.query.filter_by(id=1).first()
>>> user
<User u'Florian Beutler'>
>>> query = models.Queries.query.filter_by(id=1).first()
>>> query
<Queries 1>
>>> import datetime
>>> a = models.ReadIndex(read_datetime=datetime.datetime.utcnow())
>>> a.read_query = query
>>> user.read_dates.append(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.7/site- packages/sqlalchemy/orm/attributes.py", line 237, in __get__
return self.impl.get(instance_state(instance), dict_)
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/attributes.py", line 578, in get
value = self.callable_(state, passive)
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/strategies.py", line 529, in _load_for_state
return self._emit_lazyload(session, state, ident_key, passive)
File "<string>", line 1, in <lambda>
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/strategies.py", line 599, in _emit_lazyload
result = q.all()
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2399, in all
return list(self)
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2515, in __iter__
self.session._autoflush()
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 1292, in _autoflush
util.raise_from_cause(e)
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/util/compat.py", line 199, in raise_from_cause
reraise(type(exception), exception, tb=exc_tb)
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 1282, in _autoflush
self.flush()
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 2004, in flush
self._flush(objects)
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 2122, in _flush
transaction.rollback(_capture_exception=True)
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/util/langhelpers.py", line 60, in __exit__
compat.reraise(exc_type, exc_value, exc_tb)
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 2086, in _flush
flush_context.execute()
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/unitofwork.py", line 373, in execute
rec.execute(self)
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/unitofwork.py", line 532, in execute
uow
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/persistence.py", line 174, in save_obj
mapper, table, insert)
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/persistence.py", line 781, in _emit_insert_statements
execute(statement, params)
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 914, in execute
return meth(self, multiparams, params)
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/sql/elements.py", line 323, in _execute_on_connection
return connection._execute_clauseelement(self, multiparams, params)
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1010, in _execute_clauseelement
compiled_sql, distilled_params
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1146, in _execute_context
context)
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1341, in _handle_dbapi_exception
exc_info
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/util/compat.py", line 199, in raise_from_cause
reraise(type(exception), exception, tb=exc_tb)
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1139, in _execute_context
context)
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/default.py", line 450, in do_execute
cursor.execute(statement, parameters)
sqlalchemy.exc.IntegrityError: (raised as a result of Query-invoked autoflush; consider using a session.no_autoflush block if this flush is occurring prematurely) (sqlite3.IntegrityError) NOT NULL constraint failed: read_index.user_id [SQL: u'INSERT INTO read_index (query_id, read_datetime) VALUES (?, ?)'] [parameters: (1, '2015-07-29 23:17:06.013485')]
constraint?
thanks
carl
The .first() method either returns the first result or None if there isn't one, are you sure you're not assigning a.read_query to None?
You are getting this error because the user_id and query_id fields of the ReadIndex table are None. So, when you commit, ReadIndex object is trying to get created without having values in its primary key fields. So, do this,
user = models.User.query.filter_by(id=user_id).first()
query = models.Queries.query.filter_by(id=query_id).first()
a=models.ReadIndex(user_id=user.id,query_id=query.id,read_datetime=dt.utcnow())
db.session.add(a)
db.session.commit()
You dont need to manually append anything to the relationship. SQLAlchemy does that for you automatically. You can crosscheck if you want,
for ud in user.read_dates:
print(ud)
Hope this helps!
I'm building a flask app and I want to use sqlalchemy observers to update a shipment status once all products inside that shipment become available.
Here's my datamodel:
from app import db
from sqlalchemy_utils import observes
class Shipment(db.Model):
__tablename__ = 'shipment'
id = db.Column(db.Integer, primary_key=True)
products = db.relationship('Product', backref='shipment', lazy='dynamic')
all_products_ready = db.Column(db.Boolean)
#observes('products')
def product_observer(self, products):
for p in self.products:
if p.status != 'ready':
self.all_products_ready = False
return False
self.all_products_ready = True
return True
class Product(db.Model):
__tablename__ = 'product'
id = db.Column(db.Integer, primary_key=True)
shipment_id = db.Column(db.Integer, db.ForeignKey('shipment.id'))
status = db.Column(db.String(120), index=True)
And here is some code I run to test it:
shipment = models.Shipment(products=[models.Product(status='ready'), models.Product(status='not_ready')])
db.session.add(shipment)
db.session.commit()
print(shipment.all_products_ready)
When I run this code I get an InvalidRequestError: Session is already flushing.
Here is the stack trace:
Traceback (most recent call last):
File "test.py", line 5, in <module>
db.session.commit()
File "U:\dev\observertest\flask\lib\site-packages\sqlalchemy\orm\scoping.py",
line 150, in do
return getattr(self.registry(), name)(*args, **kwargs)
File "U:\dev\observertest\flask\lib\site-packages\sqlalchemy\orm\session.py",
line 788, in commit
self.transaction.commit()
File "U:\dev\observertest\flask\lib\site-packages\sqlalchemy\orm\session.py",
line 384, in commit
self._prepare_impl()
File "U:\dev\observertest\flask\lib\site-packages\sqlalchemy\orm\session.py",
line 364, in _prepare_impl
self.session.flush()
File "U:\dev\observertest\flask\lib\site-packages\sqlalchemy\orm\session.py",
line 1985, in flush
self._flush(objects)
File "U:\dev\observertest\flask\lib\site-packages\sqlalchemy\orm\session.py",
line 2012, in _flush
self.dispatch.before_flush(self, flush_context, objects)
File "U:\dev\observertest\flask\lib\site-packages\sqlalchemy\event\attr.py", l
ine 221, in __call__
fn(*args, **kw)
File "U:\dev\observertest\flask\lib\site-packages\sqlalchemy_utils\observer.py
", line 272, in invoke_callbacks
for (root_obj, func, objects) in args:
File "U:\dev\observertest\flask\lib\site-packages\sqlalchemy_utils\observer.py
", line 252, in gather_callback_args
lambda obj: obj not in session.deleted
File "U:\dev\observertest\flask\lib\site-packages\sqlalchemy_utils\functions\o
rm.py", line 741, in getdotattr
last = [v for v in last if condition(v)]
File "U:\dev\observertest\flask\lib\site-packages\sqlalchemy\orm\dynamic.py",
line 245, in __iter__
sess = self.session
File "U:\dev\observertest\flask\lib\site-packages\sqlalchemy\orm\dynamic.py",
line 237, in session
sess.flush()
File "U:\dev\observertest\flask\lib\site-packages\sqlalchemy\orm\session.py",
line 1979, in flush
raise sa_exc.InvalidRequestError("Session is already flushing")
sqlalchemy.exc.InvalidRequestError: Session is already flushing
How can I use my models without getting this error?
I'm not completely sure why, but I think loading the relations using dynamic is causing problems here. In this line:
products = db.relationship('Product', backref='shipment', lazy='dynamic')
you need to change the lazy parameter to select instead of dynamic (or you can take out the lazy parameter alltogether as select is its default).
See the sqlalchemy reference for all the available options.
I have a product model with a many to many relationship to product_categories as described below:
class Product(Base):
""" The SQLAlchemy declarative model class for a Product object. """
__tablename__ = 'products'
id = Column(Integer, primary_key=True)
part_number = Column(String(10), nullable=False, unique=True)
name = Column(String(80), nullable=False, unique=True)
description = Column(String(2000), nullable=False)
categories = relationship('Category', secondary=product_categories,
backref=backref('categories', lazy='dynamic'))
class Category(Base):
""" The SQLAlchemy declarative model class for a Category object. """
__tablename__ = 'categories'
id = Column(Integer, primary_key=True)
lft = Column(Integer, nullable=False)
rgt = Column(Integer, nullable=False)
name = Column(String(80), nullable=False)
description = Column(String(2000), nullable=False)
order = Column(Integer)
products = relationship('Product', secondary=product_categories,
backref=backref('products', lazy='dynamic', order_by=name))
product_categories = Table('product_categories', Base.metadata,
Column('products_id', Integer, ForeignKey('products.id')),
Column('categories_id', Integer, ForeignKey('categories.id'))
)
Then, I'm trying to delete this object with:
product = DBSession.query(Product).filter_by(name = 'Algaecide').one()
DBSession().delete(product)
But, what I get is the error message StaleDataError: DELETE statement on table 'product_categories' expected to delete 1 row(s); Only 0 were matched.. If you notice, it appears to be running the DELETE statement twice. So, the first time it's successfully removes the product_id from the product_categories table, but then attempts to do it yet again for whatever reason, and then decides it needs to throw an exception because it's not there.
>>> Attempting to delete the product 'Algaecide' assigned to categories: [<myproject.models.category.Category object at 0x106fa9d90>]
21:39:50 INFO [sqlalchemy.engine.base.Engine][Dummy-2] SELECT categories.id AS categories_id, categories.lft AS categories_lft, categories.rgt AS categories_rgt, categories.name AS categories_name, categories.description AS categories_description, categories.`order` AS categories_order
FROM categories, product_categories
WHERE %s = product_categories.products_id AND categories.id = product_categories.categories_id ORDER BY categories.name
21:39:50 INFO [sqlalchemy.engine.base.Engine][Dummy-2] (109L,)
21:39:50 INFO [sqlalchemy.engine.base.Engine][Dummy-2] DELETE FROM product_categories WHERE product_categories.products_id = %s AND product_categories.categories_id = %s
21:39:50 INFO [sqlalchemy.engine.base.Engine][Dummy-2] (109L, 18L)
21:39:50 INFO [sqlalchemy.engine.base.Engine][Dummy-2] DELETE FROM product_categories WHERE product_categories.products_id = %s AND product_categories.categories_id = %s
21:39:50 INFO [sqlalchemy.engine.base.Engine][Dummy-2] (109L, 18L)
21:39:50 INFO [sqlalchemy.engine.base.Engine][Dummy-2] ROLLBACK
21:39:50 ERROR [pyramid_debugtoolbar][Dummy-2] Exception at http://0.0.0.0:6543/product/Algaecide/edit
traceback url: http://0.0.0.0:6543/_debug_toolbar/exception?token=6344937a98ee26992689&tb=4421411920
Traceback (most recent call last):
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/pyramid_debugtoolbar-2.3-py2.7.egg/pyramid_debugtoolbar/toolbar.py", line 178, in toolbar_tween
response = _handler(request)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/pyramid_debugtoolbar-2.3-py2.7.egg/pyramid_debugtoolbar/panels/performance.py", line 57, in resource_timer_handler
result = handler(request)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/pyramid/tweens.py", line 21, in excview_tween
response = handler(request)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/pyramid_tm-0.10-py2.7.egg/pyramid_tm/__init__.py", line 95, in tm_tween
reraise(*exc_info)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/pyramid_tm-0.10-py2.7.egg/pyramid_tm/__init__.py", line 83, in tm_tween
manager.commit()
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/transaction-1.4.3-py2.7.egg/transaction/_manager.py", line 111, in commit
return self.get().commit()
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/transaction-1.4.3-py2.7.egg/transaction/_transaction.py", line 280, in commit
reraise(t, v, tb)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/transaction-1.4.3-py2.7.egg/transaction/_transaction.py", line 271, in commit
self._commitResources()
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/transaction-1.4.3-py2.7.egg/transaction/_transaction.py", line 417, in _commitResources
reraise(t, v, tb)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/transaction-1.4.3-py2.7.egg/transaction/_transaction.py", line 389, in _commitResources
rm.tpc_begin(self)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/zope.sqlalchemy-0.7.5-py2.7.egg/zope/sqlalchemy/datamanager.py", line 90, in tpc_begin
self.session.flush()
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/SQLAlchemy-0.9.8-py2.7-macosx-10.6-intel.egg/sqlalchemy/orm/session.py", line 1919, in flush
self._flush(objects)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/SQLAlchemy-0.9.8-py2.7-macosx-10.6-intel.egg/sqlalchemy/orm/session.py", line 2037, in _flush
transaction.rollback(_capture_exception=True)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/SQLAlchemy-0.9.8-py2.7-macosx-10.6-intel.egg/sqlalchemy/util/langhelpers.py", line 60, in __exit__
compat.reraise(exc_type, exc_value, exc_tb)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/SQLAlchemy-0.9.8-py2.7-macosx-10.6-intel.egg/sqlalchemy/orm/session.py", line 2001, in _flush
flush_context.execute()
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/SQLAlchemy-0.9.8-py2.7-macosx-10.6-intel.egg/sqlalchemy/orm/unitofwork.py", line 372, in execute
rec.execute(self)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/SQLAlchemy-0.9.8-py2.7-macosx-10.6-intel.egg/sqlalchemy/orm/unitofwork.py", line 479, in execute
self.dependency_processor.process_deletes(uow, states)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/SQLAlchemy-0.9.8-py2.7-macosx-10.6-intel.egg/sqlalchemy/orm/dependency.py", line 1023, in process_deletes
secondary_update, secondary_delete)
File "/Users/derek/pyramid/myproject/lib/python2.7/site-packages/SQLAlchemy-0.9.8-py2.7-macosx-10.6-intel.egg/sqlalchemy/orm/dependency.py", line 1111, in _run_crud
result.rowcount)
StaleDataError: DELETE statement on table 'product_categories' expected to delete 1 row(s); Only 0 were matched.
Am I missing some sort of a 'gotcha' in this case? Seems like a pretty standard implementation. Why is it attempting to execute the DELETE statement twice?
After a bit more searching, I found the following link which suggests it's a MySQL bug:
https://groups.google.com/forum/#!topic/sqlalchemy/ajYLEuhEB9k
Thankfully, disabling supports_san_multi_rowcount helped!
engine = engine_from_config(settings, 'sqlalchemy.')
engine.dialect.supports_sane_rowcount = engine.dialect.supports_sane_multi_rowcount = False
Good enough for me for now. Here's another interesting resources I found along the way dealing with postgresql:
https://bitbucket.org/zzzeek/sqlalchemy/issue/3015/deletes-executed-twice-when-using
I'm trying to create following self-referencing EndpointsModel (the trick with _fix_up_properties() is taken from here: https://groups.google.com/forum/#!topic/appengine-ndb-discuss/1FmgEVK7JNM):
class EventFieldSchema(EndpointsModel):
name = ndb.StringProperty(required=True)
type = msgprop.EnumProperty(EventType, required=True)
EventFieldSchema.nested_fields = ndb.LocalStructuredProperty(EventFieldSchema,repeated=True)
EventFieldSchema._fix_up_properties()
This works for datastore model, but unfortunately, the nested_fields field won't be included into ProtoRPC message.
I've tried to manually specify message fields schema, by adding at the end following line:
EventFieldSchema._message_fields_schema = ('name', 'type', 'nested_fields')
but then app-engine fails, going into a loop, trying turn EventFieldSchema into ProtoRPC field:
Traceback (most recent call last):
File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/runtime/wsgi.py", line 240, in Handle
handler = _config_handle.add_wsgi_middleware(self._LoadHandler())
File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/runtime/wsgi.py", line 299, in _LoadHandler
handler, path, err = LoadObject(self._handler)
File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/runtime/wsgi.py", line 85, in LoadObject
obj = __import__(path[0])
File "/base/data/home/apps/s~project/eventregistry:dev.380885914276541023/main.py", line 3, in <module>
from er.api.event import EventRegistryApi
File "/base/data/home/apps/s~project/eventregistry:dev.380885914276541023/er/api/event.py", line 17, in <module>
class EventRegistryApi(remote.Service):
File "/base/data/home/apps/s~project/eventregistry:dev.380885914276541023/er/api/event.py", line 23, in EventRegistryApi
name='%s.insert' % RESOURCE_NAME)
File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/protorpc-1.0/protorpc/util.py", line 170, in positional_wrapper
return wrapped(*args, **kwargs)
File "/base/data/home/apps/s~project/eventregistry:dev.380885914276541023/endpoints_proto_datastore/ndb/model.py", line 1359, in method
kwargs[REQUEST_MESSAGE] = cls.ProtoModel(fields=request_fields)
File "/base/data/home/apps/s~project/eventregistry:dev.380885914276541023/endpoints_proto_datastore/ndb/model.py", line 1031, in ProtoModel
allow_message_fields=allow_message_fields)
File "/base/data/home/apps/s~project/eventregistry:dev.380885914276541023/endpoints_proto_datastore/ndb/model.py", line 969, in _MessageFields
proto_attr = to_proto(prop, field_index)
File "/base/data/home/apps/s~project/eventregistry:dev.380885914276541023/endpoints_proto_datastore/ndb/utils.py", line 137, in StructuredPropertyToProto
property_proto = property_proto_method()
File "/base/data/home/apps/s~project/eventregistry:dev.380885914276541023/endpoints_proto_datastore/ndb/model.py", line 1031, in ProtoModel
allow_message_fields=allow_message_fields)
File "/base/data/home/apps/s~project/eventregistry:dev.380885914276541023/endpoints_proto_datastore/ndb/model.py", line 969, in _MessageFields
proto_attr = to_proto(prop, field_index)
File "/base/data/home/apps/s~project/eventregistry:dev.380885914276541023/endpoints_proto_datastore/ndb/utils.py", line 137, in StructuredPropertyToProto
property_proto = property_proto_method()
File "/base/data/home/apps/s~project/eventregistry:dev.380885914276541023/endpoints_proto_datastore/ndb/model.py", line 1031, in ProtoModel
Is this a bug in EndpointsModel? What is the "proper" way of defining self-referencing EndpointsModels?
Having the same issue with self-referencing an EndpointsModel:
class UnitsProtoModel(EndpointsModel):
""" ProtoRPC Model for storing/retrieving a unit. """
_message_fields_schema = ('id', 'uic', 'parent_id', 'branch_id', 'name')
uic = ndb.StringProperty(required=True)
parent_id = ndb.StringProperty(required=True, default=None)
branch_id = ndb.StringProperty(required=True)
name = ndb.StringProperty(required=True)
abbreviated_name = ndb.StringProperty(default="")
flagged = ndb.BooleanProperty(default=False)
message = ndb.StringProperty(default="")
unit_created_at = ndb.DateTimeProperty(auto_now_add=True)
class UnitsCollection(EndpointsModel):
items = messages.MessageField(UnitsProtoModel, 1, repeated=True)
Error msg:
`File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine- default.bundle/Contents/Resources/google_appengine/lib/protorpc-1.0/protorpc/util.py", line 170, in positional_wrapper
return wrapped(*args, **kwargs)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/protorpc-1.0/protorpc/messages.py", line 1531, in init
raise FieldDefinitionError('Invalid message class: %s' % message_type)
FieldDefinitionError: Invalid message class:
UnitsProtoModel<abbreviated_name=StringProperty('abbreviated_name', default=''), branch_id=StringProperty('branch_id', required=True), flagged=BooleanProperty('flagged', default=False), message=StringProperty('message', default=''), name=StringProperty('name', required=True), owner=UserProperty('owner'), parent_id=StringProperty('parent_id', required=True), uic=StringProperty('uic', required=True), unit_created_at=DateTimeProperty('unit_created_at', auto_now_add=True)>`
I have a sqlalchemy model that I am searching with flask-whooshalchemy. I was looking to include the output of a method in the search fields but can't figure out how it's done or if it's even possible. The flask-whooshalchemy documentation is a little limited.
I'm currently trying something like this:
class Trade(db.Model):
__searchable__ = [
'species', 'nature', 'ability', 'move1', 'move2', 'move3', 'move4', 'ivSpread']
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
dex_no = db.Column(db.Integer)
species = db.Column(db.String(30))
male = db.Column(db.Boolean)
female = db.Column(db.Boolean)
nature = db.Column(db.String(30))
ability = db.Column(db.String(30))
iv_hp = db.Column(db.Integer)
iv_atk = db.Column(db.Integer)
iv_def = db.Column(db.Integer)
iv_spa = db.Column(db.Integer)
iv_spd = db.Column(db.Integer)
iv_spe = db.Column(db.Integer)
move1 = db.Column(db.String(30))
move2 = db.Column(db.String(30))
move3 = db.Column(db.String(30))
move4 = db.Column(db.String(30))
def ivSpread(self):
ivs = [
self.iv_hp,
self.iv_atk,
self.iv_def,
self.iv_spa,
self.iv_spd,
self.iv_spe
]
return "/".join(ivs)
def __repr__(self):
return '<Post %r: %r>' % (self.owner.nickname, self.species)
Let me know if I can provide any more information. Suggestions of alternate modules to use is fine too, I'm sure there could be something more powerful than flask-whooshalchemy out there. It hasn't been pushed to in 2 years after all.
e: Using the above as is and with the #property suggestion provided by Mark Hildreth below, I get the following traceback.
whoosh.fields.UnknownFieldError
UnknownFieldError: No field named 'ivSpread' in <Schema: ['ability', 'gender', 'id', 'move1', 'move2', 'move3', 'move4', 'nature', 'species']>
Traceback (most recent call last):
File "c:\Python27\lib\site-packages\flask\app.py", line 1701, in __call__
return self.wsgi_app(environ, start_response)
File "c:\Python27\lib\site-packages\flask\app.py", line 1689, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "c:\Python27\lib\site-packages\flask\app.py", line 1687, in wsgi_app
response = self.full_dispatch_request()
File "c:\Python27\lib\site-packages\flask\app.py", line 1360, in full_dispatch_request
rv = self.handle_user_exception(e)
File "c:\Python27\lib\site-packages\flask\app.py", line 1358, in full_dispatch_request
rv = self.dispatch_request()
File "c:\Python27\lib\site-packages\flask\app.py", line 1344, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "c:\Users\Shane\Documents\Coding\python\flask\trade_lister\app\views.py", line 172, in new_trade
db.session.commit()
File "c:\Python27\lib\site-packages\sqlalchemy\orm\scoping.py", line 114, in do
return getattr(self.registry(), name)(*args, **kwargs)
File "c:\Python27\lib\site-packages\sqlalchemy\orm\session.py", line 703, in commit
self.transaction.commit()
File "c:\Python27\lib\site-packages\sqlalchemy\orm\session.py", line 367, in commit
self.session.dispatch.after_commit(self.session)
File "c:\Python27\lib\site-packages\sqlalchemy\event.py", line 319, in __call__
fn(*args, **kw)
File "c:\Python27\lib\site-packages\flask_sqlalchemy\__init__.py", line 170, in session_signal_after_commit
models_committed.send(session.app, changes=d.values())
File "c:\Python27\lib\site-packages\blinker\base.py", line 267, in send
for receiver in self.receivers_for(sender)]
File "c:\Python27\lib\site-packages\flask_whooshalchemy.py", line 256, in _after_flush
writer.update_document(**attrs)
File "c:\Python27\lib\site-packages\whoosh\writing.py", line 477, in update_document
self.add_document(**fields)
File "c:\Python27\lib\site-packages\whoosh\writing.py", line 730, in add_document
self._check_fields(schema, fieldnames)
File "c:\Python27\lib\site-packages\whoosh\writing.py", line 718, in _check_fields
% (name, schema))
UnknownFieldError: No field named 'ivSpread' in <Schema: ['ability', 'gender', 'id', 'move1', 'move2', 'move3', 'move4', 'nature', 'species']>
I don't know nearly enough about Woosh or Flask-Wooshalchemy, so this might be wrong, but I imagine you might be able to do something like this...
class Trade(db.Model):
#...
#property
def ivSpread(self):
#...
This uses a property to make the method call look like an attribute, so instead of doing...
t = Trade(...)
print t.ivSpread()
...you would do...
t = Trade(...)
print t.ivSpread
This would be necessary because Flask-WooshAlchemy seems to be assuming that the searchable item is an attribute, and at this point it's just pulling the method without calling it.
If you need to have ivSpread stay a method, you can use a wrapper:
class Trade(db.Model):
#...
def ivSpread(self):
#...
#property
def ivSpreadProp(self):
return self.ivSpread()
Then you would need to make ivSpreadProp searchable rathe rthan ivSpread.
Edit:
Looks like what you are trying to do is not currently possible. See here:
searchable = set(model.__searchable__)
for field in model.__table__.columns:
if field.primary_key:
schema[field.name] = whoosh.fields.ID(stored=True, unique=True)
primary = field.name
if field.name in searchable and isinstance(field.type,
(sqlalchemy.types.Text, sqlalchemy.types.String,
sqlalchemy.types.Unicode)):
schema[field.name] = whoosh.fields.TEXT(
analyzer=StemmingAnalyzer())
Flask-WhooshAlchemy assumes that items in the __searchable__ attribute are going to be columns defined by your model using SQLAlchemy. Flask-WhooshAlchemy would need to allow you to achieve your goal cleanly.