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
Related
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"
Hi guys i am trying to implement MVC pattern in my flask rest API application but I am facing some issues like flask migration and writing scalable code.
For flask migration I'm not able to detect models while migrating to mysql.
Following is my sample app architecture
This is the models/ini.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
And this is my models/user_master.py
import dataclasses
import flask_bcrypt
from . import db
# from sqlalchemy_utils import PhoneNumber
#dataclasses
class UserTypeMaster(db.Model):
__tablename__ = 'UserTypeMaster'
def __init__(self, _id, _type):
self.id = _id
self.type = _type
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
type = db.Column(db.String(20), unique=True, nullable=False)
This is my centuryApi.py file
from flask import Flask
from flask_migrate import Migrate
from config import config_names
from models import db
from flask_sqlalchemy import SQLAlchemy
from routes.user_route import user_bp
app = Flask(__name__)
app.config.from_object(config_names['default'])
app.config.from_pyfile('config.py')
db.init_app(app)
migrate = Migrate()
migrate.init_app(app, db)
from models.user_master import UserMaster
from models.address_master import CityMaster, StateMaster, CountryMaster
app.register_blueprint(user_bp, url_prefix='/users')
#app.route('/')
def index():
return "Hello"
if __name__ == '__main__':
app.run()
And if I don't include models after initializing migrate object and run flask db migrate I get following:
INFO [alembic.runtime.migration] Context impl MySQLImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.env] No changes in schema detected.
And when including models i get following error:
File "/home/abhishek/FreeLance/Century/centuryApi/centuryApi.py", line 17, in
from models.user_master import UserMaster
File "/home/abhishek/FreeLance/Century/centuryApi/models/user_master.py", line 9, in
class UserTypeMaster(db.Model):
TypeError: 'module' object is not callable
I'm not getting where my reference is wrongly assigned on line 9 in user_master.py
Also i need suggestion regarding this architecture and how can improvise more to make it more scalable.
Any help will be appreciated.
Thanks
I am using flask_sqlalchemy to create a database in file1.py as:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
db.init_app(app)
return app
class DataBase(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100))
time = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
path = db.Column(db.String(200), nullable=False)
status = db.Column(db.String(100), nullable=False, default='Incomplete')
def __repr__(self):
return str(self.id)
I want to use this database in another python file which already hass app = Flask(__name__).
If the second file has an app, you will need to import the db engine from the current file
First of all, try not to use numbers in file names (and generally give better names)
So I recommend you call file1.py something like dal.py (dal for data access layer), and file2.py something like main.py or app.py.
This is how your folder should look like:
src -
| app.py
| dal.py
| __init__.py
Afterward, you have a few options
import the app from app.py
in dal.py you can do the following. This is not the best practice, but it will work
from app import app
...
def init_app():
db.init_app(app)
return app
init the app in app.py, I think this is the better idea.
In app.py, do the following
from flask import Flask
from dal import db
app = Flask(__name__)
db.init(app)
I highly recommend reading the docs and how to handle imports in python, I this this is a nice article
I got the below file structure for a Python-Flask app with flask-migrate :
My issues are
1-I'm unable to use db and create_app inside manage.py
When I do:
$ python manage.py db init
I got below error:
File "/app/main/model/model.py", line 25, in <module>
class User(db.Model):
NameError: name 'db' is not defined
(db is defined in main.init.py )
I have tried different options with no success.
I want to keep the manage.py , model.py and main.init.py in separate files.
2- In model .py I will need db .How will I make db available to model.py ?
Here below is manage.py
# This file take care of the migrations
# in model.py we have our tables
import os
import unittest
from flask_migrate import Migrate, MigrateCommand
from flask_script import Manager
from app.main import create_app
from app.main import db
# # We import the tables into the migrate tool
from app.main.model import model
app = create_app(os.getenv('BOILERPLATE_ENV') or 'dev')
app.app_context().push()
manager = Manager(app)
migrate = Migrate(app, db)
manager.add_command('db', MigrateCommand)
#### If I add model.py here all should be easier , but still I have the
#### issue with
#### from app.main import create_app , db
#manager.command
def run():
app.run()
#manager.command
def test():
"""Runs the unit tests."""
tests = unittest.TestLoader().discover('app/test', pattern='test*.py')
result = unittest.TextTestRunner(verbosity=2).run(tests)
if result.wasSuccessful():
return 0
return 1
if __name__ == '__main__':
manager.run()
This is app.init.py where db and create_app are defined
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_cors import CORS
from .config import config_by_name
from flask_restful import Resource, Api
# from flask_restplus import Resource
from app.main.controller.api_controller import gconnect, \
showLogin, createNewTest, getTest, getTests, getIssue, createNewIssue
db = SQLAlchemy()
flask_bcrypt = Bcrypt()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config_by_name[config_name])
cors = CORS(app,
supports_credentials=True,
resources={r"/api/*":
{"origins":
["http://localhost:3000",
"http://127.0.0.1:3000"]}})
api = Api(app)
db.init_app(app)
flask_bcrypt.init_app(app)
api.add_resource(gconnect, '/api/gconnect')
api.add_resource(showLogin, '/login')
api.add_resource(createNewTest, '/api/test')
api.add_resource(getTest, '/api/test/<int:test_id>')
api.add_resource(getTests, '/api/tests')
api.add_resource(getIssue, '/api/issue/<int:issue_id>')
api.add_resource(createNewIssue, '/api/issue')
return app
And this is (just one of the table for simplicity) of my model
from sqlalchemy import Column, ForeignKey, Integer, String, DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, backref
from sqlalchemy import create_engine
from sqlalchemy.sql import func
# # # This will let sql alchemy know that these clasess
# # # are special Alchemy classes
# Base = declarative_base()
class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(250), nullable=False)
email = db.Column(db.String(250), nullable=False)
pictures = db.Column(db.String(250))
role = db.Column(db.String(25), nullable=True)
My issues are:
1-I'm unable to use db and create_app inside manage.py
When I do:
$ python manage.py db init
I got below error:
File "/app/main/model/model.py", line 25, in
class User(db.Model):
NameError: name 'db' is not defined
(db is defined in main.init.py )
I have tried different options with no success.
I want to keep the manage.py , model.py and main.init.py in separate files.
2- In model .py I will need db .How will I make db available to model.py ?
A simple solution is to create a seperate initializtions file besides your __init__.py. e.g. init.py where you initialize sqlalchemy along with other extensions. That way they can be imported in all the modules without any circular dependencies problems.
A more elegant solution however is to you use Flask's current_app and g proxies. They were made to help Flask users circumvent any problems with circular dependencies.
Typically you initalize the flask app in the __init__.py module and the __init__.py module sometimes has to import some variables from its sub-modules. This becomes problematic when sub-modules try to import initalized extensions
As a general rule of thumb, outer modules should be importing from their submodules not the other way around.
So here's one way you can solve your problem (cited from here):
** __init__.py
from flask import g
def get_db():
if 'db' not in g:
g.db = connect_to_database()
return g.db
#app.teardown_appcontext
def teardown_db():
db = g.pop('db', None)
if db is not None:
db.close()
def init_db():
db = get_db()
Now you can easily import your db connection into any other module by:
from flask import g
db = g.db
db.do_something()
I am reading a book about flask development, and I'm pretty new to python generally.
File layout:
Project
|
|-- App
| |-- __init__.py
| |-- models.py
|
| main.py
Code inside __init__.py:
from flask import Flask
from flask.ext.bootstrap import Bootstrap
from flask.ext.sqlalchemy import SQLAlchemy
import os
from config import options
basedir = os.path.abspath(os.path.dirname(__file__))
bootstrap = Bootstrap()
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] =\
'sqlite:///' + os.path.join(basedir, 'database_test.sqlite')
bootstrap.init_app(app)
db.init_app(app)
with app.app_context():
db.create_all()
print("DB created")
return(app)
I have been researching other people's issues on the site, mostly here where I found to use the with app.app_context(), and to instantiate the db without using app as part of the constructor.
Here is my models.py file:
from . import db
class User(db.Model):
__tablename__ = 'Users'
account_id = db.Column(db.Integer, primary_key=True)
personaname = db.Column(db.String(50), unique=False)
steamid = db.Column(db.String(64))
avatar = db.Column(db.String(200))
profileurl = db.Column(db.String(128))
is_personaname_real = db.Column(db.Integer)
def __repr__(self):
return '<User {0}>'.format(self.personaname)
I then rune the code from main.py which is just:
from app import create_app
app = create_app()
If I move the User class into the __init__.py function, everything is created fine. However, when the User class is inside it's own file, the database is created empty. I have tried using other ways of importing, maybe something like From app.__init__.py Import db, but that didn't work either.
Since defining your model directly in __init__.py works, it follows that you need to import your model(s) into __init__.py.
You can add an import in __init__.py after you create an SQLAlchemy object:
db = SQLAlchemy()
from .models import User
This works, but it feels horribly wrong and dirty to me. I don't know Flask that well, but this answer suggests that this is normal for Flask: https://stackoverflow.com/a/19008403/21945
This should work, seem you are missing the if statement
from app import create_app
app = create_app()
if __name__ == "__main__":
app.run()