I am using flask with SQLAlchemy, after set all configuration setting I got db import error on model.
ImportError: cannot import name 'db'
my main app __init__
from flask_api import FlaskAPI
from flask_sqlalchemy import SQLAlchemy
import os
import json
from flask import Flask
from flask_pymongo import PyMongo
from flask import request
from app.test.controllers import test
def create_app(config_name):
app = FlaskAPI(__name__)
CORS(app)
app.config.from_object(os.environ['APP_SETTINGS'])
db = SQLAlchemy(app)
from app.test.controllers import test
app.register_blueprint(test)
my controller and model in app/test/test.py and model.py
test.py
from flask import Blueprint, request, redirect, url_for
import json
from flask_sqlalchemy import SQLAlchemy
from app.test.model import TestModel
test = Blueprint('test', __name__, url_prefix='/api/v1')
#test.route('/test/store', methods=['POST'])
def store():
return json.dumps({'success':True}), 200, {'ContentType':'application/json'}
my model.py
from app import db
class TestModel(db.Model):
__tablename__ = 'user_profiles'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), unique=False)
email= db.Column(db.String(255), unique=False)
def __init__(self, name=None, email=None):
self.name = name
self.email = email
def __repr__(self):
return '<User %r>' % (self.name, self.email)
You are using the Flask factory method so initialize SqlAlchemy in your model and import it to your __init__.py file
So model.py becomes
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class TestModel(db.Model):
__tablename__ = 'user_profiles'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), unique=False)
email= db.Column(db.String(255), unique=False)
def __init__(self, name=None, email=None):
self.name = name
self.email = email
def __repr__(self):
return '<User %r>' % (self.name, self.email)
Then in __init__.py it becomes
from flask_api import FlaskAPI
from model import db
import os
import json
from flask import Flask
from flask_pymongo import PyMongo
from flask import request
from app.test.controllers import test
def create_app(config_name):
app = FlaskAPI(__name__)
CORS(app)
app.config.from_object(os.environ['APP_SETTINGS'])
db.init_app(app)
from app.test.controllers import test
app.register_blueprint(test)
Related
I'm setting up a new Flask app, where I want to have all of my SQLAlchemy models in separate files. The overall structure should end up looking like this:
flask-app
|
|--api
| |--user.py
| |--example.py
|
|--controllers
| |--user.py
| |--example.py
|
|--models
| |--user.py
| |--example.py
|
|-main.py
|-modelref.py
|-config.py
In terms of code here's what i have so far:
main.py:
import os
from flask import Flask, send_from_directory
from flask_bcrypt import Bcrypt
from flask_cors import CORS
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
import modelref
from apiref import load_api
app = Flask(__name__, static_url_path='', static_folder='./../react/public')
app.config.from_object(os.getenv("APP_SETTINGS", "config.Development"))
CORS(app)
db = SQLAlchemy(app)
migrate = Migrate(app, db)
bcrypt = Bcrypt(app)
#app.route("/", defaults={'path':''})
def serve(path):
return send_from_directory(app.static_folder,'index.html')
load_api(app)
The modelref import is a shorthand of sorts. In the modelref.py file I import every model that I have in the models folder like so:
modelref.py:
from models.user import User
from models.example import Example
Then the model itself is something along the lines of:
models/user.py:
class User(db.Model):
__tablename__ = "user"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(64), unique=True, nullable=False)
email = db.Column(db.String(255), unique=True, nullable=False)
password = db.Column(db.String(255), nullable=False)
first_name = db.Column(db.String(128), nullable=False)
last_name = db.Column(db.String(128), nullable=False)
registered_on = db.Column(db.DateTime, nullable=False)
def __init__(self, username, email, password, first_name, last_name):
self.username = username
self.email = email
self.password = bcrypt.generate_password_hash(password, flask.current_app.config.get('BCRYPT_LOG_ROUNDS')).decode()
self.first_name = first_name
self.last_name = last_name
self.registered_on = datetime.datetime.now()
def save(self):
db.session.add(self)
db.session.commit()
The model gets manipulated in a controller class defined here:
controllers/user.py:
class UserController:
#staticmethod
def register(username: str, password: str, email: str, first_name: str, last_name: str) -> dict:
result: dict = {}
try:
user = User(
username=username,
password=password,
email=email,
first_name=first_name,
last_name=last_name
)
user.save()
except IntegrityError:
User.rollback()
raise ResourceExists("user already exists")
return login(user.username, user.password);
#staticmethod
def login(username: str, password: str):
user = User.query.filter_by(username).first()
if user:
if bcrypt.check_password_hash(user.password, password):
token = user.encode_auth_token(user.id)
return {
"username": user.username,
"first_name": user.first_name,
"last_name": user.last_name,
"token": token
}
else:
abort(400, "Invalid Password")
else:
abort(404, "User Not Found")
The controller is accessed in an API resource defined using pluggable views. The views and routes are registered with the app in the load_app(app) method. I'm not sharing that whole pipeline, because I believe it is out of scope, but if anyone believes it's not, than I will add it into the post.
So now here's the problem. If I try to access the model in the code or run flask db migrate, I get an error that db is not defined.
A solution I've seen is to add a db=SQLAlchemy line in the model, but then the flask db migrate doesn't find this model, likely because the mentioned line creates a new SQLAlchemy instance, so it's essentially unaware of the models existence.
With this setup I'm unable to import the db object from main since that causes a circular import due to the model being imported in the controller.
Is there a way I can pass a reference to db to the model without an import, or make the model search for the "current" instance of 'db'. Or is there any way to reorganize the main code so that I can maintain the general structure, but be able to run migrations?
It turns out that in a case such as mine, the best option is to apply the application factory pattern. I now have an app.py module, where I initialize all the modules I need in a create_app method like so:
app.py:
import os
from flask import Flask
from flask_bcrypt import Bcrypt
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
db = SQLAlchemy()
migrate = Migrate()
bcrypt = Bcrypt()
def create_app():
app = Flask(__name__, static_url_path='', static_folder='./../react/public')
app.config.from_object(os.getenv("APP_SETTINGS", "config.Development"))
import modelref
db.init_app(app)
migrate.init_app(app, db)
bcrypt.init_app(app)
return app
And them my main.py file simply invokes the create_app method and then sets up routes and API resources like so:
main.py:
from flask import send_from_directory
from flask_cors import CORS
from apiref import load_api
from app import create_app
app = create_app()
CORS(app)
#app.route("/", defaults={'path':''})
def serve(path):
return send_from_directory(app.static_folder,'index.html')
load_api(app)
Running import modelref within the create_model method makes all the models imported in modelref visible to the app and the flask db commands.
I have created a flask app with Flask-Sql-Alchemy, however flask in't recognising the database table User_Plans I created and trying to query.
It gives the following error:
NameError: name 'User_Plans' is not defined.
I could be wrong, but it feels like the error is a scoping issue.
I have included my code below.
Can you help? Many thanks in advance.
database.py
from flask_sqlalchemy import SQLAlchemy
from flask_user import UserManager, UserMixin, SQLAlchemyAdapter
from datetime import datetime
def create_db(app):
db = SQLAlchemy(app)
class User(db.Model, UserMixin):
id=db.Column(db.Integer,primary_key=True)
username = db.Column(db.String(50),nullable=False,unique=True)
password = db.Column(db.String(255),nullable=False, server_default='')
active=db.Column(db.Boolean(),nullable=False,server_default='0')
email = db.Column(db.String(255),nullable=False,unique=True)
confirmed_at = db.Column(db.DateTime())
plan_id=db.Column(db.Integer, db.ForeignKey('plans.id'),default=1)
db_adapter = SQLAlchemyAdapter(db,User)
user_manager = UserManager(db_adapter,app)
class User_Plans(db.Model):
id=db.Column(db.Integer,primary_key=True)
user_id=db.Column(db.Integer, db.ForeignKey('user.id'))
plan_id=db.Column(db.Integer, db.ForeignKey('plans.id'))
start_date = db.Column(db.DateTime())
class User_APIs(db.Model):
id=db.Column(db.Integer,primary_key=True)
user_id=db.Column(db.Integer, db.ForeignKey('user.id'))
api_id=db.Column(db.Integer, db.ForeignKey('tools.id'))
api_key=db.Column(db.String(50),nullable=False,unique=True)
class Tools(db.Model):
id=db.Column(db.Integer,primary_key=True)
tool=db.Column(db.String(50),nullable=False,unique=True)
class Plans(db.Model):
id=db.Column(db.Integer,primary_key=True)
plan=db.Column(db.String(50),nullable=False,unique=True)
price=db.Column(db.Float(5),nullable=False)
credit=db.Column(db.Integer,nullable=False)
class Usage(db.Model):
id=db.Column(db.Integer,primary_key=True)
user_id=db.Column(db.Integer, db.ForeignKey('user.id'))
task_id=db.Column(db.Integer, db.ForeignKey('tasks.id'))
datetime=db.Column(db.DateTime())
class Tasks(db.Model):
id=db.Column(db.Integer,primary_key=True)
task=db.Column(db.String(50),nullable=False,unique=True)
credit=db.Column(db.Integer,nullable=False)
class Status(db.Model):
id=db.Column(db.Integer,primary_key=True)
status=db.Column(db.String(20),nullable=False,unique=True)
__init__.py
from flask import Flask
from flask import render_template
from flask_mail import Mail
from config import config
from database import create_db
from flask_user import login_required, current_user
from dateutil.relativedelta import relativedelta
from datetime import datetime
def create_app(config_name):
print(config_name)
app = Flask(__name__)
app.config.from_object(config[config_name])
create_db(app)
mail = Mail(app)
#app.route('/')
#login_required
def index():
user_id = current_user.id
start_date=User_Plans.query.with_entities(User_Plans.start_date).filter(User_Plans.user_id==user_id).first()
return '<h1>Hello {}, you started your plan on {}</h1>'.format(current_user.username,start_date.strftime('%d-%m-%Y'))
manage.py
from app import create_app
app = create_app('development')
if __name__== '__main__':
app.run()
It isn't talking about your table, it's talking about the name User_Plans, which is indeed not defined in your main code. You need to import it - and any other models you use - into that file.
from models import User_Plans
I'm having trouble creating a modular application using Flask using blueprints. I'm not sure how to migrate models defined in blueprints.
My app looks as follows:
- app
- __init__.py
- user
__init__.py
models.py
app.__init__.py looks as follows:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from config import Config
from flask_migrate import Migrate
from app.auth import bp as user_bp
db = SQLAlchemy()
app = Flask(__name__)
app.config.from_object(Config)
app.register_blueprint(user_bp, url_prefix='/user')
migrate = Migrate(app, db)
from app.auth.models import User
user/.__init__.py:
from flask import Blueprint
bp = Blueprint('user', __name__)
user/models.py:
from app import db
class User(db.Model):
user_id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.String(128))
last_name = db.Column(db.String(128))
user_name = db.Column(db.String(120))
password_hash = db.Column(db.String(220))
def __repr__(self):
return '<User {}>'.format(self.email)
When trying to run flask db migrate... no models are being detected and I think I have some sort of circular dependency.
Can someone please explain how to do this properly?
The User model (user/models.py) should be imported somewhere in the application, try to import into the blueprint file (user/__init__.py)
from flask import Blueprint
from app.user.models import User
bp = Blueprint('user', __name__)
app.py
from flask import Flask
from flask_restful import Resource, Api
from user import user_blueprint
from flask_cors import CORS
app = Flask(__name__)
api = Api(app)
app.register_blueprint(user_blueprint)
cors = CORS(app, resources={r"/*": {"origins": "*"}})
if __name__ == '__main__':
app.run(debug=True)
model/user.py
from sqlalchemy import Column, INTEGER, String
class User(Base):
__tablename__ = 'USER'
__table_args__ = {'schema': 'MAPPING'}
ID = Column(INTEGER(11), primary_key=True)
FIRST_NAME = Column(String(255), nullable=False, server_default=text("''"))
LAST_NAME = Column(String(255), nullable=False, server_default=text("''"))
EMAIL = Column(String(255), nullable=False, server_default=text("''"))
route/user_route
from flask import Blueprint, jsonify, request
from flask_restful import Resource, Api
user_blueprint = Blueprint('app/', __name__)
user_api = Api(user_blueprint, prefix='/')
class User(Resource):
def get(self):
db_conn = //db connection Object
results = // your query
db_conn.close()
return jsonify(results)
user_api.add_resource(User, '/user')
I am following this tutorial: getting started with flask-login.
However I am stuck at step 5 where I start to use SQLAlchemy. I believe the problem might be circular importing, based on what I have read but I'm still a little new to Python coding. This web app is a little project I am doing in my free time.
So I guess my overall question is, is this circular importing, and if not does anyone see what I might be doing wrong here? I am also running this using virtualenv using Python 2.7.
File Structure:
-noteapp
-noteapp
-db
-forms
-static
-templates
-views
__init__.py
app.py
models.py
This is my app.py file
from flask import Flask
from flask_login import LoginManager
from noteapp.models import db
from noteapp.views.index import bp as index_bp
from noteapp.views.createnote import bp as createnote_bp
from noteapp.views.signup import bp as signup_bp
def init_db():
db.init_app(app)
db.app = app
db.create_all()
app = Flask(__name__)
app.secret_key = 'removed for reasons'
app.config['SQLALCHEMY_DATABASE_URI'] = 'removed for reasons'
db = SQLAlchemy(app)
login_manager = LoginManager(app)
login_manager.init_app(app)
app.register_blueprint(index_bp)
app.register_blueprint(createnote_bp)
app.register_blueprint(signup_bp)
if __name__ == '__main__':
app.init_db()
app.run(debug=True)
This is my models.py file:
from noteapp.app import app
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app)
class User(db.Model):
email = db.Column(db.String(80), primary_key=True, unique=True)
password = db.Column(db.String(80))
def __init__(self, email, password):
self.email = email
self.password = password
def __repr__(self):
return '<User %r>' % self.email
You are correct you have a circle import issue.
At app.py you import from noteapp.models import db,
and at models.py you import from noteapp.app import app
A quick fix could be:
at models.py use db = SQLAlchemy() without the app.
At the app.py module, import db from models.py and do db.init_app(app)
also remove db = SQLAlchemy(app) from your app.py
your app.py should look like this..
from noteapp.models import db
...
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'removed for reasons'
...
def init_db():
db.init_app(app)
db.app = app
db.create_all()
...
if __name__ == '__main__':
app.init_db()
app.run(debug=True)
models.py should look like this:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class User(db.Model):
email = db.Column(db.String(80), primary_key=True, unique=True)
password = db.Column(db.String(80))
def __init__(self, email, password):
self.email = email
self.password = password
def __repr__(self):
return '<User %r>' % self.email
This question already has an answer here:
Tyring to set up modelview with Flask-Admin causes ImportError
(1 answer)
Closed 5 years ago.
I have a flask app which I am trying to run. It seems when I run python app.py, there is a circular import of some sort. Here is the code for both my models.py and app.py:
models.py
import datetime
from app import bcrypt, db
class User(BaseModel, db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
email = db.Column(db.String(255), unique=True, nullable=False)
password = db.Column(db.String(255), nullable=False)
registered_on = db.Column(db.DateTime, nullable=False)
admin = db.Column(db.Boolean, nullable=False, default=False)
def __init__(self, email, password, admin=False):
self.email = email
self.password = bcrypt.generate_password_hash(password)
self.registered_on = datetime.datetime.now()
self.admin = admin
app.py
from flask import Flask, render_template
from flask import request, jsonify, session
from flask.ext.bcrypt import Bcrypt
from flask_sqlalchemy import SQLAlchemy
from models import User
app = Flask(__name__)
db = SQLAlchemy()
POSTGRES = {
'user': 'postgres',
'db': 'postgres',
'host': 'localhost',
'port': '5432',
}
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://%(user)s#%(host)s:%(port)s/%(db)s' % POSTGRES
app.config['SECRET_KEY'] = 'lol'
bcrypt = Bcrypt(app)
db.init_app(app)
#app.route('/api/register', methods=['POST'])
def register():
json_data = request.json
user = User(
email=json_data['email'],
password=json_data['password']
)
try:
db.session.add(user)
db.session.commit()
status = 'success'
except:
status = 'this user is already registered'
db.session.close()
return jsonify({'result': status})
manage.py
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
from app import app, db
from models import User
migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)
#manager.command
def create_admin():
"""Creates the admin user."""
db.session.add(User(email='admin#admin.com', password='admin', admin=True))
db.session.commit()
if __name__ == '__main__':
manager.run()
I have played around with the imports but nothing seems to work, I usually will get a circular import error like this:
Traceback (most recent call last):
File "app.py", line 7, in <module>
from models import User
File "/Users/Rishub/Desktop/apps/topten/models.py", line 3, in <module>
from app import bcrypt, db
File "/Users/Rishub/Desktop/apps/topten/app.py", line 7, in <module>
from models import User
ImportError: cannot import name User
Does anyone know the solution to this?
In addition, if I run python manage.py runserver, my app runs fine so I am curious as to why this works but python app.py does not.
in models.py you are importing:
from app import bcrypt, db
in app.py you are importing models.
from models import User
To fix it restructure the program as shown here: http://flask.pocoo.org/docs/0.12/patterns/sqlalchemy/
create a database.py file with database configs etc.
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine('sqlite:////tmp/test.db', convert_unicode=True)
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()
def init_db():
import models
Base.metadata.create_all(bind=engine)
use this in models.py as
from database import Base
from sqlalchemy import Column, Integer, String
# instead of db.column directly use Column
class User(Base):
and app files as:
from database import init_db
init_db()
from database import db_session
from models import User
#app.route('/api/register', methods=['POST'])
def register():
json_data = request.json
user = User(
email=json_data['email'],
password=json_data['password']
)
db_session.add(user)
db_session.commit()
return jsonify({'result': 'success'})