Flask Blueprint setup with SQLAlchemy gives UnboundExecutionError - python

I am using Flask to build an experimental application using Blueprint. Here is my project's structure:
-myproject/
requirements.txt
run.py
-apps/
-static/
-template/
-database/
__init__.py
views.py
model.py
auth.py
message.py
I init my app in init.py, using blueprint to integrate other parts of the app.
app = Flask(__name__)
from .views import views
from .model import model, db
from .auth import auth, login_manager
db.init_app(app)
app.register_blueprint(views)
app.register_blueprint(model)
app.register_blueprint(auth)
Then in views.py:
from flask import Flask, request, redirect, render_template, session, g, url_for, Blueprint
views = Blueprint('views', __name__)
from sqlalchemy.orm import scoped_session, relation, sessionmaker
# ORM Session
orm_session = scoped_session(sessionmaker())
#views.route('/courses')
def courses():
courses = orm_session.query(Course).order_by('-id')
return render_template('courses.html', courses=courses)
My Course class is defined in model.py:
class Course(db.Model):
__tablename__ = 'course'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), nullable=False)
subjects = db.relationship('Subject', secondary='course_subject_link')
students = db.relationship('Student', secondary='course_student_link')
active = db.Column(db.Boolean)
def __repr__(self):
return "<{0}:{1.name}:{1.subjects!r}:{1.students!r}>".format(Course, self)
In template folder, I have put something like {% for course in courses %} and {% set active_page = "courses" %} in the template file. When I run the app, it gives me this error:
UnboundExecutionError: Could not locate a bind configured on mapper Mapper|Course|course, SQL expression or this Session
I did not use Blueprint before so the app used to be able to run. But after I used Blueprint the urls seem to be broken. How can I fix this?

I know what the problem is.
From the hint in the error message I guess that I forget to create_engine and pass the engine to sessionmaker using bind=engine.
Here is the code I changed in views.py:
from os.path import join, dirname
_cwd = dirname(__file__)
engine = create_engine('sqlite:///' + join(_cwd, 'database/courses.sqlite'))
Session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
orm_session = Session()
Here database/courses.sqlite is the location of my database file.

Related

Cannot Create tables in a database using SQLAchemy

i have created app.py
and tables.py
which are the main app and a file used to define the tables of a database [database.db] respectively.
I cannot create tables in the database.db, what could be the problem?
Code for both is given below
#app.py
from flask import Flask, render_template, request, session, redirect
from tables import db
from flask_session import Session
app = Flask(__name__)
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'
db.init_app(app)
#app.before_first_request
def create_tables():
db.create_all()
#app.route("/")
def home():
return render_template("register.html")
#tables.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class users (db.Model):
users_key = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(21), nullable=False)
email = db.Column(db.String(31), nullable=False, unique=True)
password = db.Column(db.String(61), nullable=False)
i expected to get tables in the database.db file which is located in the same directory as the app.py file. i could not add any tables though.
You have to create database context and initialize it.
with app.app_context():
db.create_all()
Also make sure to import the Flask module from the flask package and SQLAlchemy from the flask_sqlalchemy package in tables.py.
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'
db = SQLAlchemy(app)

Flask SQLAlchemy and Blueprints

