Access db from a separate file flask SQLAlchemy python3 - python

I am writing a flask application. I have two files. main.py and databases.py. I want to create a database from the database.py file. The main.py should access the databases.py file and create the database and table named "Users". But it shows import error. Help me with this issue
main.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from databases import User
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/data_log.db'
db = SQLAlchemy(app)
if __name__ == '__main__':
db.create_all()
app.run(host='0.0.0.0', port=5001)
databases.py
from main import db
from passlib.apps import custom_app_context as pwd_context
class User(db.Model) :
__tablename__ = 'users'
user_id = db.Column(db.Integer, primary_key = True)
username = db.Column(db.String(32), index = True)
password = db.Column(db.String(128))
def hash_password(self, password) :
self.password =pwd_context.hash(password)
def verify_password(self, password) :
return pwd_context.verify(password, self.password)
Traceback:
Traceback (most recent call last):
File "main.py", line 3, in <module>
from databases import User
File "/home/paulsteven/stack/databases.py", line 1, in <module>
from main import db
File "/home/paulsteven/stack/main.py", line 3, in <module>
from databases import User
ImportError: cannot import name 'User'

This is a regular case of cyclic imports conflict.
The traceback gives you a clear steps:
How it goes in steps:
you run main.py
the control flow starts importing features/libraries till it gets the 3rd line
from databases import User.
it goes to the databases module to find the needed User class. But ... the User may use the outer scope features (and it does require db.Model), so the control flow needs to scan databases module from the start. This reflects the 2nd step from traceback ("/home/paulsteven/stack/databases.py", line 1)
from the position of previous step being at database.py the control flow encounters from main import db - that means it should turn back to the main(main.py) module!
control flow returned to the main module start scanning again from the 1st line - till it finds from databases import User again. This reflects the traceback's 3rd step (File "/home/paulsteven/stack/main.py", line 3)
and you run into cycle ...
What is right way to solve the issue?
Keep all DB context/DB models in separate module(s).
Follow the sequence of objects relations and how they depend on each other:
---> Application instantiated first (app)
---> then DB framework instance is created db = SQLAlchemy(app) depending on app
---> then custom DB models created (like User(db.Model)) depending on db instance
main.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
# from databases import User <--- shouldn't be here
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/data_log.db'
db = SQLAlchemy(app)
if __name__ == '__main__':
from databases import User # after instantiating `db` import model(s)
db.create_all()
app.run(host='0.0.0.0', port=5001)

Related

ImportError: cannot import name 'db' from [package_name] [duplicate]

This question already has an answer here:
What is the correct way to solve this circular import error with a Flask blueprint?
(1 answer)
Closed 3 years ago.
I have a complicated code structure. The Project folder has a mother package that holds two more child package. I need to import a SQLAlchemy instance, db from the the mother package's init.py file to a child packages db_models.py file. the db_models.py holds all the routes that exchanges calls to the database. I have seen other solutions that came up but those didn't solve the problem as mine has multiple packages. Following is the hierarchy of my project.
FlaskUserAuthentication(project)
FlaskUserAuthentication(package)=>
API(package)=>
__init__.py
db_models.py
routes.py(Blueprint)
Site(package)=>
__init__.py
routes.py(Blueprint)
templates=>
index.html
signin.html
signup.html
__init__.py
run.py (under project)
Under the project folder FlaskUserAuthentication, I have a package with the same name(FlaskUserAuthentication). The following is the code from its __init__.py file.
from flask import Flask
from FlaskUserAuthentication.API.routes import api
from FlaskUserAuthentication.Site.routes import site
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
db = SQLAlchemy(app)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'
app.register_blueprint(api)
app.register_blueprint(site)
Under the two child packages under namely API and Site, there are routes.py files one of which handles the database queries(API/routes.py) and another one renders the views(Site/routes.py). Both of these packages has a Blueprint instance.
The following is the code from API(package)/routes.py file-
from flask import jsonify, Blueprint, request
from FlaskUserAuthentication.API.db_models import Member
api = Blueprint('api', __name__)
#api.route('/members')
def get_all_members():
members = Member.query.all()
return jsonify({'response': 'This will return the members from the sqlite database'})
However at the second line, where I am trying to import the SQLAlchemy model class, Member, I am getting some error which doesn't refer to that line but it was okay before I added that line, so I realized this was it. The following is the error I am getting -
Traceback (most recent call last):
File "F:\FlaskUserAuthentication\run.py", line 1, in <module>
from FlaskUserAuthentication import app
File "F:\FlaskUserAuthentication\FlaskUserAuthentication\__init__.py", line 2, in <module>
from FlaskUserAuthentication.API.routes import api
File "F:\FlaskUserAuthentication\FlaskUserAuthentication\API\routes.py", line 2, in <module>
from FlaskUserAuthentication.API.db_models import Member
File "F:\FlaskUserAuthentication\FlaskUserAuthentication\API\db_models.py", line 1, in <module>
from FlaskUserAuthentication import db
ImportError: cannot import name 'db' from 'FlaskUserAuthentication' (F:\FlaskUserAuthentication\FlaskUserAuthentication\__init__.py)
The following code is from the API/db_model.py file-
from FlaskUserAuthentication import db
from datetime import datetime
class Member(db.Model):
id = db.Column('id', db.Integer, primary_key=True)
username = db.Column('user_name', db.String(100), nullable=False)
email = db.Column('email', db.String(100), nullable=False, unique=True)
password = db.Column('password', db.String(100), nullable=False, unique=False)
However, If I comment out the from FlaskUserAuthentication.API.db_models import Member, under the API/routes.py file, I don't get this error.
I realized it must be a circular import issue but can anyone please explain me how to avoid such error?
How can I import my db_model classes in my routes.py file?
It looks like you are importing db (in API/db_model.py) before it's initialized. The quick and dirty solution might be to import api after you initialize the db object in the top level __init__.py.
from flask import Flask
from FlaskUserAuthentication.Site.routes import site
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
db = SQLAlchemy(app)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'
from FlaskUserAuthentication.API.routes import api
I suggest you use the app factory pattern, however, as your application grows in complexity.

