Connect to MSSQL Database using Flask-SQLAlchemy
Question:
I’m trying to connect to a local MSSQL DB through Flask-SQLAlchemy.
Here’s a code excerpt from my __init__.py
file:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mssql+pyodbc://HARRISONS-THINK/LendApp'
db = SQLAlchemy(app)
SQLALCHEMY_TRACK_MODIFICATIONS = False
As you can see in SQL Server Management Studio, this information seems to match:
Here is the creation of a simple table in my models.py
file:
from LendApp import db
class Transaction(db.model):
transactionID = db.Column(db.Integer, primary_key=True)
amount = db.Column(db.Integer)
sender = db.Column(db.String(80))
receiver = db.Column(db.String(80))
def __repr__(self):
return 'Transaction ID: {}'.format(self.transactionID)
I am then connecting to the database using a Python Console within Pycharm via the execution of these two lines:
>>> from LendApp import db
>>> db.create_all()
This is resulting in the following error:
DBAPIError: (pyodbc.Error) ('IM002', '[IM002] [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified (0) (SQLDriverConnect)')
The only thing that I can think of is that my database connection string is incorrect. I have tried altering it to more of a standard Pyodbc connection string and including driver={SQL SERVER}
but to no prevail.
If anyone could help me out with this it would be highly appreciated.
Thanks
Answers:
I believe your connection string is missing the authentication details. From Flask-SQLAlchemy documentation, the connection string should have the following format
dialect+driver://username:password@host:port/database
From your example, I believe it will look something like this
app.config['SQLALCHEMY_DATABASE_URI'] = 'mssql+pyodbc://<username>:<password>@<Host>:<Port>/LendApp'
So I just had a very similar problem and was able to solve by doing the following.
Following the SQL Alchemy documentation I found I could use the my pyodbc connection string like this:
# Python 2.x
import urllib
params = urllib.quote_plus("DRIVER={SQL Server Native Client 10.0};SERVER=dagger;DATABASE=test;UID=user;PWD=password")
engine = create_engine("mssql+pyodbc:///?odbc_connect=%s" % params)
# Python 3.x
import urllib
params = urllib.parse.quote_plus("DRIVER={SQL Server Native Client 10.0};SERVER=dagger;DATABASE=test;UID=user;PWD=password")
engine = create_engine("mssql+pyodbc:///?odbc_connect=%s" % params)
# using the above logic I just did the following
params = urllib.parse.quote_plus('DRIVER={SQL Server};SERVER=HARRISONS-THINK;DATABASE=LendApp;Trusted_Connection=yes;')
app.config['SQLALCHEMY_DATABASE_URI'] = "mssql+pyodbc:///?odbc_connect=%s" % params
This then caused an additional error because I was also using Flask-Migrate and apparently it doesn’t like % in the connection URI. So I did some more digging and found this post. I then changed the following line in my ./migrations/env.py
file
From:
from flask import current_app
config.set_main_option('sqlalchemy.url',
current_app.config.get('SQLALCHEMY_DATABASE_URI'))
To:
from flask import current_app
db_url_escaped = current_app.config.get('SQLALCHEMY_DATABASE_URI').replace('%', '%%')
config.set_main_option('sqlalchemy.url', db_url_escaped)
After doing all this I was able to do my migrations and everything seems as if it is working correctly now.
If someone still stumbled upon this issue and trying to figure out another solution then try with pymssql
instead of pyodbc
;
pip install pymssql
Connection URI would be:
conn_uri = "mssql+pymssql://<username>:<password>@<servername>/<dbname>"
I just changed my connection string something like this and its worked perfectly
NOTE: you need to install pyodbc to work….
app.config["SQLALCHEMY_DATABASE_URI"] = "mssql+pyodbc://user:pwd@server/database?driver=SQL+Server"
Note:
Try to avoid ‘@’ character in password. you will get error because connection string also has ‘@’ character after password. This also can cause the connection error
I had the same problem, it was resolved by specifying:
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "mssql+pyodbc://MySQLServerName/MyTestDb?driver=SQL+Server?trusted_connection=yes"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db.init_app(app)
using below solution i get resolve my connection issue with MSSQL server
params = urllib.parse.quote_plus('DRIVER={SQL Server};SERVER=HARRISONS-THINK;DATABASE=LendApp;Trusted_Connection=yes;')
app.config['SQLALCHEMY_DATABASE_URI'] = "mssql+pyodbc:///?odbc_connect=%s" % params
If you are getting any Login failed for User error then please go to this
http://itproguru.com/expert/2014/09/how-to-fix-login-failed-for-user-microsoft-sql-server-error-18456-step-by-step-add-sql-administrator-to-sql-management-studio/.
This solution makes a perfect connection string to create database connection using flask-sqlalchemy python which can handle password containing special characters.
# Make sure to replace below data with your DB values
DATABASE_HOST = "10.10.10.110"
DATABASE_NAME = "dbtest"
DATABASE_USERNAME = "admin"
DATABASE_PASSWORD = "admin@123"
# to elimate the error, if the password contains special characters like '@'
DATABASE_PASSWORD_UPDATED = urllib.parse.quote_plus(DATABASE_PASSWORD)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mssql+pymssql://'+DATABASE_USERNAME+':'+DATABASE_PASSWORD_UPDATED+'@'+DATABASE_HOST+'/'+DATABASE_NAME
The code snippet is tired and tested sample to create database connection using flask-sqlalchemy python.
Providing database
import os, sys, click, urllib
from flask import Flask, jsonify, request
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import text
# Make sure to replace below data with your DB values
DATABASE_HOST = "10.10.10.110"
DATABASE_NAME = "dbtest"
DATABASE_USERNAME = "admin"
DATABASE_PASSWORD = "admin@123"
app = Flask(__name__)
# to elimate the error, if the password contains special characters like '@'
DATABASE_PASSWORD_UPDATED = urllib.parse.quote_plus(DATABASE_PASSWORD)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mssql+pymssql://'+DATABASE_USERNAME+':'+DATABASE_PASSWORD_UPDATED+'@'+DATABASE_HOST+'/'+DATABASE_NAME
app.config['SQLALCHEMY_ECHO'] = True
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
# check if the connection is successfully established or not
with app.app_context():
try:
# db.session.execute('SELECT 1')
db.session.execute(text('SELECT 1'))
print('nn----------- Connection successful !')
except Exception as e:
print('nn----------- Connection failed ! ERROR : ', e)
class Test(db.Model):
__tablename__ = 't_test'
__table_args__ = {'extend_existing': True} # allows you to modify the existing table without raising an error.
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
applicationnumber = db.Column(db.String(15))
source = db.Column(db.String(50))
def __init__(self, applicationnumber, source):
self.applicationnumber = applicationnumber
self.source = source
print("Executed __init__ !")
@app.route('/api/test', methods=['POST'])
def insert():
try:
applicationnumber = request.json['applicationnumber']
source = request.json['source']
try:
t_test_obj = Test(applicationnumber, source)
db.session.add(t_test_obj)
db.session.commit()
print("nRow commited --------")
return jsonify({'status': 'success', 'message': 'Values inserted successfully.'}), 201
except Exception as e :
error=f"Exception Raised : {e}, errorOnLine: {sys.exc_info()[-1].tb_lineno}, file : {os.path.basename(__file__)}"
click.secho(error, fg="red")
return jsonify({'status': 'failure', 'message': f"{error}"}), 500
except Exception as e:
db.session.rollback()
return jsonify({'status': 'error', 'message': str(e)}), 500
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=True)
# MSSQL query to create table t_test
'''
CREATE TABLE t_test(
[id] [int] IDENTITY(1,1) NOT NULL,
[applicationnumber] [varchar](50) NOT NULL,
[source] [varchar](50) NULL
)
'''
# API JSON request
'''
{"applicationnumber": "IM012345",
"source": "ABCD"
}
'''
Just had this issue as well, this is my solution for that:
import pyodbc
conn_str = 'DRIVER={ODBC Driver 17 for SQL Server};'
'SERVER=ServerName;'
'DATABASE=dbName;'
'UID=uid;'
'PWD=pass'
conn = pyodbc.connect(conn_str)
app.config["SQLALCHEMY_DATABASE_URI"] = 'mssql+pyodbc:///?odbc_connect={}'.format(conn_str)
and I had to install and config the ODBC Driver.
Download ODBC Driver for SQL Server
I’m trying to connect to a local MSSQL DB through Flask-SQLAlchemy.
Here’s a code excerpt from my __init__.py
file:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mssql+pyodbc://HARRISONS-THINK/LendApp'
db = SQLAlchemy(app)
SQLALCHEMY_TRACK_MODIFICATIONS = False
As you can see in SQL Server Management Studio, this information seems to match:
Here is the creation of a simple table in my models.py
file:
from LendApp import db
class Transaction(db.model):
transactionID = db.Column(db.Integer, primary_key=True)
amount = db.Column(db.Integer)
sender = db.Column(db.String(80))
receiver = db.Column(db.String(80))
def __repr__(self):
return 'Transaction ID: {}'.format(self.transactionID)
I am then connecting to the database using a Python Console within Pycharm via the execution of these two lines:
>>> from LendApp import db
>>> db.create_all()
This is resulting in the following error:
DBAPIError: (pyodbc.Error) ('IM002', '[IM002] [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified (0) (SQLDriverConnect)')
The only thing that I can think of is that my database connection string is incorrect. I have tried altering it to more of a standard Pyodbc connection string and including driver={SQL SERVER}
but to no prevail.
If anyone could help me out with this it would be highly appreciated.
Thanks
I believe your connection string is missing the authentication details. From Flask-SQLAlchemy documentation, the connection string should have the following format
dialect+driver://username:password@host:port/database
From your example, I believe it will look something like this
app.config['SQLALCHEMY_DATABASE_URI'] = 'mssql+pyodbc://<username>:<password>@<Host>:<Port>/LendApp'
So I just had a very similar problem and was able to solve by doing the following.
Following the SQL Alchemy documentation I found I could use the my pyodbc connection string like this:
# Python 2.x
import urllib
params = urllib.quote_plus("DRIVER={SQL Server Native Client 10.0};SERVER=dagger;DATABASE=test;UID=user;PWD=password")
engine = create_engine("mssql+pyodbc:///?odbc_connect=%s" % params)
# Python 3.x
import urllib
params = urllib.parse.quote_plus("DRIVER={SQL Server Native Client 10.0};SERVER=dagger;DATABASE=test;UID=user;PWD=password")
engine = create_engine("mssql+pyodbc:///?odbc_connect=%s" % params)
# using the above logic I just did the following
params = urllib.parse.quote_plus('DRIVER={SQL Server};SERVER=HARRISONS-THINK;DATABASE=LendApp;Trusted_Connection=yes;')
app.config['SQLALCHEMY_DATABASE_URI'] = "mssql+pyodbc:///?odbc_connect=%s" % params
This then caused an additional error because I was also using Flask-Migrate and apparently it doesn’t like % in the connection URI. So I did some more digging and found this post. I then changed the following line in my ./migrations/env.py
file
From:
from flask import current_app
config.set_main_option('sqlalchemy.url',
current_app.config.get('SQLALCHEMY_DATABASE_URI'))
To:
from flask import current_app
db_url_escaped = current_app.config.get('SQLALCHEMY_DATABASE_URI').replace('%', '%%')
config.set_main_option('sqlalchemy.url', db_url_escaped)
After doing all this I was able to do my migrations and everything seems as if it is working correctly now.
If someone still stumbled upon this issue and trying to figure out another solution then try with pymssql
instead of pyodbc
;
pip install pymssql
Connection URI would be:
conn_uri = "mssql+pymssql://<username>:<password>@<servername>/<dbname>"
I just changed my connection string something like this and its worked perfectly
NOTE: you need to install pyodbc to work….
app.config["SQLALCHEMY_DATABASE_URI"] = "mssql+pyodbc://user:pwd@server/database?driver=SQL+Server"
Note:
Try to avoid ‘@’ character in password. you will get error because connection string also has ‘@’ character after password. This also can cause the connection error
I had the same problem, it was resolved by specifying:
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "mssql+pyodbc://MySQLServerName/MyTestDb?driver=SQL+Server?trusted_connection=yes"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db.init_app(app)
using below solution i get resolve my connection issue with MSSQL server
params = urllib.parse.quote_plus('DRIVER={SQL Server};SERVER=HARRISONS-THINK;DATABASE=LendApp;Trusted_Connection=yes;')
app.config['SQLALCHEMY_DATABASE_URI'] = "mssql+pyodbc:///?odbc_connect=%s" % params
If you are getting any Login failed for User error then please go to this
http://itproguru.com/expert/2014/09/how-to-fix-login-failed-for-user-microsoft-sql-server-error-18456-step-by-step-add-sql-administrator-to-sql-management-studio/.
This solution makes a perfect connection string to create database connection using flask-sqlalchemy python which can handle password containing special characters.
# Make sure to replace below data with your DB values
DATABASE_HOST = "10.10.10.110"
DATABASE_NAME = "dbtest"
DATABASE_USERNAME = "admin"
DATABASE_PASSWORD = "admin@123"
# to elimate the error, if the password contains special characters like '@'
DATABASE_PASSWORD_UPDATED = urllib.parse.quote_plus(DATABASE_PASSWORD)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mssql+pymssql://'+DATABASE_USERNAME+':'+DATABASE_PASSWORD_UPDATED+'@'+DATABASE_HOST+'/'+DATABASE_NAME
The code snippet is tired and tested sample to create database connection using flask-sqlalchemy python.
Providing database
import os, sys, click, urllib
from flask import Flask, jsonify, request
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import text
# Make sure to replace below data with your DB values
DATABASE_HOST = "10.10.10.110"
DATABASE_NAME = "dbtest"
DATABASE_USERNAME = "admin"
DATABASE_PASSWORD = "admin@123"
app = Flask(__name__)
# to elimate the error, if the password contains special characters like '@'
DATABASE_PASSWORD_UPDATED = urllib.parse.quote_plus(DATABASE_PASSWORD)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mssql+pymssql://'+DATABASE_USERNAME+':'+DATABASE_PASSWORD_UPDATED+'@'+DATABASE_HOST+'/'+DATABASE_NAME
app.config['SQLALCHEMY_ECHO'] = True
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
# check if the connection is successfully established or not
with app.app_context():
try:
# db.session.execute('SELECT 1')
db.session.execute(text('SELECT 1'))
print('nn----------- Connection successful !')
except Exception as e:
print('nn----------- Connection failed ! ERROR : ', e)
class Test(db.Model):
__tablename__ = 't_test'
__table_args__ = {'extend_existing': True} # allows you to modify the existing table without raising an error.
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
applicationnumber = db.Column(db.String(15))
source = db.Column(db.String(50))
def __init__(self, applicationnumber, source):
self.applicationnumber = applicationnumber
self.source = source
print("Executed __init__ !")
@app.route('/api/test', methods=['POST'])
def insert():
try:
applicationnumber = request.json['applicationnumber']
source = request.json['source']
try:
t_test_obj = Test(applicationnumber, source)
db.session.add(t_test_obj)
db.session.commit()
print("nRow commited --------")
return jsonify({'status': 'success', 'message': 'Values inserted successfully.'}), 201
except Exception as e :
error=f"Exception Raised : {e}, errorOnLine: {sys.exc_info()[-1].tb_lineno}, file : {os.path.basename(__file__)}"
click.secho(error, fg="red")
return jsonify({'status': 'failure', 'message': f"{error}"}), 500
except Exception as e:
db.session.rollback()
return jsonify({'status': 'error', 'message': str(e)}), 500
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=True)
# MSSQL query to create table t_test
'''
CREATE TABLE t_test(
[id] [int] IDENTITY(1,1) NOT NULL,
[applicationnumber] [varchar](50) NOT NULL,
[source] [varchar](50) NULL
)
'''
# API JSON request
'''
{"applicationnumber": "IM012345",
"source": "ABCD"
}
'''
Just had this issue as well, this is my solution for that:
import pyodbc
conn_str = 'DRIVER={ODBC Driver 17 for SQL Server};'
'SERVER=ServerName;'
'DATABASE=dbName;'
'UID=uid;'
'PWD=pass'
conn = pyodbc.connect(conn_str)
app.config["SQLALCHEMY_DATABASE_URI"] = 'mssql+pyodbc:///?odbc_connect={}'.format(conn_str)
and I had to install and config the ODBC Driver.
Download ODBC Driver for SQL Server