Issues with DB connections in Flask Framework - python

I am new to flask framework and I have just created app in it but now i am struggling with DB connections in flask. I want to connect my app with MySQL. For that I have follow this link http://flask.pocoo.org/snippets/11/ , but I am not able to connect with DB.
My code is as follows :
from flask import Flask , render_template,g
from torndb import Connection
app=Flask(__name__)
#app.before_request
def connect_db():
g.db = Connection(DB_HOST="localhost",
DB_NAME="flask",
DB_USER="root",
DB_PASSWD="ghrix321")
#app.route('/')
def home():
rows = g.db.iter("select * from user")
return render_template('home.html',rows=rows)
TypeError: init() got an unexpected keyword argument 'DB_NAME'.
So please suggest me some way so that I can connect with DB and fetch data from there.
Thanks

The snippet you refer to does not use keyword parameters.
The documentation of torndb is at http://torndb.readthedocs.org/en/latest/. If you use keyword parameters, you have to name them like they are in the function definition.
This is the correct call:
g.db = Connection('localhost','flask', user='root', password='ghrix321')
As an aside, use dedicated users in your database, and don't hardcode your password into the app, use a configuration file for that.

Related

Python Flask SQLAlchemy check if database is available

before rendering the template I want to check if the database that I am using is available. The database is only available with specific IP, therefore, if someone tries to access the page, I don't want to error everything out, but redirect to a different template without the need for a database.
The error message:
(2003, "Can't connect to MySQL server on 'db-test' (110)")
(Background on this error at: https://sqlalche.me/e/14/e3q8)
There is no issue with the error itself, I just want to be able to check if the database is accessible without waiting until the error occurs while loading the page.
storage.py:
from flask_sqlalchemy import SQLAlchemy
db_req = SQLAlchemy()
class Requests(db_req.Model):
__tablename__ = 'requests'
id = db_req.Column(db_req.Integer, primary_key=True, nullable=False)
created = db_req.Column(db_req.DateTime, nullable=False)
name = db_req.Column(db_req.String, nullable=False)
app.py:
from flask import Flask
from models import db_req
from views.requests import requests
app = Flask(__name__)
app.register_blueprint(requests)
app.config.from_object("config.Config")
db_req.init_app(app)
if __name__ == '__main__':
app.run(debug=True)
requests.py:
from flask import Blueprint, render_template, request
from query_request_db import get_fields
requests = Blueprint("requests", __name__)
#requests.route("/", methods=["GET", "POST"])
def requests_page():
# need to check before everything if I can access database not to error out
return render_template("requests_page.html", names=get_fields.get_field_data("name"))
I am trying to find a way to check if the database is available without erroring out. Any help is welcome!
Hope I understand you right? that u want to check ip Addresse of the viewer of your Page.
Then u can use
request.remote_addr
to validate the IP Adress that has access to database ohterwise just do a redirect.

Python Flask framework. AssertionError: A setup function was called after the first request was handled

I've been following the flask tutorial to add a database, in their example they're using mysqlite while I'm using MySQL but I figured that shouldn't make a huge difference here. https://flask.palletsprojects.com/en/1.1.x/tutorial/database/
Here's the mysql library I'm trying to use https://flask-mysql.readthedocs.io/en/stable/
However whatever I do I can't seem to get away from this assertion error:
AssertionError: A setup function was called after the first request was handled. This usually indicates a bug in the application where a module was not imported and decorators or other functionality was called too late.
To fix this make sure to import all your view modules, database models and everything related at a central place before the application starts serving requests.
The error only happens when trying to use the /dbtest path.
Here's my minimal __init__.py
import os
from flask import Flask, render_template
from . import db
def create_app(test_config=None):
# create and configure the app
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
MYSQL_DATABASE_HOST='mysql-svc',
MYSQL_DATABASE_USER='root',
MYSQL_DATABASE_PASSWORD='root',
DEBUG=True,
TESTING=True
)
db.init_app(app)
# a simple page that says hello
#app.route('/hello')
def hello():
return 'Hello, World!'
#app.route('/dbtest')
def db_test():
with app.app_context():
cursor = db.get_cursor()
cursor.execute('SHOW DATABASES')
return cursor.fetchall()
return app
And here is db.py which is in the same directory
from flaskext.mysql import MySQL
from flask import current_app, g
def get_cursor():
if 'db_cursor' not in g:
mysql = MySQL()
mysql.init_app(current_app)
g.db_cursor = mysql.get_db().cursor()
return g.db_cursor
def close_db(e=None):
db = g.pop('db_cursor', None)
if db is not None:
db.close()
def init_app(app):
app.teardown_appcontext(close_db)
Everything I've read about this error seems to indicate that I'm somehow messing around with routing after I've tried to access the database or something? But I'm just following the tutorial for how the routing is set up. I'm probably missing something obvious here, I believe it's an issue with mysql.init_app now but I still can't figure out how to do this.
The issue may be related if DEBUG = True, just ran into this myself came here looking for a solution. The closed github ticket below has a comment indicating that it was an issue at some point. As of today it still appears to be an issue.
https://github.com/ga4gh/ga4gh-server/issues/791
In the end I had to say screw it to the whole g thing with getting the cursor, same goes for closing the db with a teardown. In the end it works with just this in my db.py:
from flaskext.mysql import MySQL
def init_db_connection(app):
mysql = MySQL()
mysql.init_app(app)
return mysql.get_db().cursor()
Which I call once from my __init__.py before I do any routing, this gets me the db cursor. Then I just freely use that variable within the routing.
I'm not sure how well this will scale up, and frankly I think the flask tutorials are rather poor as the mechanics behind g, app initialisation, routing, current_app and the rest are poorly explained. But what I've got works for now at least. I hope someone else can provide a better answer to this question.
Just encountered the same issue and found this interesting article here.
It's about to use plain SQLAlchemy and to avoid Flask-SQLAlchemy.
Instead of initializing the connection with
db=SQLAlchemy(app)
(which causes the issue in question) I followed the article and did it like this:
class Query:
def __init__(self):
SQLALCHEMY_DATABASE_URI = 'sqlite:///db/mydb.db'
engine = create_engine(SQLALCHEMY_DATABASE_URI, connect_args={'check_same_thread': False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
self.session = SessionLocal()
Base = automap_base()
Base.prepare(engine, reflect=True)
self.Node = Base.classes.mytable
def getTop20(self):
nodes = self.session.query(self.Node).order_by(desc(self.Node.date_modified)).limit(20)
return nodes

How to close db with flask_mongoengine?

I am learning to use flask and flask_mongoengine to create a website. Follow the flask tutorial 1.0.2 version. But I ran into a problem, how to implement the get_db() and close_db() function?
Currently, what I am doing is :
myapp.py
....
def create_app():
app = Flask(__name__)
from db import db
db.init_app(app)
#app.route('/')
def home():
...
return app
db.py
from flask import g
from flask_mongoengine import MongoEngine
db = MongoEngine()
def get_db():
g.db = ???
return g.db
def close_db():
db = g.pop('db', None)
if db is not None:
??? # db.close() doesn't exist!!!
I am very confused about how to do this part. Can someone give any suggestions? In flask_mongoengine tutorial page, they don't implement the get_db() and close_db() ...
Confusion happens because in those tutorials there are too many programming patterns. In flask-1.0.2 tutorial they use getter method pattern and but flask-mongoengine relies on bootstraping a db to flask-app-instance, which relies on a builder pattern — Flask Application Factories. It may still be confusing but I'll show you how it's meant to be done.
Bootstrap a flask-mongoengine in create_app:
def create_app(test_config=None):
app = Flask(__name__)
# configure mongo settings here like in flask-mongoengine docs
g.db = db = MongoEngine()
db.init_app(app)
def get_db():
return g.db
def close_db():
pass
What's about close_db()? Well, that function exists in case db you've chosen needs some cleanup actions to be closed. But I haven't found in mongoengine docs any explicit mention that mongoengine db connection need a cleanup actions from you to be closed, so you can just pass it.

Flask-SQLAlchemy: Can't reconnect until invalid transaction is rolled back

So I am using Amazon Web Services RDS to run a MySQL server and using Python's Flask framework to run the application server and Flask-SQLAlchemy to interface with the RDS.
My app config.py
SQLALCHEMY_DATABASE_URI = '<RDS Host>'
SQLALCHEMY_POOL_RECYCLE = 60
My __ init __.py
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
application = Flask(__name__)
application.config.from_object('config')
db = SQLAlchemy(application)
I have my main application.py
from flask import Flask
from application import db
import flask.ext.restless
from application.models import Person
application = Flask(__name__)
application.debug=True
db.init_app(application)
#application.route('/')
def index():
return "Hello, World!"
manager = flask.ext.restless.APIManager(application, flask_sqlalchemy_db=db)
manager.create_api(Person, methods=['GET','POST', 'DELETE'])
if __name__ == '__main__':
application.run(host='0.0.0.0')
The models.py
class Person(db.Model):
__bind_key__= 'people'
id = db.Column(db.Integer, primary_key=True)
firstName = db.Column(db.String(80))
lastName = db.Column(db.String(80))
email = db.Column(db.String(80))
def __init__(self, firstName=None, lastName=None, email=None):
self.firstName = firstName
self.lastName = lastName
self.email = email
I then have a script to populate the database for testing purposes after db creation and app start:
from application import db
from application.models import Person
person = Person('Bob', 'Jones', 'bob#website.net')
db.session.add(person)
db.session.commit()
Once I've reset the database with db.drop_all() and db.create_all() I start the application.py and then the script to populate the database.
The server will respond with correct JSON but if I come back and check it hours later, I get the error that I need to rollback or sometimes the 2006 error that the MySQL server has gone away.
People suggested that I change timeout settings on the MySQL server but that hasn't fixed anything. Here are my settings:
innodb_lock_wait_timeout = 3000
max_allowed_packet = 65536
net_write_timeout = 300
wait_timeout = 300
Then when I look at the RDS monitor, it shows the MySQL server kept the connection open for quite a while until the timeout. Now correct me if I'm wrong but isn't the connection supposed to be closed after it's finished? It seems that the application server keeps making sure that the database connection exists and then when the MySQL server times out, Flask/Flask-SQLAlchemy throws an error and brings down the app server with it.
Any suggestions are appreciated, thanks!
I think what did it was adding
db.init_app(application)
in application.py, haven't had the error since.
Everytime checking rollback or not is troublesome..
I made insert, update functions which need commit.
#app.teardown_request
def session_clear(exception=None):
Session.remove()
if exception and Session.is_active:
Session.rollback()
It seems not to be a problem with the transactions at the first place, but this is probably caused by an MySQL Error like Connection reset by peer beforehand. That means your connection is lost, probably because your application context was not setup correctly.
In general it is preferrable to use the factory pattern to create your app. This has a lot of advantages, your code is
easier to read and setup
easier to test
avoid circular imports
To prevent the invalid transaction error (that is probably caused by an OperationalError: Connection reset by peer) you should ensure that you are handling the database connection right.
The following example is based on this article which gives a nice explanation of the flask application context and how to use it with database connections or any other extensions.
application.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
def create_app():
"""Construct the core application."""
application = Flask(__name__)
application.config.from_object('config') # Set globals
db = SQLAlchemy()
with application.app_context():
# Initialize globals/extensions in app context
db.init_app(app)
# import routes here
from . import routes
return application
if __name__ == "__main__":
app = create_app()
app.run(host="0.0.0.0")
routes.py
from flask import current_app as application
#application.route('/', methods=['GET'])
def index():
return "Hello, World!"
If you still run into disconnect-problems you should also check the SQLAlchemy documentation on dealing with disconnects and have a look at this question.
Here you missing pool recycle as MySql closes session after some time so you need to add pool recycle so that connections in pool get reconnect after pool recycle time.
app.config['SQLALCHEMY_POOL_RECYCLE'] = 3600
This error usually appears when you create sqlalchemy the engine as a singleton. In that case after the connection is invalidated (in my case it was 3600sec) you get the InvalidTransaction error.
Best advice would be to initialise the db session at the time of application initialisation
db.init_app(app)
and import this db session when ever you have to do some CRUD operation.
Never faced this issue post this change on my application.
Alternatively, use this at the end of the script that populates your database:
db.session.close()
That should prevent those annoying "MySQL server has gone away" errors.

Flask + MySQL strange behaviour

I am building a simple web-app which uses existing MySQL DB. It is my first time using Flask and I have been struggling to understand what I am doing wrong for the past couple of hours.
My simple project structure:
/root
/app
__init__.py
db.py
forms.py
views.py
/templates
base.html
index.html
login.html
config.py
run.py
I am trying to query my MySQL DB and fill the template with the result from the query.
My db.py:
from app import app
from flaskext.mysql import MySQL
class DB(object):
mysql = MySQL()
def __init__(self):
app.config['MYSQL_DATABASE_USER'] = 'loguser'
app.config['MYSQL_DATABASE_PASSWORD'] = 'asdzxc'
app.config['MYSQL_DATABASE_DB'] = 'log'
app.config['MYSQL_DATABASE_HOST'] = '127.0.0.1'
app.config['MYSQL_DATABASE_PORT'] = 33006
self.mysql.init_app(app)
def query_db(self):
cursor = self.mysql.connect().cursor()
cursor.execute("SELECT name from users limit 1")
data = cursor.fetchone()
if data is None:
return "No results from query"
else:
return data
And in my views.py I have the following:
from flask import render_template, flash, redirect
from app import app
from .forms import LoginForm
from .db import DB
#app.route('/')
#app.route('/index')
def index():
db = DB()
user = db.query_db()
print(user) (it prints it here so the db connection works)
posts = [ # fake array of posts
{
'author': {'nickname': 'John'},
'body': 'Beautiful day in Portland!'
},
{
'author': {'nickname': 'Susan'},
'body': 'The Avengers movie was so cool!'
}
]
return render_template("index.html",
title='Home',
user=user,
posts=posts)
I get "AssertionError" when I try to assign "user" to the user from the template:
AssertionError: A setup function was called after the first request was handled. This usually indicates a bug in the application where a module was not imported and decorators or other functionality was called too late.To fix this make sure to import all your view modules, database models and everything related at a central place before the application starts serving requests.
I believe I am violating a major principle of the framework. What is the correct way to pass the data to the template?
It is better to use Flask-SQLAlchemy and MySQL-python 1.2 , Successful code and documentation is available on the link below.
http://techarena51.com/index.php/flask-sqlalchemy-tutorial/
From my experience I found that MySQl support is not that good for python 3 atleast, it is better to use PostgreSQL, but that's just my personal opinion.
It's very late to give answer, but it may help someone.
You've to connect to MySQL before adding any route source to an API.
It should be in the order of
# 1. MySQL setup should be done at first
app = Flask(__name__)
api = Api(app)
mysql = MySQL()
app.config['MYSQL_DATABASE_USER'] = 'root'
app.config['MYSQL_DATABASE_PASSWORD'] = 'root'
app.config['MYSQL_DATABASE_DB'] = 'DataBase'
app.config['MYSQL_DATABASE_HOST'] = 'localhost'
mysql.init_app(app)
conn = mysql.connect()
cursor = conn.cursor()
# 2. Create API resource after that
api.add_resource(CreateUser, '/CreateUser')

Categories

Resources