I am still learning flask and I have created an restful API with SQLAlchemy. The app is getting to be big and I would like to split it up into multiple files. When I separate the routes section from the main file, the app starts complaining about the SQL modules not being found. I have added all the imports to the routes file and it doesn't seem to help either. The error I am getting is:
module>
Session.configure(bind=engine)
NameError: name 'engine' is not defined
How can I get the Alchemy module to talk to admin.py?
app
app.py
admin
__init__.py
admin.py
######################## admin.py ########################
from flask import Flask, request, jsonify, Blueprint, render_template
import sqlalchemy
from sqlalchemy.ext.declarative import declarative_base
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
import os
import json
import logging
admin = Blueprint("admin", __name__)
#initialize Session
Session = sqlalchemy.orm.sessionmaker()
Session.configure(bind=engine)
session = Session()
employee_schema = EmployeeSchema()
#create Employee
#admin.route('/', methods=['POST'])
def add_employee():
..........
#Get Employee
#admin.route('/', defaults={'id': None}, methods=['GET'])
#admin.route('/<id>', methods=['GET'])
..........
#Delete Employee
#admin.route('/<id>', methods=['DELETE'])
def delete_employee(id):
..........
#update Employee
#admin.route('/<id>', methods=['PUT'])
def update_employee(id):
..........
######################## app.py ########################
from flask import Flask, request, jsonify
import sqlalchemy
from sqlalchemy.ext.declarative import declarative_base
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
import os
import json
import logging
from admin.admin import admin
#Init app
app = Flask(__name__)
#Allows URL's to be with a trailing / or not
app.url_map.strict_slashes = False
app.register_blueprint(admin, url_prefix="/")
#Gets password info from json file
..........
# Define the MariaDB engine using MariaDB Connector/Python
engine = sqlalchemy.create_engine(f"mariadb+pymysql://{DB_USER}:{DB_PASS}#{DB_HOST}:{DB_PORT}/{DB}")
Base = declarative_base()
class Employee(Base):
__tablename__ = 'employees'
id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
firstname = sqlalchemy.Column(sqlalchemy.String(length=100))
lastname = sqlalchemy.Column(sqlalchemy.String(length=100))
active = sqlalchemy.Column(sqlalchemy.Boolean, default=True)
Base.metadata.create_all(engine)
#initialize Session
Session = sqlalchemy.orm.sessionmaker()
Session.configure(bind=engine)
session = Session()
I suppose your error is traceable to admin.py, because in there you want to initialize the session again using enginewhich is not known in admin.py.
A possible solution would be to import engine from app.py.
Found a workaround. I created a init file inside the folder instead and it is now working.

Flask SQL Alchemy create_all doesn't create any tables

I was working on my school project which required me to develop an API on Flask. I was using MySQL with Flask SQLAlchemy. After I finished the project I haven't touched it in a month. When I came back and tried to run it I found out that it doesn't create tables on its own.
What I checked:
MySQL user has all permitions
App does connect to the database
Every model has table name defined
app.py file:
import logging
from os import environ
from flask import Flask
from flask_cors import CORS
from flask_restful import Api
from flask_sqlalchemy import SQLAlchemy
from config import DevConfig, ProdConfig
db = SQLAlchemy()
def create_app():
from resources import Area, Map, Ping, SensorData
env = environ.get('ENVIRONMENT')
if env == 'DEVELOPMENT':
Config = DevConfig
else:
Config = ProdConfig
app = Flask(__name__)
app.config.from_object(Config())
CORS(app)
logging.basicConfig(
filename='app.log',
level=logging.INFO
)
api = Api(app)
api.add_resource(Area, '/area')
api.add_resource(Map, '/map')
api.add_resource(SensorData, '/api/v1/saveSensorData')
api.add_resource(Ping, '/ping')
db.init_app(app)
with app.app_context():
from models import AreaModel, SensorDataModel
db.create_all()
return app
if __name__ == '__main__':
app = create_app()
app.run(host='0.0.0.0', port=8080)
One of the models:
from app import db
from datetime import datetime
class AreaModel(db.Model):
__tablename__ = 'area_records'
id = db.Column(
db.Integer,
primary_key=True
)
aqi = db.Column(
db.Integer,
)
latitude = db.Column(
db.String(16),
)
longitude = db.Column(
db.String(16),
)
created = db.Column(
db.DateTime,
default=datetime.now()
)
I found a solution, but not an answer. For some reason, when I run app.py directly using python app.py it won't create any tables. But when I created run.py with this code:
from app import create_app
app = create_app()
app.run(host='0.0.0.0', port=8080)
It worked! I hope someone can explain it but I'm really happy I got the solution.

Peewee error on model.create() [ Proxy ]

