Flask-SQLAlchemy multiple databases and binds - python

URI:
SQLALCHEMY_DATABASE_URI = "mssql+pymssql://user:password123#127.0.0.1/DbOne"
SQLALCHEMY_BINDS = {
"sql_server": "mysql+pymysql://user:password123#127.0.0.1/DbTwo"
}
Models.py
class CrimMappings(db.Model):
__tablename__ = "crim_mappings"
id = db.Column(db.Integer, primary_key=True)
date_mapped = db.Column(db.Date)
county_id = db.Column(db.Integer)
state = db.Column(db.String(20))
county = db.Column(db.String(100))
AgentID = db.Column(db.String(100), unique=True)
CollectionID = db.Column(db.String(100))
ViewID = db.Column(db.String(100))
class LicenseType(db.Model):
__bind_key__ = "sql_server"
__table__ = db.Model.metadata.tables["sbm_agents"]
however it throws me a KeyError saying the 'sbm_agents' table is not found which it should be there because I've specified the bind key to point to the sql_server bind.
__init__.py
from os.path import join,dirname,abspath
from flask_admin import Admin
from project.apps.flask_apps.user_app.forms import UserAdminForm
from flask_admin.contrib.sqla import ModelView
from project import app_factory, db
from project.apps.flask_apps.admin_own.views import AdminHome, Utilities
from project.apps.flask_apps.admin_own.models import CredentCheckMappings, AllAgents, LicenseTypes
from project.apps.flask_apps.admin_own.forms import MasterAgentForm, AgentMappingsModelView, AllLicenseForm
from project.apps.flask_apps.user_app.models import Users
def create_application():
config_path = join(dirname(abspath(__file__)), "config", "project_config.py")
app = app_factory(config_path=config_path)
admin = Admin(app, template_mode="bootstrap3", base_template="base_templates/admin_base.html",
index_view=AdminHome())
with app.app_context():
db.create_all()
db.Model.metadata.reflect(db.engine)
admin.add_view(MasterAgentForm(AllAgents, db.session))
admin.add_view(UserAdminForm(Users, db.session))
admin.add_view(Utilities(name="Utilities", endpoint="utilities"))
admin.add_view(AgentMappingsModelView(CredentCheckMappings, db.session))
admin.add_view(AllLicenseForm(LicenseTypes, db.session))
return app
application = create_application()
if __name__ == "__main__":
application.run(host="0.0.0.0", port=5000, debug=True)
what am I missing here?
I've tried this:
flask sqlalchemy example around existing database
but im getting the KeyError
did something change or im missing a step?
Edit:
For people wanting to know how I got around this.
I went straight to SqlAlchemy and did this
from sqlalchemy import create_engine, MetaData
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.automap import automap_base
from urllib.parse import quote_plus
engine = create_engine("mssql+pyodbc:///?odbc_connect="+ quote_plus("DRIVER={FreeTDS};SERVER=172.1.1.1;PORT=1433;DATABASE=YourDB;UID=user;PWD=Password"))
metadata = MetaData(engine)
Session = scoped_session(sessionmaker(bind=engine))
LicenseType= Table("sbm_agents", metadata, autoload=True)
that way im not reflecting the entire database and only choose to reflect certain tables. because it turns out that reflecting the entire database is slow.
although this approach is a little tougher because you have to configure FREETDS but its doable just a little tedious and confusing at first

Use db.reflect() instead of db.Model.metadata.reflect(db.engine).

Related

Mapping sql alchemy database models defined in a separate file

