Query an existing mysql table in database using flask-sqlalchemy - python

I have an flask app, using flask-slqalchemy to query a mysql database
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:password#localhost/abc'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
there is a table "users" in "abc" database and it is already populated with several hundred rows.
Now i need to import this existing table, rather than first defining it with db.Model
how do i call the table?
if i do this
from sqlalchemy import Table
USERS = Table('users', db.metadata,autoload=True, autoload_with=db.engine)
then i am not able to make a query like
USERS.query.filter_by(done=1).with_entities(USERS.name,USERS.country).paginate(page, 15, False)
it generates an error
AttributeError: 'Table' object has no attribute 'query'
because this is sqlchemy command, not flask-sqlchemy, i dont fully understand this.
I have to first define the table USERS like i am creating it for the first time :
class USERS(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.VARCHAR(500))
country = db.Column(db.VARCHAR(50))
def __init__(self, id, name, country):
self.id = id
self.name = name
self.country = country
def __repr__(self):
return self.id
only then i am able to use USERS to query the database through flask-sqlalchemy
How do i access the an existing table users using flask-sqlchemy in an flask app?

In sqlalchemy you should query table(s) with session if you want to query Table(). Because 'Table' object has no attribute 'query'. And you do not need to create table if it has existed, just use it. sqlalchemy existing database query
from sqlalchemy import Table, Column, String, create_engine, MetaData
from sqlalchemy.orm import sessionmaker
engine = create_engine()
metadata = MetaData()
test_ = Table('test', metadata,
Column('msg', String, primary_key=True),
Column('msg_', String)
)
Session = sessionmaker(bind=engine)
session = Session()
print(session.query(test_).filter_by(msg_ = "test").with_entities("msg","msg_").one())
# ('t', 'test')
In flask_sqlalchemy, it almost same as sqlalchemy did.
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = ""
db = SQLAlchemy(app)
class test(db.Model):
msg = db.Column(db.String, primary_key=True)
msg_ = db.Column(db.String)
def __init__(self, msg, msg_):
self.msg = msg
self.msg_ = msg_
def __repr__(self):
return "msg: {} msg_: {}".format(self.msg,self.msg_)
result = test.query.filter_by(msg_="test").one()
print(result)
print(result.msg,result.msg_)
'''
msg: t msg_: test
t test
'''

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)

How can I create a table if not exist on Flask with SQLAlchemy?

I am using SQLAlchemy and I have the following code:
Model:
class User(db.Model):
__tablename__ = 'user'
__table_args__ = {'schema': 'task', 'useexisting': True}
id = Column(Integer, primary_key=True, autoincrement=True)
firstname = Column(String)
.env
SQLALCHEMY_DATABASE_URI = os.getenv('SQLALCHEMY_DATABASE_URI')
app.py
def create_app(config_file):
"""Create a Flask application using the app factory pattern."""
app = Flask(__name__)
"""Load configuration."""
app.config.from_pyfile(config_file)
"""Init app extensions."""
from .extensions import db
db.init_app(app)
This creates the SQLite file if it does not exist, but not the tables of each model.
The question is what can I do in order to create the tables for each model?
Just add:
db.create_all()
in app.py at the end of create_app().
create_all() will create the tables only when they don't exist and would not change the tables created before.
If you want to create the database and the tables from the command line you can just type:
python
from app.py import db
db.create_all()
exit()
The working example:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.secret_key = "Secret key"
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///my_database.sqlite3"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)
class Data(db.Model):
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(50))
email = db.Column(db.String(50))
phone = db.Column(db.String(50))
db.create_all()
# add a row
# comment out after the 1st run
table_row = Data(name="My Name", email="myemail#mail.com", phone="123456")
db.session.add(table_row)
db.session.commit()
print "A row was added to the table"
# read the data
row = Data.query.filter_by(name="My Name").first()
print "Found:", row.email, row.phone
if __name__ == "__main__":
app.run(debug=True)
This is for Python 2.7, to run with Python 3.x just change the the print statements to call the print() function.
NOTE:
When using automatic model class constructor the arguments passed to model class constructor must be keyword arguments or there will be an error. Otherwise you can override the __init__() inside Data() class like this:
def __init__(self, name, email, phone, **kwargs):
super(Data, self).__init__(**kwargs)
self.name = name
self.email = email
self.phone = phone
In that case you don't have to use keyword arguments.
you need first to use Shell Context Processor to load automatically all Model objects
in app.py add
# import all models from all blueprints you have
from .users.models import User
#app.shell_context_processor
def make_shell_context():
return { 'db': db, 'User': User .. }
and then use Flask shell command
(venv) $ flask shell
>>> db
<SQLAlchemy engine=sqlite:///data-dev.sqlite> # something similar to that
>>>
>>> User
<class 'api.users.models.User'>
>>>
>>> # to create database if not exists and all tables, run the command below
>>> db.create_all()
maybe you'll need Flask-Migrate for advanced operations (migrations) on your database: create new table, update tables / fields ...

