I'm having issues with reading data out of mysql with a cursor and displaying it over HTTP via flask. Everytime I run this code:
import os
from flask import Flask, request, session, url_for, redirect, \
render_template, abort, g, flash, _app_ctx_stack
from flaskext.mysql import MySQL
from contextlib import closing
from hashlib import md5
from datetime import datetime
import time
import os
from werkzeug import check_password_hash, generate_password_hash
import config
app = Flask(__name__)
mysql = MySQL()
app.config['MYSQL_DATABASE_HOST'] = config.MYSQL_DATABASE_HOST
app.config['MYSQL_DATABASE_PORT'] = config.MYSQL_DATABASE_PORT
app.config['MYSQL_DATABASE_USER'] = config.MYSQL_DATABASE_USER
app.config['MYSQL_DATABASE_PASSWORD'] = config.MYSQL_DATABASE_PASSWORD
app.config['MYSQL_DATABASE_DB'] = config.MYSQL_DATABASE_DB
mysql.init_app(app)
if 'SECRET_KEY' in os.environ:
app.config['SECRET_KEY'] = os.environ['SECRET_KEY']
else:
app.config['SECRET_KEY'] = os.urandom(24)
###
# Routing for your application.
###
def init_db():
with closing(connect_db()) as db:
with app.open_resource('init.sql') as f:
db.cursor().execute(f.read())
db.commit()
def connect_db():
return mysql.connect()
if __name__ == '__main__':
init_db()
app.run(debug=True)
I get this result:
(venv)λ fh → λ git master* → python app.py
Exception _mysql_exceptions.ProgrammingError: (2014, "Commands out of sync; you can't ru
n this command now") in <bound method Cursor.__del__ of <MySQLdb.cursors.Cursor object a
t 0x10bc3ddd0>> ignored
Traceback (most recent call last):
File "app.py", line 124, in <module>
init_db()
File "app.py", line 38, in init_db
db.commit()
_mysql_exceptions.ProgrammingError: (2014, "Commands out of sync; you can't run this com
mand now")
Any ideas? I'm new to flask.
Seems you need to start the app before trying to do your DB stuff, as you are accessing the DB through Flask. I'm not experienced with Flask, so I'm not sure how you can access the DB after starting the server, but I can look if you don't know. Basically,
init_db()
app.run(debug=True)
needs to be reversed to
app.run(debug=True)
init_db()
In some way.
Related
I use the below code for connecting to MYSQL DATABASE using flask and pyodbc package. AS I try to run a flask project.
app.py
from dotenv import load_dotenv
from flask_migrate import Migrate
from flask_cors import CORS
from api import create_app, init_db
from api.common.models.models import db
import os
load_dotenv()
app_name = os.environ.get('FLASK_APP') or ''
app = create_app()
# security
cors_allowed_origins = os.environ.get('CORS_ALLOWED_ORIGINS', [])
CORS(app) # , origins=cors_allowed_origins
# sqlalchemy
app.config['SQLALCHEMY_DATABASE_URI'] = "mssql+pyodbc://USERNAME:PASSWORD#./DBNAME?driver=ODBC+Driver+17+for+SQL+Server"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = FALSE
db = init_db(app)
migrate = Migrate(app, db)
#app.route('/')
def home():
str = 'Hello World {0}'.format(app_name)
return str
if __name__=='__main__':
app.run()
I get the following error:
sqlalchemy.exc.OperationalError: (pyodbc.OperationalError) ('HYT00', '[HYT00] [Microsoft][ODBC Driver 17 for SQL Server]Login timeout expired (0) (SQLDriverConnect)')
Your issue is with the connection string, you are trying to connect to MySql but the connection string is to connect to MSSQL:
"mssql+pyodbc://USERNAME:PASSWORD#./DBNAME?driver=ODBC+Driver+17+for+SQL+Server"
But for MYSQL is one of the following:
# default
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://scott:tiger#localhost/foo'
# mysqlclient (a maintained fork of MySQL-Python)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+mysqldb://scott:tiger#localhost/foo'
# PyMySQL
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://scott:tiger#localhost/foo'
Check the official documentation:
Database Urls
# project\__init__.py
from flask import Flask
from flask_mysqldb import MySQL
from .config import app_config
db = MySQL()
def create_app(config_name):
app = Flask(__name__,
instance_path=os.path.join(os.path.dirname(__file__), 'instance'),
instance_relative_config=True)
app.config.from_object(app_config[config_name])
db.init_app(app)
print(db) # prints <flask_mysqldb.MySQL object at 0x000002A13710FC10>
# project/main.py
from . import db
#main.route('/foobar')
def foobar():
print(db) # prints <flask_mysqldb.MySQL object at 0x000002A13710FC10>
# project/database/seed_shipment.py
from project import create_app, db
def foo():
.
.
.
def goo()
.
.
.
if __name__ == '__main__':
config_name = os.getenv('FLASK_ENV')
app = create_app(config_name)
cursor = db.connection.cursor()
print(db) # prints <flask_mysqldb.MySQL object at 0x000002056B4EFD60>
print(db.connection) # returns None
for x in range(20):
# code which generates dummy data using foo() and goo()
cursor.execute("INSERT INTO shipment (column1, column2) VALUES (%s)", (var1, var2))
db.connection.commit()
My database connection works fine when I host the app and carry out CRUD operations using the interface in my browser. Such as login, sign up, create a shipment.
Note that I am not executing flask run from my terminal but instead python -m project.run, here is the code of this script:
# project/run.py
import os
from . import create_app
config_name = os.getenv('FLASK_ENV')
app = create_app(config_name)
if __name__ == '__main__':
app.run()
However, when I run python -m project.database.seed_shipment db seems to reference a different MySQL instance which has no connection. See the print results in the comments in my code.
My database connection works fine when I host the app and carry out CRUD operations using the interface in my browser. Such as login, sign up, create a shipment.
This indicates to me that you are correctly connecting to your db for each request.
However, when I run python -m project.database.seed_shipment db seems to reference a different MySQL instance which has no connection. See the print results in the comments in my code.
This, on the other hand, indicates to me that you are not connecting to your db when you directly execute seed_shipment - in fact, you seem to reference something different (as you write). In other words, db = MySQL() is not called.
I recommend that you try the following.
# project\__init__.py
from flask import Flask, g
from flask_mysqldb import MySQL
from .config import app_config
def create_app(config_name):
app = Flask(__name__,
instance_path=os.path.join(os.path.dirname(__file__), 'instance'),
instance_relative_config=True)
app.config.from_object(app_config[config_name])
# this here is just to register the teardown context and some variables ....
MySQL(app)
return app
def get_db():
if 'db' not in g:
g.db = MySQL().connection.cursor()
return g.db
That way, MySQL(app) is always executed when you call create_app. Now, you should be able to simply call get_db each time you want your db.
I have a Flask application that is using the factory function pattern (from the intro tutorial) and am attempting to offload a long running job to a background worker with a Redis queue. I am invoking the background work from a Blueprint, and am unable to pass the application context along with the invocation. The intention is to use the application context and the SQLite configuration to perform writes to it from the background thread. What am I missing here? I think this may be more of a "you just don't know enough about how Flask works" issue and if that is the case, please let me know what I'm doing wrong! Thanks.
ERROR
RuntimeError: Working outside of application context.
dy.py
import sqlite3
import click
from flask import current_app, g
from flask.cli import with_appcontext
def get_db():
if 'db' not in g:
g.db = sqlite3.connect(
current_app.config['DATABASE'],
detect_types=sqlite3.PARSE_DECLTYPES
)
g.db.row_factory = sqlite3.Row
return g.db
Blueprint module:
from flask import (
Blueprint, flash, g, redirect, render_template, request, url_for, Response, current_app
)
import sqlite3
from app.db import get_db
from rq import Queue
from redis import Redis
bp = Blueprint('perform_work', __name__)
q = Queue(connection=Redis())
def some_func():
db = get_db()
...
def generate_work():
result = q.enqueue(some_func)
...
#bp.route('/perform_work', methods=['POST'])
def perform_work():
...
generate_work()
worker.py
import os
import redis
from rq import Worker, Queue, Connection
listen = ['default']
redis_url = os.getenv('REDISTOGO_URL', 'redis://localhost:6379')
conn = redis.from_url(redis_url)
if __name__ == '__main__':
with Connection(conn):
worker = Worker(list(map(Queue, listen)))
worker.work()
alright well im glad i typed this out i guess. the context of the app was never registered with the worker, which should've occurred in worker.py, so yeah the worker had no idea about the application itself. here's the updated worker.py that registers the app's context:
import os
import redis
from rq import Worker, Queue, Connection
from app import create_app
listen = ['default']
redis_url = os.getenv('REDISTOGO_URL', 'redis://localhost:6379')
conn = redis.from_url(redis_url)
app = create_app()
app.app_context().push()
if __name__ == '__main__':
with Connection(conn):
worker = Worker(list(map(Queue, listen)))
worker.work()
I have an application with python, flask, and flask_mysqldb. When I execute the first query, everything works fine, but the second query always throws an error (2006, server has gone away). Everything I found on the web says this error is a timeout issue, which doesn't seem to be my case because:
1 - I run the second query just a few seconds after running the first
2 - My timeout configuration is set to 8 hours
I don't know what else this could be, here is the code that I am running:
import os
from flask import Flask
from flask import render_template
from flaskext.mysql import MySQL
import endpoints.usuario as usuario
app = Flask(__name__, static_folder='/root/sftp/atom-projects/flask-example/public/')
app.config['MYSQL_HOST'] = '123'
app.config['MYSQL_USER'] = '123'
app.config['MYSQL_PASSWORD'] = '123'
app.config['MYSQL_DB'] = '123'
app.add_url_rule('/usuarios', 'usuarios', usuario.list_all, methods=['GET'])
#app.errorhandler(404)
def not_found(e):
return app.send_static_file('index.html')
here is the code for the usuarios file:
from flask_mysqldb import MySQL
from flask import Flask, make_response
from flask import current_app
from flask import request
import bcrypt
def list_all():
mysql = MySQL(current_app)
cursor = mysql.connection.cursor()
cursor.execute("select * from usuario")
records = cursor.fetchall()
usuarios = []
for row in records:
usuarios.append({"id":row[0], "nome":row[1], "email":row[2], "senha":row[3], "tipo":row[4]})
for usuario in usuarios:
tipo = None
cursor.execute("select * from tipo_usuario where id = %s", [usuario['tipo']])
records = cursor.fetchall()
for row in records:
usuario['tipo'] = {"id":row[0], "permissao":row[1]}
return make_response({"msg":'', "error":False, "data":usuarios})
I have this running on nginx + gunicorn, here is the log :
gunicorn -w 1 --reload main:app
[2019-12-19 12:53:21 +0000] [5356] [INFO] Starting gunicorn 20.0.4
[2019-12-19 12:53:21 +0000] [5356] [INFO] Listening at: http://127.0.0.1:8000 (5356)
[2019-12-19 12:53:21 +0000] [5356] [INFO] Using worker: sync
[2019-12-19 12:53:21 +0000] [5359] [INFO] Booting worker with pid: 5359
[2019-12-19 12:53:28 +0000] [5359] [ERROR] Error handling request /usuarios
Traceback (most recent call last):
File "/usr/local/lib/python3.5/dist-packages/gunicorn/workers/sync.py", line 134, in handle
self.handle_request(listener, req, client, addr)
File "/usr/local/lib/python3.5/dist-packages/gunicorn/workers/sync.py", line 175, in handle_request
respiter = self.wsgi(environ, resp.start_response)
File "/usr/local/lib/python3.5/dist-packages/flask/app.py", line 2463, in __call__
return self.wsgi_app(environ, start_response)
File "/usr/local/lib/python3.5/dist-packages/flask/app.py", line 2457, in wsgi_app
ctx.auto_pop(error)
File "/usr/local/lib/python3.5/dist-packages/flask/ctx.py", line 452, in auto_pop
self.pop(exc)
File "/usr/local/lib/python3.5/dist-packages/flask/ctx.py", line 438, in pop
app_ctx.pop(exc)
File "/usr/local/lib/python3.5/dist-packages/flask/ctx.py", line 238, in pop
self.app.do_teardown_appcontext(exc)
File "/usr/local/lib/python3.5/dist-packages/flask/app.py", line 2320, in do_teardown_appcontext
func(exc)
File "/usr/local/lib/python3.5/dist-packages/flask_mysqldb/__init__.py", line 100, in teardown
ctx.mysql_db.close()
MySQLdb._exceptions.OperationalError: (2006, '')
If I run it with more workers, I can run a few more (depending on how many workers) queries, what could be causing this?
I had a similar error on my python flask application. And when I tried using from flask import current_app as app I still get an error. Eventually, I manged to remove the error by creating a separate file for flask app object app = Flask(__name__) and then importing it inside all the files that needed the object.
For Instance.
App object module: main.py
from flask import Flask, request
app = Flask(__name__)
Other files like usuarios.py or config.py
from main import app
from flask_mysqldb import MySQL
app.config['MYSQL_HOST'] = '123'
app.config['MYSQL_USER'] = '123'
app.config['MYSQL_PASSWORD'] = '123'
app.config['MYSQL_DB'] = '123'
mysql = MySQL(app)
Note: I used flask_mysqldb instead of flaskext.mysql but I don't think that makes any difference as long as your using the right parameters for either.
Finally found a solution.
Turns out Flask Mysql needs to be performed within the try...catch..finally block
And also make sure to close the cursor if you are using flask_mysqldb, which doesn't handle closing for you.
This is how my Query looks like now.
try:
cur.execute('SELECT * FROM users WHERE `email` = %s', (email))
results = cur.fetchall()
cur.close()
except Exception:
return 'Error: unable to fetch items'
cur.close()
Go to the below link and use mysqlpool instead of mysqldb or mysqlext.
https://pypi.org/project/flask-mysqlpool/
connection = mysql.connection.get_connection()
cur=connection.cursor()
query = "Enter your Query"
cur.execute(query)
connection.commit()
cur.close()
and one more thing that
app.config['MYSQL_POOL_SIZE'] = 30
this pool size must be less than or equal to 32
I cannot connect to my pythoneverywhere.com database from my local project.
The error is:
mysql.connector.errors.InterfaceError: 2013: Lost connection to MySQL server during query
Thank you in advance!
from flask import Flask, request, url_for, redirect
from flask_restful import Resource, Api
import pymysql as MySQLdb
from flaskext.mysql import MySQL
import mysql.connector
import sshtunnel
app = Flask(__name__)
api = Api(app)
sshtunnel.SSH_TIMEOUT = 5.0
sshtunnel.TUNNEL_TIMEOUT = 5.0
with sshtunnel.SSHTunnelForwarder(
('ssh.pythonanywhere.com'),
ssh_username='XXX', ssh_password='XXX',
remote_bind_address=('bianca.mysql.pythonanywhere-services.com', 3306)
) as tunnel:
connection = mysql.connector.connect(
user='XXX', password='XXX',
host='127.0.0.1', port=tunnel.local_bind_port,
database='bianca$moviesdb',
)
connection.close()
# print('after SSH connection')
conn = MySQLdb.connect("bianca.mysql.pythonanywhere-services.com", "XXX", "XXX", "bianca$moviesdb")
c = conn.cursor()
c.execute("SELECT * FROM reviews")
rows = c.fetchall()
for eachRow in rows:
print(eachRow)
if __name__ == '__main__':
app.run(port=5002)
Many things could be happening here: Timeout errors, packet sizes, etc. Also check your firewall settings.
https://dev.mysql.com/doc/refman/5.7/en/error-lost-connection.html