Basic Flask SQLAlchemy Context Issue - python-3.x

I've read many of the other posts on having models separated from the main app but I can't get it to work with just app.py (my actual app) and models.py (my database models).
If I do the following I get an app.db file with no tables:
from app import db
db.create_all()
If I do the following I get a RuntimeError: No application found. Either work inside a view function or push an application context.:
from app import db
db.create_all()
I have also looked at Introduction into Contexts page and can't work out where I put def create_app():, none of it seemed to work in my case.
Here is my app.py:
from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy
from models import userTable
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
#app.route('/', methods=['GET', 'POST'])
def home():
return "home"
if __name__ == '__main__':
app.run(debug=True)
Here is my models.py:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class userTable(db.Model):
__tablename__ = "userTable"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)

Perhaps you could try the following:
app.py
from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy
import models
from models import initialize_db
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
initialize_db(app)
#app.route('/', methods=['GET', 'POST'])
def home():
return "home"
if __name__ == '__main__':
app.run(debug=True)
models.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def initialize_db(app):
app.app_context().push()
db.init_app(app)
db.create_all()
class userTable(db.Model):
__tablename__ = "userTable"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
The key is creating a database initialization function within models.py which takes the application instance as a parameter. This function only creates the database tables once it has its application instance. This will allow you to import the models module initially without an application instance and still have a modular design.

Related

UserWarning: Neither SQLALCHEMY_DATABASE_URI nor SQLALCHEMY_BINDS is set. Defaulting SQLALCHEMY_DATABASE_URI to "sqlite:///:memory:"

I have been trying to solve an issue related to SQLALCHEMY in Flask as my db is not getting created even though I set the SQLACHEMY_DATABASE_URI to "app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'".
In the warning it says the 'sqlite:///:memory:'. When db.create_all() is call test.sql file is not created and also in the UI I see errors as mentioned bellow:
Instance of 'SQLAlchemy' has no 'Column' memberpylint(no-member) and 3 others
Please help in resolving this issue and generating the db and SQL file.
from flask import Flask, render_template, url_for
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
#Initializing database
app = Flask(__name__)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
db = SQLAlchemy(app)
#Creating model
class Todo(db.Model):
id = db.Column(db.Integer, primary_key=True)
content = db.Column(db.String(200), nullable=False)
completed = db.Column(db.Integer, default=0)
date_created = db.Column(db.DateTime, default=datetime.utcnow)
def __repr__(self):
return '<Task %r>' % self.id
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
if __name__ == "__main__":
app.run(debug=True)

How to start another thread in request handling thread with Flask?

First of all, I have tried looking for answers in this website. But no luck...
What I wanna achieve is that starting an independent thread in the request handling thread to do some asynchronous task. The tricky point is that there are some database operations needed in this independent thread.
Here is an example. Five files included.
project
|__manager.py
|__config.py
|__deployer
|__`__init__.py`
|__models.py
|__views.py
|__operators.py
Detail code below...
# deployer/__init__.py
from flask import Flask
from deployer.models import db
def create_app():
app = Flask(__name__)
app.config.from_object(object_name)
db.init_app(app)
# Add route for index
#app.route('/')
def index():
return {'code': 200, 'message': 'OK'}
return app
# manager.py
from os import environ
from flask_script import Manager, Server
from deployer import create_app
from flask_restful import Api
from deployer.views import HostView
env = environ.get('APM_ENV', 'dev')
app = create_app('config.%sConfig' % env.capitalize())
api = Api(app)
api.add_resource(HostView, '/api/v1/hosts')
manager = Manager(app)
manager.add_command("server", Server(host='0.0.0.0', port=9527))
if __name__ == '__main__':
manager.run(default_command='server')
# deployer/views.py
from flask_restful import Resource, reqparse
from flask import jsonify
from deployer.models import db, Host
from deployer.operators import HostInitiator
parser = reqparse.RequestParser()
parser.add_argument('host', type=int, help='Specify an unique host.')
class HostView(Resource):
def get(self):
h = db.session.query(Host).filter(Host.id == 1).one()
return jsonify(
host_id=h.id,
host_code=h.code,
host_ip=h.ip_addr_v4
)
def post(self):
h = Host(
code='Harbor',
ip_addr_v4='10.10.10.199',
state='created'
)
db.session.add(h)
db.session.commit()
initiator = HostInitiator(host=h)
initiator.start()
return {
'code': 'Harbor',
'ip_addr_v4': '10.10.10.199',
'state': 'created'
}
# deployer/models.py
from sqlalchemy import Column, Integer, String
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Host(db.Model):
__tablename__ = 'br_host'
id = Column(Integer, primary_key=True, autoincrement=True)
code = Column(String(128), index=True, nullable=False)
ip_addr_v4 = Column(String(15), nullable=False)
state = Column(String(16), nullable=False)
# deployer/operators.py
from threading import Thread
from deployer.models import db
class HostInitiator(Thread):
def __init__(self, host):
super().__init__()
self.host = host
def run(self):
# Update Host.state [created-->initating]
db.session.query(Host).filter(Host.id == self.host.id).update({'state': 'initating'})
db.session.commit()
# do some initiating things...
# Update Host.state [initating-->ready]
db.session.query(Host).filter(Host.id == self.host.id).update({'state': 'ready'})
db.session.commit()
Always got outside application context error with code above. The error message indicates that no database operation is permitted in the HostInitiator thread.
It suggests me to push a context or move my code into a view function. I'm suffering this quite a while, please help out if you guys have any suggestions. Thanks in advance.
The code works for me
def test_multi_threading_query():
# module which i create Flask app instance
from app.main import app
# module which i create sqlalchemhy instance
from app.model.db import db, Post
with app.app_context():
posts = Post.query.all()
p = posts[0]
p.foo = 1
db.session.add(p)
db.session.commit()
print(p)
#api.route('/test')
def test_view():
from threading import Thread
t = Thread(target=test_multi_threading_query)
t.start()
return ''
# main.py
app = Flask(__main__)
#db.py
db = SQLAlchemy()
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
foo = db.Column(db.Integer)
https://flask.palletsprojects.com/en/1.1.x/appcontext/