Hello.
When i'm trying to create new record in model, i'm getting
AttributeError: 'dict' object has no attribute 'compiler'
Possible, that i'm getting this error because using Proxy class, but can't find mistake in my code.
init.py
from flask import Flask
from flask_peewee.db import Proxy
from flask_bootstrap import Bootstrap
from app.config import config_select
db = Proxy()
bootstrap = Bootstrap()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config_select[config_name])
config_select[config_name].init_app(app)
db.initialize(config_select[config_name].DATABASE)
bootstrap.init_app(app)
#register blueprints
from app.blueprint.main import main_bp as main_blueprint
app.register_blueprint(main_blueprint)
return app
models.py
from peewee import *
from app import db
class BaseModel(Model):
class Meta:
database = db
class User(BaseModel):
id = PrimaryKeyField()
username = CharField(default='test', max_length=20)
class Meta:
db_table = 'users'
MODELS_LIST = [User]
Database was created by manager 'generate_db_tables' command
import os
from app import create_app
from flask_script import Manager, Shell
app = create_app(os.getenv('FLASK_CONFIG') or 'default')
manager = Manager(app)
def connect_db():
from peewee import SqliteDatabase
db_lite = SqliteDatabase(app.config['DATABASE']['name'])
return db_lite
#manager.command
def generate_db_tables():
from app.models.models import MODELS_LIST
db_lite = connect_db()
for model in MODELS_LIST:
db_lite.create_table(model, safe=True)
print("Db tables created")
and the view function:
from flask import render_template, session, \
redirect, url_for, current_app, flash, request, make_response
from . import main_bp
from .forms import NameForm
from app.models.models import User
#main_bp.route('/', methods=['GET', 'POST'])
def index():
form = NameForm()
if form.validate_on_submit():
User.create(username=form.name.data) # <<<< Here is error
return url_for('.index')
return render_template('index.html', form=form)
Before i started to use Proxy class everything worked like a charm.
Seems, that i pass dict
DATABASE = {
'name': 'test.db',
'engine': 'peewee.SqliteDatabase'
}
to db.initialize()
instead of string name of database
DATABASE_INFO = 'test.db'
DATABASE = peewee.SqliteDatabase(DATABASE_INFO)
db.initialize(DATABASE)

How do I remove a circular dependency between a Flask blueprint and the application initialisation? [duplicate]

I want to structure my Flask app something like:
./site.py
./apps/members/__init__.py
./apps/members/models.py
apps.members is a Flask Blueprint.
Now, in order to create the model classes I need to have a hold of the app, something like:
# apps.members.models
from flask import current_app
from flaskext.sqlalchemy import SQLAlchemy
db = SQLAlchemy(current_app)
class Member(db.Model):
# fields here
pass
But if I try and import that model into my Blueprint app, I get the dreaded RuntimeError: working outside of request context. How can I get a hold of my app correctly here? Relative imports might work but they're pretty ugly and have their own context issues, e.g:
from ...site import app
# ValueError: Attempted relative import beyond toplevel package
The flask_sqlalchemy module does not have to be initialized with the app right away - you can do this instead:
# apps.members.models
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Member(db.Model):
# fields here
pass
And then in your application setup you can call init_app:
# apps.application.py
from flask import Flask
from apps.members.models import db
app = Flask(__name__)
# later on
db.init_app(app)
This way you can avoid cyclical imports.
This pattern does not necessitate the you place all of your models in one file. Simply import the db variable into each of your model modules.
Example
# apps.shared.models
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
# apps.members.models
from apps.shared.models import db
class Member(db.Model):
# TODO: Implement this.
pass
# apps.reporting.members
from flask import render_template
from apps.members.models import Member
def report_on_members():
# TODO: Actually use arguments
members = Member.filter(1==1).all()
return render_template("report.html", members=members)
# apps.reporting.routes
from flask import Blueprint
from apps.reporting.members import report_on_members
reporting = Blueprint("reporting", __name__)
reporting.route("/member-report", methods=["GET","POST"])(report_on_members)
# apps.application
from flask import Flask
from apps.shared import db
from apps.reporting.routes import reporting
app = Flask(__name__)
db.init_app(app)
app.register_blueprint(reporting)
Note: this is a sketch of some of the power this gives you - there is obviously quite a bit more that you can do to make development even easier (using a create_app pattern, auto-registering blueprints in certain folders, etc.)
an original app.py: https://flask-sqlalchemy.palletsprojects.com/en/2.x/quickstart/
...
app = flask.Flask(__name__)
app.config['DEBUG'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = flask.ext.sqlalchemy.SQLAlchemy(app)
class Person(db.Model):
id = db.Column(db.Integer, primary_key=True)
...
class Computer(db.Model):
id = db.Column(db.Integer, primary_key=True)
...
# Create the database tables.
db.create_all()
...
# start the flask loop
app.run()
I just splitted one app.py to app.py and model.py without using Blueprint. In that case, the above answer dosen't work. A line code is needed to work.
before:
db.init_app(app)
after:
db.app = app
db.init_app(app)
And, the following link is very useful.
http://piotr.banaszkiewicz.org/blog/2012/06/29/flask-sqlalchemy-init_app/

Categories