SQLAlchemy (sqlite3.OperationalError) no such table:

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

Flask SQLAlchemy does not close MySQL database connections

I have a Flask app using Flask-SQLAlchemy with a MySQL database where the db is defined as the following:
db.py:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
main.py:
from db import db
app = Flask(__name__)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = "mysql+pymysql://" + \
DB_USERNAME + ":" + DB_PASSWORD + "#" + DB_HOST + "/" + DB_DATABASE
db.init_app(app)
#app.teardown_appcontext
def teardown_db(error):
db.session.close()
db.engine.dispose()
user.py:
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
I query my database using models using either db.engine.execute() to write raw SQL queries where required or use the integrated Flask-SQLAlchemy APIs for reading data such as User.query.filter_by().all().
I write new data into the db using the following:
new_user_entry = User(username = "abc", email = "abc#example.com")
db.session.add(new_user_entry)
db.session.commit()
I am monitoring my MySQL server using show processlist and I notice that the database connections keep increasing by 2 for every single request that comes my way. The database connections seem to reset only when I stop the Flask process. With time, the MySQL server throws the below error:
`sqlalchemy.exc.TimeoutError: QueuePool limit of size 10 overflow 10 reached, connection timed out, timeout 30 (Background on this error at: http://sqlalche.me/e/3o7r)`
I am serving the app using gunicorn and gevent/eventlet with 2 worker processes. I use python3.
Am I missing something here? I tried ending the db session and disposing the engine, but this does not seem to work.
I finally found a fix to the above problem.
I used the declarative model defined in here instead of following the quickstart documentation for Flask-SQLAlchemy given here.
The changed files are as follows:
db.py:
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine(DB_URI, convert_unicode=True)
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()
def init_db():
import user
Base.metadata.create_all(bind=engine)
main.py:
from db import init_db, db_session
init_db()
#app.teardown_appcontext
def shutdown_session(exception=None):
db_session.remove()
user.py:
from sqlalchemy import Column, Integer, String
from data_models.db import Base
class User(Base):
id = db.Column(Integer, primary_key=True)
username = db.Column(String(80), unique=True, nullable=False)
email = db.Column(String(120), unique=True, nullable=False)
To query for records we could either use User.query.filter_by().all() or db_engine.execute().
To write new data into the database, we can use the following:
new_user_entry = User(username = "abc", email = "abc#example.com")
db_session.add(new_user_entry)
db_session.commit()
In case we need to close session before creating a new child process (what is recommended), this is what we should use:
db.session.remove()
db.engine.dispose()
Like
from multiprocessing import Process
from app import db
#app.route('/process/start/', methods = ["GET"])
def process_start():
db.session.remove()
db.engine.dispose()
p = Process(target = long_task)
p.start()
return 'started the long task'
def long_task():
'''
do long task
'''
Use with statement, there is a test:
def test():
with db.session() as dbss:
qss = models.WhateverModel.query.session
assert dbss == qss

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.

Categories