Flask-migrate No changes in schema detected

I am trying to understand how flask and sqlalchemy works.Below is my app structure
init.py contains
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
import User
# Create a login manager object
login_manager = LoginManager()
app = Flask(__name__)
# Often people will also separate these into a separate config.py file
app.config['SECRET_KEY'] = 'mysecretkey'
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'data.sqlite')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
Migrate(app, db)
model.py
from test import db
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
class User(db.Model, UserMixin):
# Create a table in the db
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(64), unique=True, index=True)
def __init__(self, email, username, password,first_name,last_name):
self.email = email
and app.py
# This is app.py, this is the main file called.
from test import app
from flask import render_template
#app.route('/')
def index():
return 'Hello World'
if __name__ == '__main__':
app.run(debug=True)
and I am using below commands to create tables
set FLASK_APP=
flask db init
flask db migrate -m
But flask migrate is not detecting table and displays below message
I am unable to figure how to resolve this issue.Could someone please highlight what I am doing wrong.Thanks
You need to import model in __init__.py
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
import User
# Create a login manager object
login_manager = LoginManager()
app = Flask(__name__)
# Often people will also separate these into a separate config.py file
app.config['SECRET_KEY'] = 'mysecretkey'
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'data.sqlite')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
Migrate(app, db)
from app import model
This is because model.py depends on __init__.py

User login on Flask?

I've been working through chapters 3 and 4 of the Flask mega-tutorial (https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-iv-database). I'm trying to set up user logins on my flask webpage that I have hosted at pythonanywhere. I'm able to register an account successfully (I can see the record added to my database), however, when I try to login, Flask is unable to find the record when searching for the username and it returns None. I'm not sure why this is happening. Complicating things a bit is that I'm using a MySQL database rather than a SQLLite database that the tutorial uses.
config.py:
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config(object):
SECRET_KEY = os.environ.get('SECRET_KEY') or 'something'
SQLALCHEMY_DATABASE_URI = 'mysql+mysqlconnector://username:password#jplank.mysql.pythonanywhere-services.com/jplank$default'
SQLALCHEMY_TRACK_MODIFICATIONS = False
flask_app.py:
from config import Config
from flask_sqlalchemy import SQLAlchemy
from werkzeug.urls import url_parse
from flask import Flask, render_template, flash, redirect, url_for, request
from pandas import DateOffset, DataFrame, date_range, to_datetime
from flask_login import current_user, login_user, logout_user, login_required, LoginManager
import MySQLdb
from flask_bootstrap import Bootstrap
from numpy import nan
from dateutil.relativedelta import relativedelta
import datetime
import math
from yearfrac import CalcYearFrac
import decimal
from sqlalchemy import create_engine
app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)
login = LoginManager(app)
login.login_view = 'login'
Bootstrap(app)
from forms import NameForm, LoginForm, RegistrationForm
import routes, models
#app.route('/table', methods=('GET', 'POST'))
#login_required
def calculatetable():
[...]
models.py:
from flask_app import db, login
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
class User(UserMixin, db.Model):
__tablename__ = "user"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
email = db.Column(db.String(120), index=True, unique=True)
password_hash = db.Column(db.String(128))
def __repr__(self):
return '<User {}>'.format(self.username)
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
#login.user_loader
def load_user(id):
return User.query.get(int(id))
routes.py:
from flask import render_template, flash, redirect, url_for, request
from flask_login import login_user, logout_user, current_user
from werkzeug.urls import url_parse
from flask_app import app, db
from forms import LoginForm, RegistrationForm
from models import User
from config import Config
#app.route('/logout')
def logout():
logout_user()
return redirect(url_for('index'))
#app.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('index'))
form = LoginForm()
if form.validate_on_submit():
user =
User.query.filter_by(username=form.username.data).first()
if user is None:
flash('user is none')
flash(form.username.data)
return redirect(url_for('login'))
elif not user.check_password(form.password.data):
flash('not hash match')
return redirect(url_for('login'))
login_user(user, remember=form.remember_me.data)
next_page = request.args.get('next')
if not next_page or url_parse(next_page).netloc != '':
next_page = url_for('calculatetable')
return redirect(next_page)
return render_template('login.html', title='Sign In', form=form)
#app.route('/register', methods=['GET', 'POST'])
def register():
if current_user.is_authenticated:
return redirect(url_for('index'))
form = RegistrationForm()
if form.validate_on_submit():
user = User(username=form.username.data, email=form.email.data)
user.set_password(form.password.data)
db.session.add(user)
db.session.commit()
flash('Congratulations, you are now a registered user!')
return redirect(url_for('login'))
return render_template('register.html', title='Register', form=form)
I managed to solve this. There was a problem with the way I'd set up my MySQL table and I didn't have certain columns identified as index. Recreating the table solved the issue.

