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()
Related
I am using SQLalchemy to create my db in flask. For this I create a project.db file and run the following code :
from flask import Flask
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:///project.db"
# initialize the app with the extension
db.init_app(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String, unique=True, nullable=False)
email = db.Column(db.String)
with app.app_context():
db.create_all()
When I run create_table, it creates me a new folder named instance and a new project.db file in it. The result is that my first project.db does not work and is useless.
What must I do then ? Because when looking at different topic and videos this never happens. Thanks in advance !
Where is project.db located? Keep it in the same folder as the script, or try using an absolute path like this?
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:////absolute/path/to/project.db"
I am trying to build an API using Flask. For database actions I use flask_sqlalchemy.
In my main file, the flask app is initalized. I pass the resulting instance to another file where the configuration is set and to my database module that handles database operations.
main.py:
app = flask.Flask(__name__) # initialize flask app
#initialize modules with app
config.init(app)
database.init(app)
The problem is, the relations I use in the database are in a seperate file and it needs the db object to declare the classes for ORM.
My idea was to declare db and initialize it later in an init function, but that doesn't work in this case, because the db object is undefined when the pythonfile is loaded by an import.
relations.py
db: SQLAlchemy
def init(db):
Relations.db = db
class Series(db.Model):
"""Representation of a series
"""
id = db.Column(db.String(255), primary_key=True)
title = db.Column(db.String(255))
class User(db.Model):
"""Representation of a user
"""
id = db.Column(db.INT, primary_key=True)
name = db.Column(db.String(255))
class Subscription(db.Model):
"""Representation of a subscription
"""
series_id = db.Column(db.INT, primary_key=True)
user_id = db.Column(db.String(255), primary_key=True)
My database module uses the way and it works fine(init.py file):
db: SQLAlchemy
def init(app):
database.db = SQLAlchemy(app)
# handle database operations...
One approach to solve the issue is just using another instance in the relations.py like that:
app = flask.Flask(__name__)
db = SQLAlchemy(app)
# declare classes...
I tried it out and it workes, but that is not a nice way to solve this and leads to other problems.
Importing it from main does also not work because of circular import.
I have no idea how to smoothly solve this without removing modularization. I would be thankful for any inputs. If I should add any further information, just let me know.
I would create the app variable in your main.py file but leave out the initializing part. From there you call a function from init.py to basically set up the database. That is what I did for my last flask project.
Main.py:
from init import create_app
app = create_app()
if __name__ == '__main__':
app.run(debug=True)
Init.py:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
DB_NAME = "database.db"
def create_app():
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{DB_NAME}'
db.init_app(app)
create_database(app)
#Other operations ...
return app
Relations.py
from init import db
#all your classes ...
db.create_all()
So now you can import the db object to your relations.py file from the init.py.
I am working on a Udemy course using flask to record heights. I am at the point where we are using PostgreSQL, and I have it installed, and I have his code copied exactly:
from flask import Flask, render_template, request
from flask.ext.sqlalchemy import SQLAlchemy
app=Flask(__name__)
app.config(['SQLALCHEMY_DATABASE_URI']='postgresql://postgres:password
#localhost/height_collector')
db=SQLAlchemy(app)
class Data(db.Model):
__tablename__='data'
id=db.Column(db.Integer, primary_key=True)
email_=db.Column(db.String(120), unique=True)
height_=db.Column(db.Integer)
def __init__(self, email_, height_):
self.email_=email_
self.height_=height_
#app.route("/")
def index():
return render_template("index.html")
#app.route("/success", methods=["post"])
def success():
if request.method=='POST':
email=request.form['email_name']
height=request.form['height_name']
print(height,email)
return render_template("success.html")
if __name__=='__main__':
app.debug=True
app.run()
Problem comes into play, when he says to run python in a virtual env, and then enter :db.create_all() to create a database in PostgreSQL and I get this error :
File <'stdin'>, line 1 in
NameError: Name 'db' is not defined
Not sure how to proceed, any input would be appreciated.
you can make a db.py where you can store the code db = SQLAlchemy(). Then import in in app.py. now you can able to call db. or just remove APP in db=SQLAlchemy(app)
I think you probably need to run some of the other code first so that you define db and your table schema. Then you can run db.create_all().
from flask import Flask, render_template, request
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config(['SQLALCHEMY_DATABASE_URI'] =
'postgresql://postgres:password#localhost/height_collector')
db = SQLAlchemy(app)
class Data(db.Model):
__tablename__ = 'data'
id = db.Column(db.Integer, primary_key=True)
email_ = db.Column(db.String(120), unique=True)
height_ = db.Column(db.Integer)
def __init__(self, email_, height_):
self.email_ = email_
self.height_ = height_
db.create_all()
I just faced this error and it is because I didn't import db before calling the db function. If you're running in terminal, 'from yourappname import db' and any other functions you are running.
//IN TERMINAL
from yourappname import db
Start python shell by running the command python. Then import db to define it:
from main import db
db.drop_all()
db.create_all()
You need to set the FLASK env variable.
create a .flaskenv file in the top directory of your project
Add this to your .flaskenv file:
export FLASK_APP=myappfile.py
Install dotenv to your environment
pip install python-dotenv
Now if you run the app it should pick up your env variable.
Type the Following and it will work:
cd flask-app
venv\scripts\activate
python3
from app import db
db.create_all()
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/
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.