How to configure DB in a Flask app dynamicly? - python

I'm working on app, where user have to enter database connection parametrs by hands
So I've made an api here it is:
from flask_mysqldb import MySQL
from flask import Flask, request
import MySQLdb.cursors
app = Flask(__name__)
# /hello
#app.route("/hello", methods=['GET'])
def hello():
return "Hello word"
# /get_tables
#app.route(f"/get_tables", methods=['GET'])
def get_tables():
host = request.args.get('host', type=str)
user = request.args.get('user', type=str)
password = request.args.get('password', type=str)
database = request.args.get('database', type=str)
app.config['MYSQL_HOST'] = "localhost"
app.config['MYSQL_USER'] = "root"
app.config['MYSQL_PASSWORD'] = "password"
app.config['MYSQL_DB'] = "restaurant"
mysql = MySQL(app)
cursor = mysql.connection.cursor(MySQLdb.cursors.DictCursor)
query = "SHOW TABLES"
cursor.execute(query)
records = cursor.fetchone()
print(records)
return records
"hello" endpoint is working fine, but when run "get_tables" I recieve an error:
AssertionError: The setup method 'teardown_appcontext' can no longer be called on the application. It has already handled its first request, any changes will not be applied consistently. Make sure all imports, decorators, functions, etc. needed to set up the application are done before running it.
I also was trying to debug my api and found out that errorr ocures on a mysql = MySQL(app) line
What can I do to solve this problem? or maybe it's better not to use api at all and just connect to DB from ui?

Related

Flask: db is not being referenced properly when importing into my database seeder script

# 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.

error: 'MySQL' object has no attribute 'connection'/ 'MySQL' object has no attribute 'get_db'

I am new to flask and i am writing a basic program for login. Everytime I ammend i end with error mentioned above. below is my code for reference. Can someone please correct me.
#app.route('/')
def index():
return render_template('form_ex.html')
#app.route('/',methods = ['POST'])
def Authenticate():
login = request.form['u']
password = request.form['p']
cursor = mysql.get_db().cursor()
cursor.execute("SELECT * FROM UserLogin WHERE login=%s and password=%s")
data= cursor.fetchone()
if data is None:
return("Username or password incorrect")
else:
return("You are logged in")
By the looks of the code you didn't initialise the MySQL DB, taken from this link the answer is below: Using MySQL in Flask
Firstly you need to install Flask-MySQL package. Using pip for example:
pip install flask-mysql
Next you need to add some configuration and initialize MySQL:
from flask import Flask
from flaskext.mysql import MySQL
app = Flask(__name__)
mysql = MySQL()
app.config['MYSQL_DATABASE_USER'] = 'root'
app.config['MYSQL_DATABASE_PASSWORD'] = 'root'
app.config['MYSQL_DATABASE_DB'] = 'EmpData'
app.config['MYSQL_DATABASE_HOST'] = 'localhost'
mysql.init_app(app)
Now you can get connection and cursor objects and execute raw queries:
conn = mysql.connect()
cursor =conn.cursor()
cursor.execute("SELECT * from User")
data = cursor.fetchone()

Problems using sqlAlchemy to execute SQL queries on my database