Flask objects on multiple sessions when they not should be

I have a similar problem to the user here: SQLAlchemy Object already attached to session
And I'm getting basically the same error:
'<Link at 0x7f31a785f630>' is already attached to session '1' (this is '15')
I'm really trying to figure out why multiple sessions are being created, when I only want one. I have two files __init__.py and models.py:
Lines of interest from __init__.py:
from .models import User, draft_new_link_message, load_history, load_messages, db
# Initialize app and such
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///my.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
app.secret_key = 'super secret keyssss'
socketio = SocketIO(app)
db.init_app(app)
app.app_context().push()
...
db.create_all()
From models.py:
db = SQLAlchemy()
class Link(db.Model):
__tablename__ = 'link'
id = db.Column(db.Integer, primary_key=True, nullable=False)
url = db.Column(db.String(500), nullable=False)
originator_id = db.Column(db.Integer, db.ForeignKey('user.id'))
originator = db.relationship("User", back_populates='history')
From these lines alone, it seems that I should be on one session. If I'm not, how do I format my code correctly to reduce headaches and make sure I don't have to transfer objects between sessions? Thanks!
Edit: Solution
The reason I structured my project this way was because a few pieces of documentation said this was the correct pattern (creating the db inside your models file and then callng db.init_app() to get it into the main file). But I guess this was a bad idea. I thought maybe I had to because I can't have both the files reference each other. But to get around this I wrote a method in the main file to get the db and called the import on the models function
My new __init__.py:
# Initialize app and such
app = Flask(name)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///browse_together.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
app.secret_key = 'super secret keysssss'
socketio = SocketIO(app)
db = SQLAlchemy(app)
# Provide a way for models.py (and any other files that needs it) to get access to the database
def get_db():
return db
# Now you can import models.py because it can use this database
from . import urltils, models
from .models import User, Group, get_groups, create_group, \
draft_new_link_message, load_history, load_messages, toggle_send
The new first few lines from models.py:
from flask_login import UserMixin
from . import urltils
from . import get_db
# Get an instance of the db from __init__
db = get_db()
I think this is more correct.
The reason I structured my project this way was because a few pieces of documentation said this was the correct pattern (creating the db inside your models file and then callng db.init_app() to get it into the main file). But I guess this was a bad idea. I thought maybe I had to because I can't have both the files reference each other. But to get around this I wrote a method in the main file to get the db and called the import on the models function
My new __init__.py:
# Other imports...
# Initialize app and such
app = Flask(name)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///my.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
app.secret_key = 'super secret keysssss'
db = SQLAlchemy(app)
# Provide a way for models.py (and any other files that needs it) to get access to the database
def get_db():
return db
# Now you can import models.py because it can use this database
from . import urltils, models
from .models import User, Group, get_groups, create_group, \
draft_new_link_message, load_history, load_messages, toggle_send
The new first few lines from models.py:
from flask_login import UserMixin
from . import urltils
from . import get_db
# Get an instance of the db from __init__
db = get_db()
I think this is more correct.

flask-migrate issue while refactoring code

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()

