I am new to Flask and currently exploring the official tutorial available in https://flask.palletsprojects.com/en/2.0.x/tutorial/factory/.
The example creates a blog based on a SQLite database. The database is defined in the following statement:
app.config.from_mapping(
SECRET_KEY='dev',
DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),
)
Program Code
flaskr/__init__.py
import os
from flask import Flask
def create_app(test_config=None):
# create and configure the app
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
SECRET_KEY='dev',
DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),
)
if test_config is None:
# load the instance config, if it exists, when not testing
app.config.from_pyfile('config.py', silent=True)
else:
# load the test config if passed in
app.config.from_mapping(test_config)
# ensure the instance folder exists
try:
os.makedirs(app.instance_path)
except OSError:
pass
# a simple page that says hello
#app.route('/hello')
def hello():
return 'Hello, World!'
return app
However, instead of am SQLite database, I want to use a MySQL database for storing information. How can I define the MySQL configuration at this stage?
I have modified the following code in the db.py file of the tutorial:
https://flask.palletsprojects.com/en/2.0.x/tutorial/database/
import mysql.connector
import click
from flask import current_app, g
from flask.cli import with_appcontext
# Function to create a database connection.
def get_db():
if 'db' not in g:
g.db=mysql.connector.connect(host="localhost",user="dbuser",password="database123",database="testdb")
return g.db
# Function to close an existing database connection.
def close_db(e=None):
db=g.pop('db',None)
if db is not None:
db.close()
# Function to initialize the database from a script.
def init_db():
db = get_db()
with open('schema.sql', 'r') as f:
with db.cursor() as cursor:
cursor.execute(f.read(), multi=True)
db.commit()
#click.command('init-db')
#with_appcontext
def init_db_command():
# Delete existing data and re-create tables.
init_db()
click.echo('Initialized the database.')
# Register with the application.
def init_app(app):
app.teardown_appcontext(close_db)
app.cli.add_command(init_db_command)
Can someone please provide some guidance on how to setup a MySQL database connection?
I did some digging around and figured that it is not mandatory to define the MySQL database connection inside the factory function for the application to work. I removed the database parameter values from app.config.from_mapping and only kept the database connection string inside the actual db.py file. So far, the application has been working fine.
app=Flask(__name__, instance_relative_config=True)
app.config.from_mapping(SECRET_KEY='development',)
Here you can use pymysql to manage your connections. Below is an example showing that how you can manage the DB connection.
import pymysql
def db_connect():
conn = pymysql.connect(user='Your user',
password="Your password",
host="Your host",
database="Your database",
cursorclass=pymysql.cursors.DictCursor)
return conn
def db_close(conn):
if conn and conn.open:
conn.close()
class DatabaseHandler(object):
def __init__(self):
self.conn = None
def __enter__(self):
self.conn = db_connect()
return self.conn
def __exit__(self, exc_type, exc_val, exc_tb):
db_close(self.conn)
You can use it as,
with DatabaseHandler() as db_conn:
Any database operation with db_conn
Related
I have an issue with in my Flask app concerning SQLAlchemy and MySQL.
In one of my file: connection.py I have a function that creates a DB connection and set it as a global variable:
db = None
def db_connect(force=False):
global db
db = pymysql.connect(.....)
def makecursor():
cursor = db.cursor(pymysql.cursors.DictCursor)
return db, cursor
And then I have a User Model created with SQL ALchemy models.ppy
class User(Model):
id = column........
It inherits from Model which is a class that I create in another file orm.py
import connection
Engine = create_engine(url, creator=lambda x: connection.makecursor()[0], pool_pre_ping=True)
session_factory = sessionmaker(bind=Engine, autoflush=autoflush)
Session = scoped_session(session_factory)
class _Model:
query = Session.query_property()
Model = declarative_base(cls=_Model, constructor=model_constructor)
In my application I can have long script running so the DB timeout. So I have a function that "reconnect" my DB (it actually only create a new connexion and replace the global DB variable)
My goal is to be able to catch the close of my DB and reconnect it instantly. I tried with SQLAlchemy events but it never worked. (here)
Here is some line that reproduces the error:
res = User.query.filter_by(username="myuser#gmail.com").first()
connection.db.close()
# connection.reconnect() # --> SOLUTION
res = User.query.filter_by(username="myuser#gmail.com").first()
If you guys have any ideas of how to achieve that, let me know 🙏🏻
Oh and I forgot, this application is still running with python2.7.
I want to delete some entries in a MySQL database when I go to this URL: http://127.0.0.1:8080/api/td
I have a file named database.py and it has:
engine = create_engine(config.database_uri)
def delete():
with engine.connect() as con:
con.execute("delete from INS where a = 2;")
I have a file named init.py and it has:
#app.route('/api/td', methods=["DELETE"])
def update():
database.delete()
return 'succefully'
when I go to http://127.0.0.1:8080/api/td, I get this error:
There was an error connecting to http://127.0.0.1:8080/api/td.
The method above worked perfectly for multiple get requests. But it's not working for my delete request. both files have other codes and imports.
Cause:
When a route is visited via browser, it performs a GET request.
So, visiting /api/td that is declared with only DELETE method will result in Method not allowed error.
Solution:
To overcome this, we need to declare the route with GET method instead of DELETE:
#app.route("/api/td", methods=['GET'])
I have created a dummy application to delete a row from MySQL database table.
app.py:
from flask import Flask
from database import Database
app = Flask(__name__)
database = Database()
#app.route("/api/td", methods=['GET'])
def delete_row():
return database.delete()
app.run(debug=True, port=8080)
database.py:
from sqlalchemy import create_engine
class Database(object):
def __init__(self):
# dialect+driver://username:password#host:port/database
self.engine = create_engine('mysql://root:123#localhost/practice_db')
def delete(self):
try:
with self.engine.connect() as con:
con.execute('DELETE FROM `user_table` WHERE `id`=2')
return 'Deleted successfully'
except Exception as e:
return "Exception occurs: {}".format(str(e))
requirements.txt:
Click==7.0
Flask==1.0.2
itsdangerous==1.1.0
Jinja2==2.10
MarkupSafe==1.1.0
mysqlclient==1.3.13
SQLAlchemy==1.2.14
Werkzeug==0.14.1
Screenshot:
I am using Flask-MySQL to connect to my database in a view. The view works the first time I go to it, but when I go to it the second time it always crashes with the error:
ProgrammingError: closing a closed connection
Why am I getting this error? How do I connect successfully the second time?
from flask import Flask, render_template, request
from flaskext.mysql import MySQL
app = Flask(__name__)
#app.route('/hello/', methods=['POST'])
def hello():
app.config['MYSQL_DATABASE_USER'] = 'root'
app.config['MYSQL_DATABASE_PASSWORD'] = 'xxx'
app.config['MYSQL_DATABASE_DB'] = 'pies'
app.config['MYSQL_DATABASE_HOST'] = 'localhost'
query = request.form['yourname']
mysql = MySQL(app)
conn = mysql.connect()
with conn as cursor:
try:
cursor.execute(query)
name = str(cursor.fetchone())
except:
name = "SQL is wrong"
conn.close()
return render_template('form_action.html', name=name)
if __name__ == '__main__':
app.run(debug=True)
You should not be initializing the extension during every request. Create it during app setup, then use it during the requests. Setting configuration should also be done during app setup.
The extension adds a teardown function that executes after every request and closes the connection, which is stored as a threadlocal. Since on the second request you've registered the extension multiple times, it is trying to close the connection multiple times.
There's no need to call connect, the extension adds a before request function that does that. Use get_db to get the connection for the request. Since the extension closes this connection for you, don't call close either.
from flask import Flask
from flaskext.mysql import MySQL
MYSQL_DATABASE_USER = 'root'
MYSQL_DATABASE_PASSWORD = 'xxx'
MYSQL_DATABASE_DB = 'pies'
MYSQL_DATABASE_HOST = 'localhost'
app = Flask(__name__)
app.config.from_object(__name__)
mysql = MySQL(app)
#app.route('/hello/')
def hello():
conn = mysql.get_db()
# ...
Note that Flask-MySQL is using a very old extension pattern that is no longer supported by Flask. It also depends on an unsupported mysql package that does not support Python 3. Consider using Flask-MySQLdb instead.
I've the code like this below. Is it necessary to close mysql connection because whenever my home page is requested, a new sql connection will be created?
I randomly get Connection Limit error. But I'm not sure if the DB connection is the problem.
#app.route("Home", methods=["GET"])
def get_home_page():
db = mysql.connect(host, user, password, db_name, charset='utf8', use_unicode=True)
...
It is good practice to close the connection. You can put your codes inside a try..finally block.
#app.route("Home", methods=["GET"])
def get_home_page():
db = mysql.connect(host, user, password, db_name, charset='utf8', use_unicode=True)
try:
... do something ...
finally:
db.close()
from my experience, close session after use it take significant difference amount of time to response in api whom i've experienced in flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
try:
db.session.query( Any Model ...
except:
finally:
db.close_all_sessions
I have a CherryPy "site" set up under Apache with modwsgi. It works fine and I can return hello world messages no problem. The problem is when I try to connect to my MySQL database. Here is the code I'm using.
import sys
sys.stdout = sys.stderr
import atexit
import threading
import cherrypy
import MySQLdb
cherrypy.config.update({'environment': 'embedded'})
if cherrypy.__version__.startswith('3.0') and cherrypy.engine.state == 0:
cherrypy.engine.start(blocking=False)
atexit.register(cherrypy.engine.stop)
def initServer():
global db
db=MySQLdb.connect(host="localhost", user="root",passwd="pass",db="Penguin")
class Login(object):
def index(self):
return 'Login Page'
index.exposed = True
class Root(object):
login = Login();
def index(self):
# Sample page that displays the number of records in "table"
# Open a cursor, using the DB connection for the current thread
c=db.cursor()
c.execute('SELECT count(*) FROM Users')
result=cursor.fetchall()
cursor.close()
return 'Help' + result
index.exposed = True
application = cherrypy.Application(Root(), script_name=None, config=None)
Most of this was copied from the CherryPy site on setting up modwsgi, I just added the database stuff which I pieced together from various internet sources.
When I try to view the root page I get a 500 Internal Server Error. I can still get to the login page fine but so I'm pretty sure I'm messing up the database connection somehow.
You have a bunch of errors, not related to CherryPy really.
def initServer():
global db
db is not defined in the global scope. Try:
db = None
def initServer():
global db
In addition, initServer() is never called to create the DB connection.
Another:
c = db.cursor()
c.execute('SELECT count(*) FROM Users')
result = cursor.fetchall()
cursor.close()
cursor is not defined. I think you mean c:
c = db.cursor()
c.execute('SELECT count(*) FROM Users')
result = c.fetchall()
c.close()