Flask SQLAlchemy Connect to MySQL Database - python

Setup & Code:
I'm building a basic Flask Application with an an AngularJS front end and I am currently at the point where I need to make a connection to a MySQL database I have hosted with Godaddy phpmyadmin.
This is part of my __init__.py
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
# Create instnace called app
app = Flask(__name__)
app.config['SQLAlchemy_DATABASE_URI'] = 'mysql://username:password##xxxxxx.hostedresource.com/dbname'
# Create SQLAlchemy object
db = SQLAlchemy(app)
# ...
This is my models.py
from app import app, db
class UsersPy(db.Model):
__tablename__ = "userspy"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String, nullable=False)
password = db.Column(db.String, nullable=False)
def __init__(self, username, password):
self.username = username
self.password = password
def __repr__(self):
return '<title {}'.format(self.username)
This is a snippet from my views.py:
from app import app, db
from app.models import UsersPy
from flask import render_template, request, redirect, url_for, jsonify, session, flash
#app.route('/testdb/')
def testdb():
admin = UsersPy('user1', 'password1')
guest = UsersPy('user2', 'password2')
db.session.add(admin)
db.session.add(guest)
#db.session.merge(admin)
#db.session.merge(guest)
db.session.commit()
results = UsersPy.query.all()
json_results = []
for result in results:
d = {'username': result.username,
'password': result.password}
json_results.append(d)
return jsonify(items=json_results)
Problem:
All of this works well, the users are 'created' and displayed back in JSON format when you visit the /testdb/ location, however the actual database hosted with Godaddy is not being updated so the real connection must not be being made or it is failing for some reason. I have the userspy database table already created but add() and commit() functions are not actually adding users to the database. I can't figure out how to solidify the connection between SQLAlchemy and the MySQL Database. Any help is appreciated, thanks.

A good first step in debugging this would be to set SQLALCHEMY_ECHO to True in your app configuration. This will cause the actual MySQL database statements that SQLAlchemy is executing to be printed out.
Also, it's worth noting that SQLAlchemy_DATABASE_URI is different from SQLALCHEMY_DATABASE_URI, which is what the Flask-SQLAlchemy documentation states the config key should be.

Related

Flask & SQL ALchemy, the created Database has an unknown Type

I am currently writing a program in python using flask and flask_sqlalchemy. I have done the same steps as in the documentation. But when the database gets created automatically, it has an unknown file type, altough it should be a sqlite database. I am using Pycharm btw.
from flask import Flask, render_template, request, redirect
from flask_sqlalchemy import SQLAlchemy
# create the extension
db = SQLAlchemy()
# create the app
app = Flask(__name__)
# configure the SQLite database, relative to the app instance folder
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///filemanager.db"
# initialize the app with the extension
db.init_app(app)
class File(db.Model):
id = db.Column(db.Integer, primary_key=True)
path = db.Column(db.String, unique=True, nullable=False)
type = db.Column(db.String, unique=False, nullable=False)
#app.route('/', methods=['GET', 'POST'])
def index():
return render_template('index.html')
if __name__ == '__main__':
create_database = True
if create_database:
with app.app_context():
db.create_all()
app.run(debug=True, port=5008)
I tried to change the file type manually to sqlite, but it still doesn't contain tables and columns. If I create the columns manually in the console everything works, but I have and want to do it programmatically.
I also tried another stackoverflow answer, where he split the code into two files, didn't work eiter.
Thanks in advance!
The problem was the name of the Database and the name of the table. I had "filemanager.db" and "files", these names don't work (don't ask me why), but I tried with "users.db" and "users" and it works

db.create_all() not generating db

