SQLAlchemy Attempting to Twice Delete Many to Many Secondary Relationship - python

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

Related

SQLAlchemy: How do I create a 1:n relationship? [duplicate]

This question already has answers here:
SQLAlchemy multiple foreign keys in one mapped class to the same primary key
(2 answers)
Closed 5 years ago.
I am about to create a certain 1:n-realtionship with SQLAlchey.
I have brought two pictures for you, so you can see what this is about. First you'll see a picture of the EER model. In this EER model, I created a 1: n relationship between the person table and the family table. Any person is stored in the person table. And we all know that people can be in a relationship with one another (mother, father, daughter, son, cousin, cousin, nephew, etc ...). For this reason I have set up the family table.
In order to play the whole time exemplary, I have filled the tables with fictitious data. With a look at the family table, we see in the first column, which is the central person, namely Hans Schmidt (with the ID 1). In the Family table the following persons are saved by their foreign key: Kurt Schmidt (son), Gerda Schmidt (wife), Gisela Schmidt (Hans' mother), and Julia Schmidt (daughter). I would like to point out Hans Schmidt's relationship.
And in my source code, I have mapped this ORM model as follows:
class FAMILY(Base):
__tablename__ = "family"
id = Column(Integer, primary_key=True, unique=True, autoincrement=True)
status = Column(String(255), nullable=False)
person_id = Column(Integer, ForeignKey('person.id'))
person = relationship("PERSON", backref='family', lazy='dynamic')
family_person_id = Column(Integer, ForeignKey('person.id'))
family_person = relationship("PERSON", backref='family', lazy='dynamic')
class PERSON(Base):
__tablename__ = "person"
id = Column(Integer, primary_key=True, unique=True, autoincrement=True)
nickname = Column(String(255))
alias_name = Column(String (255))
name_normally_used = Column(String(50), nullable=False)
first_middle_name = Column(String(255))
last_name = Column(String(100))
When creating the model, SQLAlchemy does not cause any problems (echo is true, so I could track it there were no problems.). However, SQLAlchemy throws an exception when I start the user interface, where you can manage the data of a person.
Traceback (most recent call last):
File "D:\Dan\Python\Xarphus\xarphus\subclass_master_data_load_data_item.py", line 140, in populate_item
self.populate_item_signal.emit(next(self._element))
File "D:\Dan\Python\Xarphus\xarphus\core\manage_data_manipulation_master_data.py", line 205, in select_all
for record in dict_store_session_query[category]():
File "D:\Dan\Python\Xarphus\xarphus\core\manage_data_manipulation_master_data.py", line 191, in <lambda>
'person_gender': lambda: self._session.query(PERSON_GENDER),
File "C:\Python27\lib\site-packages\sqlalchemy\orm\session.py", line 1362, in query
return self._query_cls(entities, self, **kwargs)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\query.py", line 139, in __init__
self._set_entities(entities)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\query.py", line 150, in _set_entities
self._set_entity_selectables(self._entities)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\query.py", line 180, in _set_entity_selectables
ent.setup_entity(*d[entity])
File "C:\Python27\lib\site-packages\sqlalchemy\orm\query.py", line 3585, in setup_entity
self._with_polymorphic = ext_info.with_polymorphic_mappers
File "C:\Python27\lib\site-packages\sqlalchemy\util\langhelpers.py", line 764, in __get__
obj.__dict__[self.__name__] = result = self.fget(obj)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\mapper.py", line 1948, in _with_polymorphic_mappers
configure_mappers()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\mapper.py", line 2869, in configure_mappers
raise e
InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers. Triggering mapper: 'Mapper|FAMILY|family'. Original exception was: Could not determine join condition between parent/child tables on relationship FAMILY.person - there are multiple foreign key paths linking the tables. Specify the 'foreign_keys' argument, providing a list of those columns which should be counted as containing a foreign key reference to the parent table.
Traceback (most recent call last):
File "D:\Dan\Python\Xarphus\xarphus\subclass_master_data_load_data_item.py", line 140, in populate_item
self.populate_item_signal.emit(next(self._element))
File "D:\Dan\Python\Xarphus\xarphus\core\manage_data_manipulation_master_data.py", line 205, in select_all
for record in dict_store_session_query[category]():
File "D:\Dan\Python\Xarphus\xarphus\core\manage_data_manipulation_master_data.py", line 194, in <lambda>
'person_title': lambda: self._session.query(PERSON_TITLE),
File "C:\Python27\lib\site-packages\sqlalchemy\orm\session.py", line 1362, in query
return self._query_cls(entities, self, **kwargs)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\query.py", line 139, in __init__
self._set_entities(entities)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\query.py", line 150, in _set_entities
self._set_entity_selectables(self._entities)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\query.py", line 180, in _set_entity_selectables
ent.setup_entity(*d[entity])
File "C:\Python27\lib\site-packages\sqlalchemy\orm\query.py", line 3585, in setup_entity
self._with_polymorphic = ext_info.with_polymorphic_mappers
File "C:\Python27\lib\site-packages\sqlalchemy\util\langhelpers.py", line 764, in __get__
obj.__dict__[self.__name__] = result = self.fget(obj)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\mapper.py", line 1948, in _with_polymorphic_mappers
configure_mappers()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\mapper.py", line 2872, in configure_mappers
mapper._post_configure_properties()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\mapper.py", line 1765, in _post_configure_properties
prop.init()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\interfaces.py", line 184, in init
self.do_init()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\relationships.py", line 1654, in do_init
self._setup_join_conditions()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\relationships.py", line 1729, in _setup_join_conditions
can_be_synced_fn=self._columns_are_mapped
File "C:\Python27\lib\site-packages\sqlalchemy\orm\relationships.py", line 1987, in __init__
self._determine_joins()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\relationships.py", line 2114, in _determine_joins
% self.prop)
AmbiguousForeignKeysError: Could not determine join condition between parent/child tables on relationship FAMILY.person - there are multiple foreign key paths linking the tables. Specify the 'foreign_keys' argument, providing a list of those columns which should be counted as containing a foreign key reference to the parent table.
And there we would be. SQLALchey apparently has a problem with the two foreign keys that come from the same table? Question to you: How should modeling be done best to show the interrelationship between people? Because after my reasoning, I need at least two foreign keys from the person table, in order to establish a relationship among the persons.
There are two main problems in your definition of mapper class FAMILY.
(1) You have referred PERSON as foreign key twice, so you have to explicitly tell SQLAlchemy how to join the PERSON, please set foreign_keys parameter for each relationship.
(2) You have used the same value as backref. The value of backref (FAMILY), would become the property name of PERSON class. Look in your FAMILY, there are two properties named person and family_person, then there should be two different properties for the PERSON class.
Also, in your code, the relationship between FAMILY and PERSON is MANY TO ONE, thus the dynamic value is not valid for the parameter lazy, you should use the default one. Here is the sample code:
class FAMILY(Base):
__tablename__ = "family"
id = Column(Integer, primary_key=True, unique=True, autoincrement=True)
status = Column(String(255), nullable=False)
person_id = Column(Integer, ForeignKey('person.id'))
person = relationship("PERSON", backref='family_to',
foreign_keys=[person_id],
)
family_person_id = Column(Integer, ForeignKey('person.id'))
family_person = relationship("PERSON",
foreign_keys=[family_person_id],
backref='family_from')
Here are some useful links related to your question: Refer a table twice, Relationship configration
Thanks!