I have created a website using flask (python). I would like to create my SQLAlchemy database models in a separate file and import them. I have tried the following code but getting import error. I have tried solutions from similar questions but none is working. What modifications are needed to be made in my code?
structure
main.py
from Website import create_app
app = create_app()
if __name__ == '__main__':
app.run(debug=True)
init.py (underscore not displayed)
from flask import Flask
from .routes import routes
from flask_sqlalchemy import SQLAlchemy
from .dbmodels import Subscribers
DB_NAME = "myDatabase.db"
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
#..........................Register blueprint.......................#
app.register_blueprint(routes, url_prefix='/')
#..........................Database config.......................#
app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{DB_NAME}'
db.init_app(app)
db.create_all()
sub_1 = Subscribers(name="pavan")
db.session.add(sub_1)
db.session.commit()
return app
dbmodels.py
from . import db
from datetime import datetime
class Subscribers(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
date_created = db.Column(db.DateTime, default=datetime.utcnow())
def __repr__(self):
return '<User %r>' % self.name
You import Subscribers from dbModels in __init__ and db from __init__ in dbModelds. It leads to circular imports.
The simpliest solution - put db = SQLAlchemy() in separate file (e.g. extensions.py and import it from this file in __init__ and in dbModels

'scoped_session' object has no attribute 'create_all' 'scoped_session' object has no attribute 'session'

So Im trying to create a website using flask and SQLAlchemy for database storage but I keep getting the two aforementioned errors
Here is my app.py code
import os
from flask import Flask, session,render_template, request
from flask_session import Session
from sqlalchemy import create_engine,Column, Integer, String
from sqlalchemy.orm import scoped_session, sessionmaker
from flask_sqlalchemy import SQLAlchemy
from models import *
app = Flask(__name__)
#app.config["DATABASE_URL"] = "sqlite:////plz_work.db"
app.config["SQLALCHEMY_DATABASE_URI"] = os.getenv("DATABASE_URL")
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db.init_app(app)
# Check for environment variable
#if not os.getenv("DATABASE_URL"):
# raise RuntimeError("DATABASE_URL is not set")
# Configure session to use filesystem
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
# Set up database
engine = create_engine(os.getenv("DATABASE_URL"))
db = scoped_session(sessionmaker(bind=engine))
class User:
def __init__(self,username,password):
self.username = username
self.password = password
#app.route("/")
def index():
return render_template('index.html')
#app.route("/registration.html")
def registration():
return render_template('registration.html')
#app.route("/send", methods = ['GET','POST'])
def send():
username = request.form['username']
password = request.form['password']
users = User(username,password)
db.session.add(users)
db.session.commit()
return render_template('index.html')
if __name__ == "__main__":
app.run(debug = True)
db.create_all()
and here is my models.py file
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class USERS(db.Model):
__tablename__ = "Users"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String)
password = db.Column(db.String)
def __repr__(self):
value = "USER:({}, {})".format(self.username, self.password)
return value
I have been looking online for a soloution for so long but I can not find anything that works for me, and I have spent 2 days just on this problem, any help will be appreciated.
Thank You !!
I guess you're overriding your database object within your models.py file.
I suggest you to use sqlalchemy itself or flask-sqlalchemy not using them together. In my opinion things get complicated if you use them together.
You can achive that like this:
in your app.py
...your_other_imports...
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from .models import *
app = Flask(__name__)
...your_other_configs...
# Set up database
engine = create_engine(os.getenv("DATABASE_URL"))
db = scoped_session(sessionmaker(bind=engine))
#NOW db carries your database session
#Do not define your database models in app.py remove User class from here.
#You should define your database model and also your query method (not necessary)
#if you're used to query with flask-sqlalchemy. Would make queries look similar to you
dbModel = declarative_base()
dbModel.query = db.query_property()
# define the function which will create your tables
def init_db():
from .models import *
dbModel.metadata.create_all(bind=engine)
...your_routes...
if __name__ == "__main__":
app.run(debug = True)
# now call the function to create your tables
init_db()
in your models.py
from .app import dbModel
from sqlalchemy import Column, Integer, String
class User(dbModel):
__tablename__ = "users"
id = Columnn(Integer, primary_key=True)
username = Column(String)
password = Column(String)
def __repr__(self):
value = "USER:({}, {})".format(self.username, self.password)
return value
Using query_property you can now query your data from your database and use your session to put data in your database like this:
User.query.filter_by(username=...).first()
newUser = User(
username=...,
password=...
)
db.add(newUser)
db.commit()

Circular dependency while importing models for create_all() in a Flask App

Context:
Python 3.6
flask
flask_restful
flask_sqlalchemy
Objective: Create database tables before the first request to the flask restful api, avoiding circular dependency between models.
Problem: When I do the first resquest, #app.before_first_request is called as expected, but It seems to be considering the includes with circular dependendy:
File "./app.py", in create_tables
from models.uf_model import UfModel
File "home/server/models/uf_model.py", in <module>
from models.cidade_model import CidadeModel
File "/home/server/models/cidade_model.py", in <module>
from models.uf_model import UfModel
ImportError: cannot import name 'UfModel'
MY QUESTION: Even using app_context(), as suggested in similar questions, the circular dependency was not solved. How to fix it? What am I doing wrong?
My code:
db.py:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
uf_model.py One uf has many cidades
from db import db, filter_query
from datetime import datetime
from models.cidade_model import CidadeModel
class UfModel(db.Model):
__tablename__ = 'uf'
unfe_id = db.Column(db.Integer, primary_key=True)
cidades = db.relationship('CidadeModel', backref='unfe_cidades', lazy=True, uselist=False)
To easily find all the cidades of a given uf, I've created that relationship.
cidade_model.py One cidade has just one uf
from db import db, filter_query
from datetime import datetime
from models.uf_model import UfModel
class CidadeModel(db.Model):
__tablename__ = 'cidade'
cida_id = db.Column(db.Integer, primary_key=True)
cida_unfe_id = db.Column(db.Integer, db.ForeignKey('uf.unfe_id'), nullable=False, index=True)
uf = db.relationship('UfModel')
To easily find the uf of a given cidade, I've created that relationship.
app.py:
from db import db
app = Flask(__name__)
api = Api(app)
#app.before_first_request
def create_tables():
with app.app_context():
from models.uf_model import UfModel
from models.cidade_model import CidadeModel
db.create_all()
if __name__ == '__main__':
# some resources api.add_resource
db.init_app(app)
You've got 2 ways to define relationships in models, either you reference the model class itself or you use the class name (the latter was added to avoid such circular dependency problem).
Since you've define the relationship with strings (e.g: uf = db.relationship('UfModel') in cidade_model.py), you don't need to import from models.uf_model import UfModel anymore. The same goes for CidadeModel in uf_model.py. You aren't using the imported class so you can just remove the import line.

Using SQLAlchemy models in and out of Flask

I'm trying to build SQLAlchemy models that can be used in Flask and in other non-Flask services. I know that in order to use these objects in Flask I can use the Flask-SQLAlchemy module and build the models like this:
app_builder.py
def create_app(config):
# Create a Flask app from the passed in settings
app = Flask('web_service')
app.config.from_object(config)
# Attach SQLAlchemy to the application
from database import db
db.init_app(app)
database.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Job(db.Model):
__tablename__ = 'job'
job_id = db.Column(db.Integer, primary_key=True)
description = db.Column(db.String(256))
def __init__(self, description):
self.description = description
However it looks like doing this ties the models to using flask_sqlalchemy. I have another service that I would like to use these models in that don't use flask. Is there a way I can reuse these class definitions (maybe by changing db.Model) within a non-Flask specific context?
flask_sqlalchemy doesn`t allow you to use it outside of a Flask context. However, you can create models via SQLAlchemy itself. So your database.py file would look like this:
from sqlalchemy import MetaData, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
metadata = MetaData()
Base = declarative_base(metadata=metadata)
class Job(Base):
__tablename__ = 'job'
job_id = Column(Integer, primary_key=True)
description = Column(String(256))
def __init__(self, description):
self.description = description
You can initialize a flask_sqlalchemy object using produced metadata (flaskdb.py):
from flask_sqlalchemy import SQLAlchemy
from database import metadata
db = SQLAlchemy(metadata=metadata)
And you initialize your Flask app like this:
from flask import Flask
from flaskdb import db
def create_app(config):
app = Flask('web_service')
app.config.from_object(config)
db.init_app(app)
Created models can be used outside of the Flask context via a Session. For example:
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from database import metadata, Job
engine = create_engine('your://database#configuration/here')
session = Session(engine)
jobs = session.query(Job).all()
session.close()
As a downside of this approach, you can't use direct access to database objects through models. Instead, you are forced to use Sessions:
from database import Job
from flaskdb import db
Job.query.all() # Does not work
db.session.query(Job).all() # Works

Flask - SQLAlchemy OperationalError

I've come into the following error:
sqlalchemy.exc.OperationalError
OperationalError: (OperationalError) no such table: user u'SELECT user.id AS user_id, user.name AS user_name, user.password AS user_password \nFROM user \nWHERE user.id = ?' (1,)
I'm not sure how to debug this but I think it must be coming because its not loading the db file that I already generated using my models.py file. I've loaded that db file and made sure that the users table exists, and it does with data, but I can't figure out how to connect my flask application to the database.
Here's my models.py that I ran beforehand to generate the tables (I haven't included the declarations above it):
from datetime import datetime
import os
from sqlalchemy import Column, ForeignKey
from sqlalchemy import Boolean, DateTime, Integer, String, Text
from sqlalchemy.orm import relationship, synonym, backref
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
""" User """
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(200))
password = Column(String(100))
def __init__(self, name, password):
self.name = name
self.password = password
def __repr__(self):
return '<User %r>' % self.name
if __name__ == '__main__':
from datetime import timedelta
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
PWD = os.path.abspath(os.curdir)
engine = create_engine('sqlite:///{}/arkaios.db'.format(PWD), echo=True)
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
# Add a sample user
user = User(name='Philip House', password="test")
session.add(user)
session.commit()
Here's app.py:
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from flask import render_template
from arkaios.models import Base, User
from arkaios import config
app = Flask(__name__)
app.config.from_object(config)
db = SQLAlchemy(app)
db.Model = Base
#app.route('/admin/large-group')
def largeGroupOverview():
user = db.session.query(User).filter_by(id=1)
return render_template('largegroup/overview.html', user=user)
#app.route('/admin/large-group/<int:event_id>')
def largeGroupAttendance(event_id):
return render_template('largegroup/attendance.html')
#app.route('/focus')
def largegroup():
return 'Focus work'
And finally, app.py refers to config.py which is below:
import os
PWD = os.path.abspath(os.curdir)
DEBUG=True
SQLALCHEMY_DATABASE_URI = 'sqlite:///{}/arkaios.db'.format(PWD)
SECRET_KEY = 'thisissecret'
SESSION_PROTECTION = 'strong'
I can post the stack trace as well if need be! There must be something missing conceptually about how I'm thinking about how to connect Flask and SQLAlchemy, but I can't figure it out.
Thanks for any help :)
Are you running python models.py before python app.py app to create the database? The if __name__ == "__main__" will keep that part of the code from running when you import the file from app.py.
I would also make sure the db is valid using sqlite3 and run the .tables command.

Categories

Resources