I'm trying to test Flask with SQLAlchemy and I stumbeld accross this problem. First, I have to note that I read all of the related threads and none of them solves my problem. I have a problem that db.create_all() doesn't generate the table I defined. I have model class in file person.py:
from website import db
class Person(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String, nullable=False)
password = db.Column(db.String)
width = db.Column(db.Integer)
height = db.Column(db.Integer)
agent = db.Column(db.String)
user_data_dir = db.Column(db.String)
And in my website.py which is the file from where I launch the app:
from flask import Flask, jsonify, render_template, request
from flask_sqlalchemy import SQLAlchemy
# create the extension
db = SQLAlchemy()
def start_server(host, port, debug=False):
from person import Person
# create the app
app = Flask(__name__,
static_url_path='',
static_folder='web/static',
template_folder='web/templates')
# configure the SQLite database, relative to the app instance folder
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///database0.db"
# initialize the app with the extension
db.init_app(app)
print('initialized db')
print('creating tables...')
with app.app_context():
db.create_all()
db.session.add(Person(username="example33"))
db.session.commit()
person = db.session.execute(db.select(Person)).scalar()
print('persons')
print(person.username)
if __name__ == '__main__':
start_server(host='0.0.0.0', port=5002, debug=True)
I think the problem might be that the Person class is not importing properly, because when I put the class inside the start_server function it executes fine and creates the table, but I don't know why this is happening. I followed all the advice and imported it before everything, and also I share the same db object between the 2 files
There is probably a better way to do this but this is the only way I could get this to work. You need to create a models.py file or w.e you wanna call it. Then all your database stuff goes in there. The db engine, ALL your models and a function to initialize it all. The reason is, you are having import issues where Person is imported but not fully and so the db doesn't have it in its metadata.
models.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Person(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String, nullable=False)
password = db.Column(db.String)
width = db.Column(db.Integer)
height = db.Column(db.Integer)
agent = db.Column(db.String)
user_data_dir = db.Column(db.String)
# All other models
def initialize_db(app: Flask):
db.init_app(app)
with app.app_context():
db.create_all()
main.py
from flask import Flask
import models
def start_server(host, port, debug=False):
app = Flask(__name__)
# configure the SQLite database, relative to the app instance folder
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///database0.db"
# initialize the app with the extension
models.initialize_db(app)
db = models.db
with app.app_context():
db.session.add(models.Person(username="example33"))
db.session.commit()
person = db.session.execute(db.select(models.Person)).scalar()
print('persons')
print(person.username)
if __name__ == '__main__':
start_server(host='0.0.0.0', port=5002, debug=True)
I am reading the documentation,
which explains that the function will
Create all tables stored in this metadata.
That leads me to believe Person is not associated with the db metadata.
You mentioned
when I put the class inside the start_server function it ... creates the table
Your from person import Person is nice enough,
but I suspect we wanted a simple import person.
In many apps the idiom would be import models.
Failing that, you may be able to point
create_all in the right direction
with this optional parameter:
tables – Optional list of Table objects, which is a subset of the total tables in the MetaData
Please let us know
what technical approach worked for you.

Is there a way to add mySQL database/schema name in flask sqlalchemy connection

I have a flask restful app connected to mySQL database and I am using SQLAlchemy. We can connect to the mySQL server using the following -
app.config['SQLALCHEMY_DATABASE_URI'] = f"mysql+pymysql://root:password#127.0.0.1:3306"
I am working on a use case where the database name will be provided on real-time basis through a GET request. Based on the database name provided, the app will connect to the respective database and perform the operations. For this purpose, I would like to have a way where I can tell the flask app to talk to the provided database (Flask app is already connected to the mySQL server). Currently, I am creating the connection again in the API class.
API: Calculate.py
from flask_restful import Resource, reqparse
from app import app
class Calculate(Resource):
def get(self):
parser = reqparse.RequestParser()
parser.add_argument('schema', type=str, required=True, help='Provide schema name.')
args = parser.parse_args()
session['schema_name'] = args.get('schema')
app.config['SQLALCHEMY_DATABASE_URI'] = f"mysql+pymysql://root:password#127.0.0.1:3306/{session['schema_name']}"
from db_models.User import User
...
DB Model: User.py
from flask import session
from flask_sqlalchemy import SQLAlchemy
from app import app
db = SQLAlchemy(app)
class User(db.Model):
__tablename__ = 'user'
__table_args__ = {"schema": session['schema_name']}
User_ID = db.Column(db.Integer, primary_key=True)
Name = db.Column(db.String(50))
db.create_all()
The above thing works for me. But I would want to understand if there is an alternative to this or a better way of doing this.
Edit: The above code does not work. It references the first schema name that was provided even if I provide a new schema name in the same running instance of the app.
you can write the SQLALCHEMY path like this:
SQLALCHEMY_DATABASE_URI='mysql+pymysql://root:password#localhost:3306/database name'
According to the docs not all values can be updated (first parragraph), in your use case you should use SQLALCHEMY_BINDS variable in your use case this is a dict and create a Model for each schema. Example:
Db Model
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://root:password#127.0.0.1:3306/schema_name1"
SQLALCHEMY_BINDS = {
'db1': SQLALCHEMY_DATABASE_URI, # default
'db2': f"mysql+pymysql://root:password#127.0.0.1:3306/schema_name2"
}
app = Flask(__name__)
db = SQLALchemy(app)
then create a model for each schema
class UserModeldb1(db.Model):
__tablename__ = 'user'
__bind_key__ = 'db1' #this parameter is set according to the database
id = db.Column(db.Integer, primary_key=True)
...
class UserModeldb2(db.Model):
__tablename__ = 'user'
__bind_key__ = 'db2'
id = db.Column(db.Integer, primary_key=True)
...
finally in your get method add some logic to capture the schema and execute your model accorddingly. you should look this question is really helpful Configuring Flask-SQLAlchemy to use multiple databases with Flask-Restless

