SQLAlchemy (sqlite3.OperationalError) no such table: - python

I'm using SQLAlchemy to connect to an in-memory SQLite database.
In my main.py file I have
engine = create_engine('sqlite:///:memory:', echo = True)
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
sess = Session()
After this I create a new thread, where I pass the session to
thread = MyThread(sess)
thread.start()
I have created my tables in tables.py like this
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, Float
Base = declarative_base()
class My_Entry(Base):
__tablename__ = 'my_entry'
id = Column(Integer, primary_key=True)
name = Column(String)
url = Column(String)
My_Thread looks like this
class MyThread(Thread):
def __init__(sess):
Thread.__init__(self)
self.sess = sess
def run(self):
last_entry_url = self.sess.query(My_Entry).filter_by(name=key).all()[-1]
I try to query the database in the run function of my thread
last_entry_url = self.sess.query(My_Entry).filter_by(name=key).all()[-1]
but this throws an error
(sqlite3.OperationalError) no such table: my_entry
But creating the tables is one of the first things I do?
Indeed, using the echo=True gives me
CREATE TABLE my_entry (
id INTEGER NOT NULL,
name VARCHAR,
url VARCHAR,
PRIMARY KEY (id)
)
I have a sleep statement before running MyThread. My other tables work just fine, it's only this one table that doesn't.
bonus question: is there another way to get the last entry instead of all()[-1]? I assume there is but I didn't find anything

Related

Why doesn't schema_translate_map change schema?

