This question already has an answer here:
Import Flask extension when it is created in an app factory [duplicate]
(1 answer)
Closed 4 years ago.
I'm trying to import database and get an error "cannot import name 'db'". I've seen answers on such problem, but none of them helped in my case.
Tree of my project:
chat
| chat.py
└─ app
│ models.py
│ __init__.py
│
├─── main
│ events.py
│ forms.py
│ routes.py
│ __init__.py
chat.py:
from app import create_app, socketio
app = create_app(debug=True)
if __name__ == '__main__':
socketio.run(app)
app\init.py:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_socketio import SocketIO
socketio = SocketIO()
def create_app(debug=False):
app = Flask(__name__)
app.debug = debug
app.config['SECRET_KEY'] = 'gjr39dkjn344_!67#'
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql:///site.db'
db = SQLAlchemy(app)
from .main import main as main_blueprint
app.register_blueprint(main_blueprint)
socketio.init_app(app)
return app
app\main\init.py:
from flask import Blueprint
main = Blueprint('main', __name__)
from . import routes, events
app\models.py:
from app import db
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(15), nullable=False)
session_id = db.Column(db.String(200), nullable=False)
isready = db.Column(db.Boolean, default='False')
room = db.relationship('Room', backref='spy')
def __repr__(self):
return f"User('{self.username}')"
So, when I'm trying from app import db in python terminal I get
ImportError: cannot import name 'db'
Since I'm new to flask (and web at all), I have no idea, what to do. I've tried this solution (kinda closest to my case) and all alike answers but it didn't work.
What can I try?
db is just a local variable in the create_app() function. You'll need to create that object outside of the create_app() factory.
You can create the Flask-SQLAlchemy db plugin object without passing in an app argument, and in the factory connect that object to te Flask app with the .init_app() method, just like you already do for the Flask-SocketIO plugin:
db = SQLAlchemy()
def create_app(debug=False):
app = Flask(__name__)
app.debug = debug
app.config['SECRET_KEY'] = 'gjr39dkjn344_!67#'
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql:///site.db'
db.init_app(app)
socketio.init_app(app)
from .main import main as main_blueprint
app.register_blueprint(main_blueprint)
return app
Now db is available as a global in the module, and so can be imported elsewhere.
Related
I am developing a Flask application, and I am not sure why I am getting this error:
File "app.py", line 17, in <module>
from endpoints.users.resource import UserResource
File "{basedir}/endpoints/users/resource.py", line 4, in <module>
from .model import User
File "{basedir}/endpoints/users/model.py", line 1, in <module>
from app import db
File "{basedir}/app.py", line 17, in <module>
from endpoints.users.resource import UserResource
ImportError: cannot import name 'UserResource' from 'endpoints.users.resource' ({basedir}/endpoints/users/resource.py)
I believe it is due to a circular dependency, from looking at the error, but I can't figure out why, because I think that the order in which I am importing things in my code should have circumvented this issue:
app.py:
from flask import Flask
from flask_restful import Api
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)
api = Api(app)
api.prefix = '/api'
from endpoints.users.resource import UserResource
api.add_resource(UserResource, '/users')
if __name__ == '__main__':
app.run(host="0.0.0.0")
endpoints/users/model.py:
from app import db
class User(db.Model):
# info about the class, requires db
endpoints/users/resource.py:
from flask_restful import Resource
from .model import User
from app import db
class UserResource(Resource):
def get(self, username=None):
# get request, requires db and User
In app.py, since I am importing from endpoints.users.resource after db is created, shouldn't that circumvent the circular dependency?
In addition, I can run this with flask run but when I try to use python app.py, then it gives me the above error. Why would these give different results?
So on from endpoints.users.resource import UserResource line python tries to import from app import db line to app.py which causes app reference to itself, which is not good at all.
One workaround to solve circual import errors in Flask is using init_app function which exists in most of Flask apps. So just create database file like this:
database.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
app.py
from flask import Flask
from flask_restful import Api
from database import db
from endpoints.users.resource import UserResource
app = Flask(__name__)
app.config.from_object(Config)
db.init_app(app)
api = Api(app)
api.prefix = '/api'
api.add_resource(UserResource, '/users')
if __name__ == '__main__':
app.run(host="0.0.0.0")
endpoints/users/model.py:
from database import db
class User(db.Model):
# info about the class, requires db
endpoints/users/resource.py:
from flask_restful import Resource
from endpoints.users.model import User
from database import db
class UserResource(Resource):
def get(self, username=None):
# get request, requires db and User
Note that I rewrote your imports from related, so don't forget to add __init__.py files
Your structure will be like this:
.
├── app.py
└── database.py/
└── endpoints/
├── __init__.py
└── users/
├── __init__.py
├── model.py
└── resource.py
I have the following code:
init.py:
"""Initialize app."""
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def create_app():
"""Construct the core application."""
app = Flask(__name__, instance_relative_config=False)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'
app.config['RECAPTCHA_PUBLIC_KEY'] = '6LcmEeoUAAAAAIbdhgkFBvz676UCRJMjnSx8H6zy'
app.config['RECAPTCHA_PARAMETERS'] = {'size': '100%'}
db.init_app(app)
# blueprint for auth routes in our app
from .auth import auth as auth_blueprint
app.register_blueprint(auth_blueprint)
# blueprint for non-auth parts of app
from .__main__ import main as main_blueprint
app.register_blueprint(main_blueprint)
with app.app_context():
# Import parts of our application
from . import routes
return app
and I try to initialize the db with the following code:
from realProject import db, create_app
db.create_all(app=create_app())
all of the scripts are in realProject folder
but when trying to compile the last code I get this error:
ModuleNotFoundError: No module named 'realProject'
What am I doing wrong?
You need to follow this structure :
|__project_name
|__app.py ----------> The main file from where you run your app
|__app -----> This is the app folder
├── templates
│ └── index.html
└── __init__.py -----------> The __init__.py should be inside the app folder for it to be imported
└── routes.py
And then do this in your main file :
from app import db, create_app
db.create_all(app=create_app())
I am trying to implement Flask-PyMongo with blueprints and an application factory and keep getting AttributeError: 'Flask' object has no attribute 'db'
My directory structure looks like
myapp/
myapp.py
config.py
/app
__init__.py
/v1
__init__.py
endpoints.py
In my python script that starts the Flask app I have:
import os
from app import create_app
app = create_app('dev')
In my top level init.py I have:
mongo = PyMongo()
def create_app(config_name):
app = Flask(__name__)
mongo.init_app(app)
app.config.from_object(config[config_name])
from app.v1 import psapi as psapi_bp
app.register_blueprint(psapi_bp, url_prefix='/api')
if not os.path.exists('logs'):
os.mkdir('logs')
In my endpoints.py I have a route that looks like
#myapp.route('/addentry', methods=['POST'])
def addentry():
username = request.json['username']
userid = current_app.db.user_entry.insert({'username':username})
return jsonify({'userid':userid})
I feel like there is something small that I am missing but I am not seeing it.
You need to call db on your mongo object, not on the app object
to those who may be facing this problem again :
you should first define mongo oustside create_app to have access to it from inside other files.
then init_app with that like the following:
from flask import Flask, current_app
from flask_pymongo import PyMongo
mongo = PyMongo()
def create_app(config_name):
app = Flask(__name__, instance_relative_config=False)
app.config.from_object(app_config[config_name])
# INIT EXTENSIONS ----------------------
mongo.init_app(app)
return app
then in any file you can import mongo from above file. for example:
from ../factory import mongo
Trying to run the tutorial here: http://flask-sqlalchemy.pocoo.org/2.1/quickstart/ using my app
I have looked at the circular imports problem but I don't think that's it. I'm an absolute beginner to python and flask (and sqlalchemy). My app currently runs, but the database part doesn't
This is the current setup:
mysite
|- __init__.py
|- flask_app.py
|- models.py
|- views.py
init.py
from flask import Flask
app = Flask(__name__)
flask_app.py
from flask import Flask, request, url_for
import random
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql:// -- database uri --'
... app continues here
models.py
from app import app
from flask.ext.sqlalchemy import SQLAlchemy
db = SQLAlchemy(app)
class Foo(db.Model):
... model continues here
views.py
from app import app,models
... views continue here, still not using anything from models
when I run from mysite import db in the python console I get:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: cannot import name 'db'
Declare your db object in __init__.py. The stuff that is declared in __init__.py defines what can be imported under mysite/.
See: What is __init__.py for?
Also consider moving to the application factory pattern.
For example in __init__.py:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
app.config['DEBUG'] = True
... more application config ...
db.init_app(app)
return app
Then in flask_app.py:
from mysite import create_app, db
app = create_app()
if __name__ == '__main__':
app.run()
I point this out because you instantiate the app object twice in the code you've shown. Which is definitely wrong.
If app is created in global scope
__init__.py
from flask import Flask
app = Flask(__name__)
app.config.from_object('config')
from app import views
This code down below in run.py would be enuf to start using whoosh_search in views.py like post = Post.query.whoosh_search(name, limit=3).all()
run.py
import os
from app import app
from flask.ext.script import Manager
from flask.ext.moment import Moment
from flask.ext.sqlalchemy import SQLAlchemy
import flask.ext.whooshalchemy as whooshalchemy
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] =\
'sqlite:///' + os.path.join(basedir, 'post.sqlite')
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
app.config['SECRET_KEY'] = 'hard to guess string'
db = SQLAlchemy(app)
manager = Manager(app)
moment = Moment(app)
class Post(db.Model):
__tablename__ = 'post'
__searchable__ = ['body']
id = db.Column(db.Integer, primary_key=True)
body = db.Column(db.String(140))
timestamp = db.Column(db.DateTime))
def __repr__(self):
return '<Post %r>' % (self.body)
whooshalchemy.whoosh_index(app, Post)
if __name__ == '__main__':
db.create_all()
manager.run()
So how to implement Flask-WhooshAlchemy using an Application Factory.
__init__.py
from flask import Flask
from flask.ext.bootstrap import Bootstrap
from flask.ext.moment import Moment
from flask.ext.sqlalchemy import SQLAlchemy
from config import config
bootstrap = Bootstrap()
moment = Moment()
db = SQLAlchemy()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
bootstrap.init_app(app)
moment.init_app(app)
db.init_app(app)
from .main import main as main_blueprint
app.register_blueprint(main_blueprint)
return app
How to register app in whooshalchemy.whoosh_index(app, Post) with Application Factory so whoosh_search could be use in views.py like in last example.
In your application factory function fx. after initializing all the apps, and before registering your blueprints. You should import your model and run whoosh_index. Something along the lines of:
from .model import Post
whooshalchemy.whoosh_index(app, Post)