I am trying to define and create my models with flask_sqlalchemy.
If I do it all in one script, it works:
all_in_one.py
from config import DevConfig
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config.from_object(DevConfig)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = app.config.get("DB_URI")
db = SQLAlchemy(app)
class Members(db.Model):
id = db.Column(db.String, primary_key=True, nullable=False)
def main():
db.drop_all()
db.create_all()
if __name__ == "__main__":
main()
The Members table is created.
If I split this process into files, I can't seem to get the db object to register my Members model and do anything.
root
│-- config.py
│-- create.py
│-- database.py
│-- members.py
database.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
members.py
from database import db
class Members(db.Model):
id = db.Column(db.String, primary_key=True, nullable=False)
create.py
from database import db
from config import DevConfig
from flask import Flask
app = Flask(__name__)
app.config.from_object(DevConfig)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = app.config.get("DB_URI")
def main():
db.init_app(app)
with app.app_context():
db.drop_all()
db.create_all()
if __name__ == "__main__":
main()
The Members table does not get created.
add import members below db.init_app(app)
from database import db
from config import DevConfig
from flask import Flask
app = Flask(__name__)
app.config.from_object(DevConfig)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = app.config.get("DB_URI")
def main():
db.init_app(app)
import members
with app.app_context():
db.drop_all()
db.create_all()
if __name__ == "__main__":
main()
Related
I have a flask app with SQLAlchemy trying to connect to sqlite app.db file.
When I run the app (python run.py) it says:
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) unable to open database file
Relevant project structure:
/app
__init__.py
models.py
/db
app.db
run.py
config.py
My run.py file as follows:
from app import create_app
app = create_app()
app.run()
This imports and runs a create_app function from init.py file:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from .home.routes import home_bp
from .students.routes import students_bp
from .datasets.routes import datasets_bp
from .reports.routes import reports_bp
def create_app():
"""Create Flask application."""
app = Flask(__name__)
app.config.from_object('config')
# Initialise extensions
db = SQLAlchemy(app)
db.create_all()
with app.app_context():
# Import parts of our application
from .home import routes
from .students import routes
from .datasets import routes
from .reports import routes
# Register Blueprints
app.register_blueprint(home_bp)
app.register_blueprint(students_bp)
app.register_blueprint(datasets_bp)
app.register_blueprint(reports_bp)
return app
Database config is loaded from config.py:
from dotenv import load_dotenv
load_dotenv()
# DB Config
DB_FILE = 'db/app.db'
SQLALCHEMY_DATABASE_URI = 'sqlite:///db/app.db'
SQLALCHEMY_TRACK_MODIFICATIONS = False
The models.py file:
import db
class Student(db.Model):
id = db.Column(db.Integer, primary_key=True)
usi = db.Column(db.String(64), index=True)
first_name = db.Column(db.String(256))
last_name = db.Column(db.String(256))
dob = db.Column(db.String(64))
active = db.Column(db.Boolean)
def to_dict(self):
return {
'usi': self.usi,
'first_name': self.first_name,
'last_name': self.last_name,
'dob': self.dob,
'active': self.active
}
I've been building a Flask app with the help of this video:
https://www.youtube.com/watch?v=dam0GPOAvVI&t=3256s
Here is the file of my init so far :
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from os import path
DB_NAME = "database.db"
db = SQLAlchemy()
app = Flask(__name__)
app.config['SECRET_KEY'] = 'bindthemostselling'
app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{DB_NAME}'
db.init_app(app)
from views import views
from auth import auth
app.register_blueprint(views, url_prefix='/')
app.register_blueprint(auth, url_prefix='/')
if __name__ == '__main__':
app.run(debug=True)
and here is the file of my models so far its just one class:
from flask_login import UserMixin
from . import db
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(150), unique=True)
password = db.Column(db.String(150))
first_name = db.Column(db.String(150))
My problem is that the db.Column inside the User class is unrecognizable. I've tried to reinstall sqlalchemy and flask and i've looked at everything he did again and even copied the code from his github and it still wont recognize that function or even other functions that I have noticed so far from the video. This is the first time I try to make an actual python app so maybe there is something i'm missing in the syntax?
Thanks in advance.
EDIT:
So i have updated the init file to include everything so i can run and see what error i get here is what I have now:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from os import path
from models import User
from flask_login import LoginManager
DB_NAME = "database.db"
db = SQLAlchemy()
app = Flask(__name__)
app.config['SECRET_KEY'] = 'bindthemostselling'
app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{DB_NAME}'
db.init_app(app)
from views import views
from auth import auth
app.register_blueprint(views, url_prefix='/')
app.register_blueprint(auth, url_prefix='/')
login_manager = LoginManager()
login_manager.login_view = 'auth.login'
login_manager.init_app(app)
#login_manager.user_loader
def load_user(id):
return User.query.get(int(id))
def create_database(app):
if not path.exists('.' + DB_NAME):
db.create_all(app=app)
print('Created Database!')
create_database(app)
if __name__ == '__main__':
app.run(debug=True)
Here is the traceback that I got (Sorry if the formatting is bad):
Traceback (most recent call last):
File "c:\Users\Ashraf\FlaskToDo_init_.py", line 4, in
from models import User
File "c:\Users\Ashraf\FlaskToDo\models.py", line 2, in
from . import db
ImportError: attempted relative import with no known parent package
so apparently the db is not imported correctly? This can't be true cause when I created the User class and passed the db.Model, it recognized it. What am I exactly missing here?
Try changing the import statement in the models file from
from . import db
to:
from init import db
This way you should get a circular import error, so move from models import User in your init after db is defined.
This is the complete setup:
init:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from os import path
from flask_login import LoginManager
DB_NAME = "database.db"
db = SQLAlchemy()
app = Flask(__name__)
app.config['SECRET_KEY'] = 'bindthemostselling'
app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{DB_NAME}'
db.init_app(app)
login_manager = LoginManager()
login_manager.login_view = 'auth.login'
login_manager.init_app(app)
#login_manager.user_loader
def load_user(id):
return User.query.get(int(id))
def create_database(app):
if not path.exists('.' + DB_NAME):
db.create_all(app=app)
print('Created Database!')
create_database(app)
if __name__ == '__main__':
app.run(debug=True)
from models import User
models:
from flask_login import UserMixin
from init import db
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(150), unique=True)
password = db.Column(db.String(150))
first_name = db.Column(db.String(150))
EDIT:
add a route to actually navigate in your app:
#app.route("/")
def home():
return "Hello World"
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
Checking Flask and Flask-SQLAlchemy doc i have a confusion, if i have:
models.py:
from flask_sqlalchemy import SQLAlchemy
#:Use or not
db = SQLAlchemy()
class User(db.Model):
__tablename__ = "USERS"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(25), nullable=False)
password = db.Column(db.String(255), nullable=False)
config.py:
import os
class Config(object):
DEBUG = True
SECRET_KEY = os.urandom(12)
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_DATABASE_URI = "mysql://root:#localhost/example"
app.py:
from config import Config
from models import db
from models import User
app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)
if __name__ == "__main__":
db.init_app(app)
with app.app_context():
db.create_all()
app.run()
is necessary use:
db = SQLAlchemy(app) after app.config.from_object(Config)
or db.init_app(app) is the same?
Because i founded some examples of flask with only db = SQLAlchemy() in models.py and have db.init_app(app) before app.run()
And so founded examples with db = SQLAlchemy(app) override in app.py with no db.init_app(app)
I printed both values and get:
with only db in models:
<SQLAlchemy engine=None>
the problem is:
The app create the tables in my database
But engine=None
with db = SQLAlchemy(app) override
<SQLAlchemy engine=mysql://root:***#localhost/hsl_db?charset=utf8>
the problem is:
The app dont create the tables in my database
What is the correct way to assign the database of SQLAlchemy to Flask app?
From: https://flask-sqlalchemy.palletsprojects.com/en/2.x/api/
There are two usage modes which work very similarly. One is binding the instance to a very specific Flask application:
app = Flask(__name__)
db = SQLAlchemy(app)
The second possibility is to create the object once and configure the application later to support it:
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
db.init_app(app)
return app
The difference between the two is that in the first case methods like create_all() and drop_all() will work all the time but in the second case a flask.Flask.app_context() has to exist.
There is no correct way as it all depends on how you want to instantiate your db using SQLAlchemy and app using Flask.
But I'll go over how I use the app.
def create_app():
app = Flask(__name__, static_folder='static', instance_relative_config=True)
app.config.from_pyfile('app_config.py')
return app
app = create_app()
db = SQLAlchemy(app)
The Flask documentation recommends:
db.init_app(app)
Flask Factories & Extensions
I'm trying to split out my models into a separate file as it's getting too large to manage. I've followed this but I am getting a NameError despite having run db.create_all():
NameError: name 'importsTable' is not defined
# stack_app.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from stack_dbmodels import db
from stack_dbmodels import importsTable
from datetime import datetime
app = Flask(__name__)
app.secret_key = 'secretsquirrel'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///stack_newAppCsv.db'
db.init_app(app)
#app.route('/', methods=['GET'])
def stack():
username = "username"
new_user = importsTable(username)
db.session.add(new_user)
db.session.commit()
return "Done!"
if __name__ == "__main__":
app.run(debug = True, port=8080)
My models file:
# stack_dbmodels.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class importsTable(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80))
def __init__(self, username):
self.username = username
def __repr__(self):
return '<Import {0}>'.format(self.username)
The problem was mainly with the context of the app but during my tests there were a couple of gotchas I found. Key to make the above work was:
When I reference importsTable it wasn't initially defined unless I did:
from stack_dbmodels import db
from stack_dbmodels import importsTable
And whilst the .db file was created, the context wasn't correct so it couldn't create the actual importsTable so I added the following and problem solved, the key bit was "with app.app_context()":
db.init_app(app)
with app.app_context():
db.create_all()
Final working code was:
# stack_app.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from stack_dbmodels import db
from stack_dbmodels import importsTable
from datetime import datetime
app = Flask(__name__)
app.secret_key = 'secretsquirrel'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///stack_newAppCsv.db'
db.init_app(app)
with app.app_context():
db.create_all()
#app.route('/', methods=['GET'])
def stack():
username = "username"
new_user = importsTable(username)
db.session.add(new_user)
db.session.commit()
return "Done!"
if __name__ == "__main__":
app.run(debug = True, port=8080)