I'm trying to use schema_translate_map to change a schema:
Base = declarative_base()
class DataAccessLayer():
def __init__(self):
conn_string = "mysql+mysqlconnector://root:root#localhost/"
self.engine = create_engine(conn_string)
Session = sessionmaker()
Session.configure(bind=self.engine)
self.session = Session()
def change_schema(self):
self.session.connection(execution_options={"schema_translate_map": {"belgarath": "belgarath_test"}})
class Player(Base):
__tablename__ = "player"
__table_args__ = {'schema': "belgarath"}
id_ = Column(Integer, primary_key=True)
dal = DataAccessLayer()
dal.change_schema()
qry = dal.session.query(Player.id_)
print(qry)
However, the SQL comes out as:
SELECT belgarath.player.id_ AS belgarath_player_id_
FROM belgarath.player
Instead of:
SELECT belgarath_test.player.id_ AS belgarath_test_player_id_
FROM belgarath_test.player
Where am I going wrong?
Try what happens if you simply append .all() to your qry:
from sqlalchemy import Integer
from sqlalchemy import Column
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class DataAccessLayer():
def __init__(self):
conn_string = "sqlite:///:memory:"
#conn_string = "mysql+mysqlconnector://root:root#localhost/"
self.engine = create_engine(conn_string)
Session = sessionmaker()
Session.configure(bind=self.engine)
self.session = Session()
def change_schema(self):
self.session.connection(execution_options={"schema_translate_map": {"belgarath": "belgarath_test"}})
class Player(Base):
__tablename__ = "player"
__table_args__ = {'schema': "belgarath"}
id_ = Column(Integer, primary_key=True)
dal = DataAccessLayer()
dal.change_schema()
qry = dal.session.query(Player.id_)
print(qry.all())
Output (without trace):
OperationalError: (sqlite3.OperationalError) no such table: belgarath_test.player
[SQL: SELECT belgarath_test.player.id_ AS belgarath_player_id_
FROM belgarath_test.player]
(Background on this error at: http://sqlalche.me/e/13/e3q8)
I'm not an expert, but I guess this might be related to the following issue:
the schema translate feature takes place within the compiler and this is plainly wrong. the schema assignment should be taking place after the SQL is generated so that we only need one cache key. This is along the lines of #5002 however I think even the existing cache key mechanism used with baked etc. needs to pull the schema translate out of the compiler entirely for 1.4 and add it to the translations which occur from the ExecutionContext, along with the expanding parameter sets of logic. schema translate is intended to service many hundreds / thousands of schemas so having this occur pre-cache has to change.
I guess that Query API is not aware of execution_options in connection. Try not to mix this two approaches.
dal = DataAccessLayer()
dal.change_schema()
qry = dal.session.connection().execute(Player.__table__.select())
print(qry)
Result:
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: belgarath_test.player
[SQL: SELECT belgarath_test.player.id_
FROM belgarath_test.player]
(Background on this error at: http://sqlalche.me/e/13/e3q8)

SQLAlchemy: update & delete value from database

I'm newer in SQLAlchemy I use some examples to create table and insert information to it and it's working 100% .
But what I didn't find is some example for how can I update & delete some information from the database.
What I'm doing is :
from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
Base = declarative_base()
## create
class Person(Base):
__tablename__ = 'person'
id = Column(Integer, primary_key=True)
name = Column(String(250), nullable=False)
engine = create_engine('sqlite:///database.db')
Base.metadata.create_all(engine)
## insert
Base.metadata.bind = engine
DBSession = sessionmaker(bind=engine)
session = DBSession()
new_person = Person(name='new person')
session.add(new_person)
session.commit()
## fetch
getperson = session.query(Person).first()
print getperson.name
# this will print : new person
# I need some example to how can I update and delete this : new person
So in this code it'll print "new person" my question is how can I update or delete it ?
Here's some example on each CRUD operation in sqlalchemy (ommiting Create, Read as you already know how to perform those):
First, necessary imports and configs for any operation:
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
# Category, Item, User are my tables
from database_setup import Base, Category, Item, User
# Generating session to connect to the db's ORM
engine = create_engine('sqlite:///catalogwithusers.db') # my db
Base.metadata.bind = engine
DBSession = sessionmaker(bind = engine)
session = DBSession()
Then peforming an update:
# Get the item filtering by it's id using a one() query on Item table
# If query is not empty, update the attributes, add query to session and commit
q = session.query(Item).filter_by(id=item_id).one()
if q != []:
q.name = edited_name
q.description = edited_description
session.add(q)
session.commit()
Finally, performing a deletion:
# Again get the item similarly to the example above
# Then if query returned results, use the delete method and commit
q = session.query(Item).filter_by(id=item_id).one()
if q != []:
session.delete(q)
session.commit()
These examples are taken from here. I suggest you have a look. ORM Creation is inside database_setup.py and CRUD ops are performed inside project.py and populatecatalog.py.

Concurrent atomic select-update

How can I, using sqlalchemy, do something like this?
user = session.query("select * from user")
if user.state == "active"
session.query("update user set state = 'inactive' where id = %d" % user.id)
I need the select and update to be one atomic operation. Another program should not be able to select/update the user while the operation is going.
How can I do it concurrently?
Note: I need to know if we succeeded in change the state or not.
How can I achieve that?
Am I doing it wrong?
Should it be a stored procedure?
Should I use database "lock"?
You can do this by setting an isolation level of Serializable, which can be done on a specific session with SQLAlchemy using session.connection(execution_options={'isolation_level': 'SERIALIZABLE'}). If two connections conflict (they both read before the other wrote), committing the transaction will fail, and you can just loop until it goes through.
from sqlalchemy import Column, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy.types import Boolean, Integer, String
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False)
active = Column(Boolean, nullable=False)
url = 'postgresql://postgres#localhost/test'
engine = create_engine(url, echo=True)
if not engine.dialect.has_table(engine.connect(), 'users'):
Base.metadata.create_all(bind=engine)
Session = sessionmaker(bind=engine)
session = Session()
session.add(User(name="remram", active=True))
session.commit()
Session = sessionmaker(bind=engine)
session = Session()
session.connection(execution_options={'isolation_level': 'SERIALIZABLE'}) # Commenting this line will make this unsafe in a concurrent environment
user = session.query(User).filter(User.name == "remram").one()
if user.active:
user.active = False
raw_input() # So you can run this twice
session.commit()
If your database supports SELECT FOR UPDATE
(ie: PostgreSQL) you could use:
user = session.query("select * from user where id = %d for update" % theId)
if user.state == "active"
session.query("update user set state = 'inactive' where id = %d" % user.id)

Inserting objects and using ids in SqlAlchemy

I have a table and populating it with object list then I need to use their IDs, but I am getting an
Instance <location at 0x457f3b0> is not bound to a Session; attribute refresh operation cannot proceed
error.
I am populating a list with objects and send it to a function to insert all at once. Then I try to use IDs.
Here is my insert all function:
def insertlocations(locationlist):
session.add_all(locationlist)
session.commit()
session.close()
then I try to get IDs:
insertlocations(neighbourhoodlist)
session.flush(neighbourhoodlist)
for neighbourhood in neighbourhoodlist:
print neighbourhood.locationid
Session is global by the way. Any further info needed?
The data are inserted, as I look in the MySQL table.
Most likely your problem is that you already close() the session in your insertlocations() function.
When you then access neighbourhood.locationid, the session is closed and thatneighbourhood object isn't bound to a session any more.
For example, this should work:
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import sessionmaker
engine = create_engine('sqlite:///example.db')
engine.echo = True
Base = declarative_base()
class Location(Base):
__tablename__ = 'locations'
locationid = Column(Integer, primary_key=True)
name = Column(String)
address = Column(String)
def __init__(self, name, address):
self.name = name
self.address = address
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
def insertlocations(locationlist):
session.add_all(locationlist)
session.commit()
loc1 = Location('loc1', 'Foostreet 42')
loc2 = Location('loc2', 'Barstreet 27')
neighbourhoodlist = [loc1, loc2]
insertlocations(neighbourhoodlist)
for neighbourhood in neighbourhoodlist:
print neighbourhood.locationid
session.close()
Move session.close() out of your function and do it after you're done using that session.
Ditch the session.flush(), it's not needed since you already commit the session when you add the objects.

How to (re-) arrange this python code without breaking sqlalchemy relevant dependencies?

I have a little problem regarding "arranging of code, which depends on each other" when setting an sqlalchemy mapping to a sqlite database in python.
The goal is to write a script, whcih satisfies the following conditions:
Gets a filename parameter as command line argument.
Based on the filename it should create an absolute path to the SQLite database.
It should connect to the database and create an engine
It shall reflect the tables in this databases.
It should monkey patch the column id in the table mytable as a primary key column, since the table doesn't habe a primary key and sqlalchemy requires one.
So I came up with this:
from sqlalchemy import create_engine, Column, Integer
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
def create_path(file_name):
# generate absolute path to file_name
path_to_file = create_path("my_file_name.sqlite")
engine = create_engine('sqlite:///{path}'.format(path=path_to_file), echo=False)
Base = declarative_base()
Base.metadata.create_all(engine)
class MyTable(Base):
__tablename__ = 'my_table'
__table_args__ = {'autoload': True}
id = Column(Integer, primary_key=True) # Monkey patching the id column as primary key.
def main(argv):
# parse file_name here from argv
Session = sessionmaker(bind=engine)
session = Session()
for row in session.query(MyTable).all():
print row
return "Stop!"
if __name__ == '__main__':
sys.exit(main())
But this is a doomed construction and I don't see how I could rearrange my code without breaking the dependencies.
To be able to create MyClass I need Base to be defined before MyClass.
To be able to create Base I need engine to be defined before Base.
To be able to create engine I need path_to_file to be defined before engine.
To be able to create path_to_file outside of main() I need create_file() to be defined before path_to_file.
And so on...
Hopefully you see where I am stuck...
Any suggestions?
Edit: By the way, the code works, but only with a hardcoded filename in the top of the script.
I do not see why you could not use the declarative mapping still complety. I think the key to the proper dependencies is to know what to put in the module and what in the script/function. With python, you can easily define the class inside the run_script function.
from sqlalchemy import create_engine, Column, Integer
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
def create_path(filename):
import os
fn = os.path.abspath(os.path.join(os.path.dirname(__file__), 'sqlite_files', filename))
return fn
def run_script(filename):
path_to_file = create_path(filename)
engine = create_engine('sqlite:///{path}'.format(path=path_to_file), echo=True)
Session = sessionmaker(bind=engine)
Base = declarative_base(bind=engine)
# object model
class MyTable(Base):
__tablename__ = 'my_table'
__table_args__ = {'autoload': True}
id = Column(Integer, primary_key=True) # Monkey patching the id column as primary key
# script itself
session = Session()
for row in session.query(MyTable).all():
print row
return "Stop!"
def main(argv):
assert argv, "must specify a database file name"
run_script(argv[0])
if __name__ == '__main__':
import sys
sys.exit(main(sys.argv))
I solved my problem using the classical mapping approach of SQLAlchemy:
from sqlalchemy import create_engine, Column, Integer, MetaData, Table
from sqlalchemy.orm import sessionmaker, mapper
class MyTable(object):
pass
def main():
path_to_file = create_path("my_file_name.sqlite")
engine = create_engine('sqlite:///{path}'.format(path=path_to_file), echo=False)
metadata = MetaData()
metadata.bind = engine
my_table = Table('mytable',
metadata,
Column('id', Integer, primary_key=True), # Monkey patching the id column as primary key.
autoload=True,
autoload_with=engine)
mapper(MyTable, my_table)
Session = sessionmaker(bind=engine)
session = Session()
# Do Stuff!
I don't have the capability to do any testing at my current location. But I suggest moving all of that code to main() as follows. Also, MyTable subclasses declarative_base.
from sqlalchemy import create_engine, Column, Integer
from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import declarative_base
class MyTable(declarative_base):
__tablename__ = 'my_table'
__table_args__ = {'autoload': True}
id = Column(Integer, primary_key=True) # Monkey patching the id column as primary key.
def create_path(file_name):
# generate absolute path to file_name
def main(argv): # parse file_name here from argv
path_to_file = create_path("my_file_name.sqlite")
engine = create_engine('sqlite:///{path}'.format(path=path_to_file), echo=False)
Base = MyTable()
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
for row in session.query(MyTable).all():
print row
return "Stop!"
if __name__ == '__main__':
sys.exit(main())

Categories