I am working on a project to work on a website that connects to a mysql server using flask and sqlAlchemy (Hosted on AWS RDS) and I am following this tutorial but when I try to do (/api/bar) I get this error. When I just do my localhost:8080 it shows "Hello World" perfectly fine.
sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (2003, "Can't connect to MySQL server on 'localhost' ([WinError 10061] No connection could be made because the target machine actively refused it)") (Background on this error at: http://sqlalche.me/e/e3q8)
config.py
database_url = "mysql+pymysql://username:password#localhost:3306/barbeerdrinker"
Here is my __init__.py
from flask import Flask
from flask import jsonify
from flask import make_response
from flask import request
import json
from barbeerdrinker import database
#Flask application
app = Flask(__name__)
#app.route("/")
def hello_world():
return "Hello World"
#app.route("/api/bar", methods=["GET"])
def get_bars():
return jsonify(database.get_bars())
#app.route("/api/bar/<name>", methods=["GETS"])
def find_bar(name):
try:
if name is None:
raise ValueError("Bar is not specified")
bar = database.find_bar(name)
if bar is None:
return make_response("No bar found within given name", 404)
return jsonify(bar)
except ValueError as e:
return make_response(str(e), 400)
except Exception as e:
return make_response(str(e), 500)
#app.route("/api/beers_cheaper_than", methods=["POST"])
def find_beers_cheaper_than():
body = json.loads(request.data)
max_price = body['maxPrice']
return jsonify(database.filter_beers(max_price))
database.py
from sqlalchemy import create_engine
from sqlalchemy import sql
from barbeerdrinker import config
engine = create_engine(config.database_url)
def get_bars():
with engine.connect() as con:
rs = con.execute("SELECT name, address, city, opening, closing, phoneNum FROM bars")
return [dict(row) for row in rs]
def find_bar(name):
with engine.connect() as con:
query = sql.text("SELECT * FROM bars WHERE name = :name;")
rs = con.execute(query, name=name)
result = rs.first()
if result is None:
return None
return dict(result)
def filter_beers(max_price):
with engine.connect() as con:
query = sql.text("SELECT * FROM sells WHERE price < : max_price;")
rs = con.execute(query, max_price=max_price)
results = [dict(row) for row in rs]
for r in results:
r['price'] = float(r['price'])
return results
**Edit: So it seems like the problem is not an issue with my code but a Windows error. One solution I tried to do was to open up the required ports through my firewall to no avail.
I just figured it out, turns out the issue is not a windows issue. The problem is within my config.py:
Instead of:
database_url = "mysql+pymysql://username:password#localhost:3306/barbeerdrinker"
It should be:
database_url = "mysql+pymysql://username:password#**AWSENDPOINT/HOSTNAME**:3306/barbeerdrinker"

python connection to DB throwing error

I am new to using python to connect to a mysql DB and I am getting the following error:
OperationalError: (pymysql.err.OperationalError) (1045, u"Access denied for user 'xxxxxxadmin'#'xx.xx.xx.xx' (using password: YES)") (Background on this error at: http://sqlalche.me/e/e3q8)
xx.xxx.216.44 - - [02/Apr/2018 17:27:49] "GET /testconnect HTTP/1.1" 500 -
This is most of the connect script in my python file:
#!/usr/bin/python3
from flask import Flask, request
from flask_restful import Resource, Api
from sqlalchemy import create_engine
from json import dumps
from flask.ext.jsonpify import jsonify
db_connect = create_engine("mysql+pymysql://xxxxxxxadmin:password#,mymaindb.xxxxxxxx.us-east-2.rds.amazonaws.com:3306/myDBname")
app = Flask(__name__)
api = Api(app)
class TestConnect(Resource):
def get(self):
conn = db_connect.connect() # connect to database
query = conn.execute("select * from Players") # This line performs query and returns json result
return {'employees': [i[0] for i in query.cursor.fetchall()]} # Fetches first column that is Employee ID
api.add_resource(TestConnect, '/testconnect') # Route_1
if __name__ == '__main__':
app.run(host='0.0.0.0', debug = False)
Other background:
But when I try to connect to the same mysql database using the exact same credentials via the command line on the server running the python script I am able to get in.
Not sure how to test more to get a better error result that will help me figure this issue out.
UPDATE
So I was able to connect to my DB via mysql workbench with the connection strings and information I have in the python script. Does this mean my python script is doing something wrong?
Why not use:
mysql+pymysql://xxxxxxxadmin:password#mymaindb.xxxxxxxx.us-east-2.rds.amazonaws.com:3306/myDBname
instead of
mysql+pymysql://xxxxxxxadmin:password#**,**mymaindb.xxxxxxxx.us-east-2.rds.amazonaws.com:3306/myDBname
Not sure why you're connection string has a comma. Might just be a typo?
On that note, I usually build the connection URL before passing it to create_engine just to make it easier to manage in the future incase I have to pull the actual values from the environmental variables:
HOST = "mymaindb.xxxxxxxx.us-east-2.rds.amazonaws.com"
PORT = 3306
USERNAME = "xxxxxxxadmin"
PASSWORD = "password"
DBNAME = "myDBname"
CONNECTION_URL = 'mysql+pymysql://%s:%s#%s:%s/%s' % (
USERNAME,
PASSWORD,
HOST,
PORT,
DBNAME
)

MySQL connection times out after a while (Python, MySQL, FLASK)

I'm currently running an flask python application running on an NGINX server with the help of uWGI. The static pages are always reachable but the pages that use a connection (MySQL) time out after 2 minutes. What's going on? They become simply become unavailable.
Things I have tried:
Not using a global
working with pools
turning off firewall
.
# using python version 2.7.10
from flask import Flask, jsonify, request, session
import mysql.connector.pooling
#Make a connection with the DB
dbconfig = {
"host" : "12.34.5.78",
"database": "db",
"user": "user",
"password": "pass"
}
conn = mysql.connector.connect(pool_name = "mypool",
pool_size = 6,
**dbconfig)
#Define the root
app = Flask(__name__)
#Landings page
#app.route('/')
def index():
return "Hello World."
# return all resources by name
#app.route('/resources', methods=['GET'])
def allResourceNames():
conn1 = mysql.connector.connect(pool_name="mypool")
reader = conn1.cursor()
query = ("SELECT name FROM resources")
reader.execute(query)
resources = []
for name in reader:
resources.append({'name' : name[0]})
reader.close()
conn1.close()
return jsonify({"resources" : resources})
if __name__ == "__main__":
app.run(debug=True)
According to MySQL Python Connector Doc
you may want to set connection_timeout as connect option. E.g.,
conn = mysql.connector.connect(pool_name = "mypool",
pool_size = 6, connection_timeout=3600,
**dbconfig)

Categories

Resources