IntegrityError: ERROR: null value in column "user_id" violates not-null constraint

Using: postgres (PostgreSQL) 9.4.5
I just migrated a sqlite3 db onto a postgresql db. For some reason since this migration, when I try to create a user, an error regarding the user_id (which is a primary key) is being raised. This was not an issue before with sqlite3. I have spent time looking through the docs and stack questions, but remain confused.
Inside api.create_user():
api.create_user(username ='lola ', firstname ='cats ', lastname ='lcatk', email='cags#falc.com')
sqlalchemy db Model:
class User(Base):
__tablename__ = 'users'
#user_id = Column(Integer, primary_key=True)
#changed to:
id = Column(Integer, primary_key=True)
username = Column(String(50))
firstname = Column(String(50))
lastname = Column(String(50))
email = Column(String(300))
password = Column(String(12))
institution = Column(String(50))
def __init__(self, username, firstname, lastname, email):
self.username = username
self.firstname = firstname
self.lastname = lastname
self.email = email
def __repr__(self):
return "<User(username ='%s', firstname ='%s', lastname ='%s', email='%s')>" % (self.username, self.firstname, self.lastname, self.email)
pyramid views.py:
#view_config(#code supplying the template and etc.)
def save_assessment_result(request):
with transaction.manager:
username = request.params['username']
firstname = request.params['firstname']
lastname = request.params['lastname']
email = request.params['email']
user = api.create_user(username, firstname, lastname, email)
#mode code to commit and etc.
transaction.commit()
return HTTPCreated()
postgres Server.log:
ERROR: null value in column "user_id" violates not-null constraint
DETAIL: Failing row contains (null, lola , cats , lcatk, cags#falc.com, null, null, 2015-10-19 23:02:21.560395).
STATEMENT: INSERT INTO users (username, firstname, lastname, email, password, institution, created_on) VALUES ('lola ', 'cats ', 'lcatk', 'cags#falc.com', NULL, NULL, '2015-10-19T23:02:21.560395'::timestamp) RETURNING users.user_id
Traceback:
015-10-19 19:02:21,563 ERROR [pyramid_debugtoolbar][Dummy-3] Exception at http://0.0.0.0:6432/save_assessment_result
File "/Users/ack/code/venv/NotssWEB/notssweb/views/default.py", line 61, in save_assessment_result
assessment = api.retrieve_assessment(assessment_id)
File "/usr/local/lib/python2.7/site-packages/notssdb/api/object.py", line 112, in retrieve_assessment
filter(Assessment.assessment_id == something_unique).one()
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2473, in one
ret = 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)
IntegrityError: (raised as a result of Query-invoked autoflush; consider using a session.no_autoflush block if this flush is occurring prematurely) (psycopg2.IntegrityError) null value in column "user_id" violates not-null constraint
DETAIL: Failing row contains (null, lola , cats , lcatk, cags#falc.com, null, null, 2015-10-19 23:02:21.560395).
[SQL: 'INSERT INTO users (username, firstname, lastname, email, password, institution, created_on) VALUES (%(username)s, %(firstname)s, %(lastname)s, %(email)s, %(password)s, %(institution)s, %(created_on)s) RETURNING users.user_id'] [parameters: {'username': u'lola ', 'firstname': u'cats ', 'lastname': u'lcatk', 'institution': None, 'created_on': datetime.datetime(2015, 10, 19, 23, 2, 21, 560395), 'password': None, 'email': u'cags#falc.com'}]
2015-10-19 19:02:21,564 DEBUG [notssweb][Dummy-3] route matched for url http://0.0.0.0:6432/_debug_toolbar/exception?token=a30c0989db02aeff9cd2&tb=4459323984; route_name: 'debugtoolbar', path_info: u'/_debug_toolbar/exception', pattern: '/_debug_toolbar/*subpath', matchdict: {'subpath': (u'exception',)}, predicates: '
First.
I changed the id naming convention from user_id to simply id in the database (this is true for all others).
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
Second.
The issue was found in dumping the original sqlite db file into postgres (from sqlite3 --> postgres) instead of creating the db in postgres.
So, I ran the original code in SQLAlchemy, but this time pointing to the postgres db:
engine = create_engine('postgresql://localhost/some_db')
This created the needed relationships and sequences (shown via \ds in postgres, psql). Issue resolved.

many-to-many relationship in sqlalchemy [duplicate]

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!

session is already flushing when I use #observes

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.

Adding an object to a one-to-many relationship in Pyramid, SQLAlchemy

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

Categories