Flask circular dependency

I am developing a Flask application. It is still relatively small. I had only one app.py file, but because I needed to do database migrations, I divided it into 3 using this guide:
https://realpython.com/blog/python/flask-by-example-part-2-postgres-sqlalchemy-and-alembic/
However, I now can't run my application as there is a circular dependency between app and models.
app.py:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask import render_template, request, redirect, url_for
import os
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ['DB_URL']
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.debug = True
db = SQLAlchemy(app)
from models import User
... routes ...
if __name__ == "__main__":
app.run()
models.py:
from app import db
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(120), unique=True)
def __init__(self, username, email):
self.username = username
self.email = email
def __repr__(self):
return self.username
manage.py:
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
from app import app, db
migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)
if __name__ == "__main__":
manager.run()
They are all in the same directory. When I try to run python app.py to start the server, I receive an error which definitely shows a circular dependency (which is pretty obvious). Did I make any mistakes when following the guide or is the guide wrong? How can I refactor this to be correct?
Thanks a lot.
EDIT: Traceback
Traceback (most recent call last):
File "app.py", line 14, in <module>
from models import User
File "/../models.py", line 1, in <module>
from app import db
File "/../app.py", line 14, in <module>
from models import User
ImportError: cannot import name User
I propose the following structure:
# app/extensions.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
...
# app/app.py
from app.extensions import db
def create_app(config_object=ProdConfig):
app = Flask(__name__.split('.')[0])
app.config.from_object(config_object)
register_extensions(app)
...
def register_extensions(app):
db.init_app(app)
...
# manage.py
from yourapp.app import create_app
app = create_app()
app.debug = True
...
In this case, database, app, and your models are all in separate modules and there are no conflicting or circular imports.
I chased this for a few hours, landing here a few times, and it turned out I was importing my page modules (the ones holding the #app.route commands) before the line where the app was created. This is easy to do since import commands tend to be placed at the very beginning, but it doesn't work in this case.
So this:
# app/__init__.py
print("starting __init__.py")
from flask import Flask
from flask import render_template
import matplotlib.pyplot as plt
import numpy as np
import mpld3
app = Flask(__name__, instance_relative_config=True)
app.config.from_object('config')
from . import index
from . import simple
app.run(threaded=False)
print("finished __init__.py")
Instead of having all imports on top.
Placing this here because this has to be a common error for casual flask users to encounter and they are likely to land here. I have hit it as least twice in the last couple of years.

flask sqlalchemy example around existing database

Problem: there needs to be full working example of auto-mapping sqlalchemy to an existing database in an app with multiple binds.
I want to bind to two databases and have one auto-map the tables. I need to do this because i don't have control over one DB, thus would have to constantly re-write my models and might delete new tables every time i migrate.
I love the answers given here, but i can't seem to make it work in Flask (I am able to use the sqlalchemy only to query as per the example).
The model.py I set up from the example above results in
EDIT I pulled the line
db.Model.metadata.reflect[db.engine]
from another post, and it should be db.Model.metadata.reflect(db.engine)
very simple solution
here is my model.py
from app import db
from sqlalchemy.orm import relationship
db.Model.metadata.reflect[db.engine]#change to (db.engine)
class Buildings(db.Model):
__table__ = db.Model.metadata.tables['test']
__bind_key__ = 'chet'
def __repr__(self):
return self.test1
.... other models from sqlalchemy uri here...
i get this
>>> from app import db, models
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "app/__init__.py", line 69, in <module>
from app import views, models
File "app/views.py", line 1, in <module>
from app import app,models, db
File "app/models.py", line 163, in <module>
db.Model.metadata.reflect[db.engine]
TypeError: 'instancemethod' object has no attribute '__getitem__'
Here's my config.py
SQLALCHEMY_DATABASE_URI = 'postgresql://chet#localhost/ubuntuweb'
SQLALCHEMY_BINDS = {
'chet': 'postgresql://chet#localhost/warehouse',
}
here's my init.py file
from flask import Flask
from flask_bootstrap import Bootstrap
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.admin import Admin, BaseView, expose
from flask.ext.script import Manager
from flask.ext.migrate import Migrate, MigrateCommand
from flask.ext.login import LoginManager, UserMixin, login_required
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = 'app/static'
app.config.from_object('config')
db = SQLAlchemy(app)
migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)
Bootstrap(app)
from app import views, models
admin = Admin(app)
Your code has
db.Model.metadata.reflect[db.engine]
When it should be
db.Model.metadata.reflect(db.engine) # parens not brackets
This should have been pretty obvious from the stack trace....

Categories

Resources