Creating a database in flask sqlalchemy

I'm building a Flask app with Flask-SQLAlchemy and I'm trying to write a script that will create a Sqlite3 database without running the main application. In order to avoid circular references, I've initialized the main Flask app object and the SQLAlchemy database object in separate modules. I then import and combine them in a third file when running the app. This works fine when I'm running the app, as the database is built and operates properly when create rows and query them. However, when I try to import them in another module, I get the following error:
RuntimeError: application not registered on db instance and no applicationbound to current context
My code looks like the following:
root/create_database.py
from application.database import db
from application.server import app
db.init_app(app)
db.create_all()
root/run.sh
export FLASK_APP=application/server.py
flask run
root/application/init.py
from database import db
from server import app
db.init_app(app)
from routes import apply_routes
apply_routes(app)
root/application/database.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
root/application/server.py
from flask import Flask
import os
app = Flask(__name__)
path = os.path.dirname( os.path.realpath(__file__) )
database_path = os.path.join(path, '../mydb.sqlite')
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + database_path
root/application/models/init.py
from user import User
root/application/models/user.py
from application.database import db
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
password = db.Column(db.String(120))
def __init__(self, username, password):
self.username = username
self.password = password
In my create_database.py script I'm trying to make sure that the SQLAlchemy db instance is configured with the config details from the app object, but it doesn't seem to be connecting for some reason. Am I missing something important here?
You either have to create a request or you have to create the models with sqlalchemy directly. We do something similar at work and chose the former.
Flask lets you create a test request to initialize an app. Try something like
from application.database import db
from application.server import app
with app.test_request_context():
db.init_app(app)
db.create_all()

use db without requiring app.app_context()- Flask

I have an app like this:
myapp/app/init.py:
import sqlite3
from contextlib import closing
from flask import Flask, g
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
# from app.models import db
from database import db
application = Flask(__name__)
application.config.from_object('config')
application.debug = True
db.init_app(application)
login_manager = LoginManager()
login_manager.init_app(application)
from app import views
myapp/database.py:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
myapp/app/models.py:
from database import db
from app import application
class CRUDMixin(object):
...
def delete(self, commit=True):
"""Remove the record from the database."""
with application.app_context():
db.session.delete(self)
return commit and db.session.commit()
class Model(CRUDMixin, db.Model):
"""Base model class that includes CRUD convenience methods."""
__abstract__ = True
def __init__(self, **kwargs):
db.Model.__init__(self, **kwargs)
class User(Model):
"""
:param str email: email address of user
:param str password: encrypted password for the user
"""
__tablename__ = 'users'
email = db.Column(db.String, primary_key=True)
password = db.Column(db.String)
authenticated = db.Column(db.Boolean, default=False)
def is_active(self):
"""True, as all users are active."""
return True
def get_id(self):
"""Return the email address to satisfy Flask-Login's requirements."""
return self.email
def is_authenticated(self):
"""Return True if the user is authenticated."""
return self.authenticated
def is_anonymous(self):
"""False, as anonymous users aren't supported."""
return False
The project I tried to structure after did not require with application.app_context() in the Model helper class. I cannot see any significant differences between my setup and its, and yet without with application.app_context() all over anything related to db I get the usual application not registered on db error. When everything you see in app/models.py and database.py was in app/__init__.py, it worked without requiring any with application.app_context() and I could import db raw in the shell like from myapp.app import db and it worked as is. What can I do to quiet the application not registered on db complaint but be able to use db easily without needing app_context, but still keep a proper directory structure where everything isn't jammed into init? Thank you
Flask-Script gives you a shell.
If you want to do it without Flask-Script, you must set the application context. A normal Python shell doesn't know how to setup your context.
It is easy to mimic the Flask-Script shell.
Create a shell.py file:
from app import application
ctx = application.app_context()
ctx.push()
Run it with python -i and use db with your app context already defined:
$ python -i shell.py
>>> from app import db
>>> db.create_all()

Categories