SQLAchemy 'No application found. Either work inside a view function or push'

Ello ello,
I found similar questions on the bug i'm facing, and tried the solutions offered but it didn't work for me.
I'm trying to separate out my models in a different directory and import them into the app.py
When I try to import the db into the python terminal, i'm getting the no application found.
app.py code
from flask import Flask
from flask_restful import Resource, Api
# from flask_sqlalchemy import SQLAlchemy
from routes import test, root, user
from models.todo import db
app = Flask(__name__)
api = Api(app)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://username:pass123#localhost/db'
app.config['SECRET_KEY'] = 'thiskeyissecret'
# db.init_app(app)
with app.app_context():
api = Api(app)
db.init_app(app)
api.add_resource(root.HelloWorld, '/')
api.add_resource(test.Test, '/test')
api.add_resource(user.User, '/user')
if __name__ == '__main__':
app.run(debug=True)
models
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Todo(db.Model):
__tablename__ = 'Todos'
id = db.Column('id', db.Integer, primary_key=True)
data = db.Column('data', db.Unicode)
def __init__(self, id, data):
self.id = id
self.data = data
def __repr__(self):
return '<Todo %>' % self.id
my file directory looks like
Main_app
Models
Todo.py
routes
some routes
app.py
Flask-SQLAlchemy needs an active application context.
Try:
with app.app_context():
print(Todo.query.count())
From the flask documentation:
Purpose of the Context
The Flask application object has attributes, such as config, that are
useful to access within views and CLI commands. However, importing the
app instance within the modules in your project is prone to circular
import issues. When using the app factory pattern or writing reusable
blueprints or extensions there won’t be an app instance to import at
all.
Flask solves this issue with the application context. Rather than
referring to an app directly, you use the the current_app proxy, which
points to the application handling the current activity.
Flask automatically pushes an application context when handling a
request. View functions, error handlers, and other functions that run
during a request will have access to current_app.
It is ok to have db initialised in app.py
from flask import Flask
from flask_restful import Api
from flask_sqlalchemy import SQLAlchemy
from routes import test, root, user
app = Flask(__name__)
api = Api(app)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://username:pass123#localhost/db'
app.config['SECRET_KEY'] = 'thiskeyissecret'
db = SQLAlchemy(app)
api.add_resource(root.HelloWorld, '/')
api.add_resource(test.Test, '/test')
api.add_resource(user.User, '/user')
if __name__ == '__main__':
app.run(debug=True)
Then in your todo.py
from app import db
class Todo(db.Model):
__tablename__ = 'Todos'
id = db.Column('id', db.Integer, primary_key=True)
data = db.Column('data', db.Unicode)
def __init__(self, id, data):
self.id = id
self.data = data
def __repr__(self):
return '<Todo %>' % self.id
I get a same err
that err reason for just can operation db in viewfunc
def __init__(self, id, data):
self.id = id
self.data = data
try move that code operation to your viewfunc
In a nutshell, do something like this:
from yourapp import create_app
app = create_app()
app.app_context().push()

Resources