Possible circular import issue in Flask app - python

Trying a simple rest api in flask and basic stuff works. When I try to introduce DB, it's failing on imports for model
app.py
from flask import Flask, jsonify, request
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
import redis from rq import Queue
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)
migrate = Migrate(app, db)
from models import OcrText
models.py
from app import db
class OcrText(db.Model):
# schema
Error
Traceback (most recent call last):
File "app.py", line 21, in <module> from models import OcrText
File "/Users/anibara/Learn/Flask/ml_ocr/models.py", line 1, in <module> from app import db
File "/Users/anibara/Learn/Flask/ml_ocr/app.py", line 21, in <module> from models import OcrText
ImportError: cannot import name 'OcrText'

Yes, you are correct, it is a circular import issue. Just move the DB initialization to a new file like db.py and import this file from app.py and models.py. This way it will work fine.
Example db.py
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
db = None
def init_db(app):
global db
db = SQLAlchemy(app)
Migrate(app, db)
return db
Example app.py
from db import init_db
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
init_db(app)
from models import OcrText
Example models.py
from db import db
class OcrText(db.Model):
# schema

Related

I am getting import errors when trying to import my database into my own module

I have a module called crop.py in my flask application. Everything works great until I want to import database parts from models.py. I'm guessing it has something to do with initializing the module into the app and then trying to import models into it, but I'm not sure.
Here is the error:
flask.cli.NoAppException: While importing 'test', an ImportError was raised.
Here is my basic app construction.
-app
models.py
crop.py
crop.py
from app import current_app
from flask import url_for, Markup
import PIL
from PIL import Image
from uuid import uuid4
import os
#Adding these below causes an importerror------------------------------------
#from app import db
#from app.models import Upload
class _Avatars(object):
#code here
class Avatars(object):
def __init__(self, app=None):
if app is not None:
self.init_app(app)
#code here
__init.py
from flask import Flask, request, current_app _l
from elasticsearch import Elasticsearch
from redis import Redis
import rq
from config import Config
#This is my module-----------------------------------------------------
from .crop import Avatars
db = SQLAlchemy()
migrate = Migrate()
avatars = Avatars()
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
db.init_app(app)
avatars.init_app(app)
I think it is causing a circular import error, since you're importing your crop model in your __init.py file and you're import db from __init.py into crop model file. Python does not allow this kind of scenario. Either you'll have to define your DB connections elsewhere in a separate file or add them manually everywhere you need to use the DB.

Flask-Migrate not detecting tables

I have the following project structure:
project/__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
db = SQLAlchemy()
migrate = Migrate()
def create_app():
app = Flask(__name__)
app.config.from_object(os.environ['APP_SETTINGS'])
db.init_app(app)
migrate.init_app(app, db)
return app
run.py
from project import create_app
app = create_app()
if __name__ == "__main__":
app.run()
manage.py
from flask_script import Manager
from flask_migrate import MigrateCommand
from project.models import *
from project import create_app
manager = Manager(create_app)
manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
manager.run()
Yet when I run the following commands, Flask-Migrate is not detecting any tables to be added.
python manage.py db init
Which outputs:
Creating directory $HOME/Project/migrations ... done
Creating directory $HOME/Project/migrations/versions ... done
Generating $HOME/Project/migrations/script.py.mako ... done
Generating $HOME/Project/migrations/env.py ... done
Generating $HOME/Project/migrations/README ... done
Generating $HOME/Project/migrations/alembic.ini ... done
Please edit configuration/connection/logging settings in
'$HOME/Project/migrations/alembic.ini' before proceeding.
and
python manage.py db migrate
Which only outputs:
INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO [alembic.runtime.migration] Will assume transactional DDL.
Why is Flask-Migrate with Alembic not detecting the Models and therefore creating the tables? Here's what I've tried:
Deleting the database, starting from nothing
Creating a custom db class inside the manage.py file, doesn't detect that
Googling every answer to this problem, found lots of similar questions but none of their solutions worked for me.
EDIT:
Here is an example of the models.py file
from flask import current_app
from project import db
from flask_login import UserMixin
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50))
The solution was to import the models in the __init__.py file like so:
def create_app():
app = Flask(__name__)
app.config.from_object(os.environ['APP_SETTINGS'])
from project import models
db.init_app(app)
migrate.init_app(app, db)
return app
I had the same issue. The solution is pretty same as #joe's
In routes file
from models import User
api_user = Namespace('user', description='user related operations')
In project/__init__.py
def create_app():
app = Flask(__name__)
app.config.from_object(os.environ['APP_SETTINGS'])
from project import models
db.init_app(app)
migrate.init_app(app, db)
blueprint = Blueprint('api', __name__, url_prefix=url_prefix)
api = Api(blueprint, doc='/documentation') # ,doc=False
app.register_blueprint(blueprint)
api.add_namespace(api_user)
return app
when adding api_user namespace in create_app flask_migrate detected models

importing an attribute from parent directory

This is how my folder and files looks like:
/app
__init__.py
/admin
__init__.py
models.py
and app/__init__.py file:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from app.admin.models import *
app = Flask('app')
#app.route('/users', methods=['GET'])
def show_users():
return "list of all Users:\n" + User.query.limit(5).all()
and app/admin/models.py :
from datetime import datetime
from sqlalchemy.orm import relationship
from flask_sqlalchemy import SQLAlchemy
from app import app
db = SQLAlchemy(app)
class User(db.Model):
pass
I want have access to my User model in init file,from Import from parent directory and import script from a parenet directory I have tried from app import * or from .. import app or also put db = SQLAlchemy(app) in __init__ file and import it in models.py with from app import db or from .. import db but I'm keep getting app and db are not defined and also I think it's weird that I should import both file in each other.
The error is about Flask extensions, while your app created sqlalchemy extension didn't initialize, therefore it cause error. The best practice is to keep extensions initializes in same place:
#app/__init__.py
...
db = SQLAlchemy(app)
from app.admin.models import *
#app/admin/models.py
...
from app import db
If you do this changes, it will work.

flask migrate seemed to delete all my database data

Here is my migration file :
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
import models
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + 'C:\\flaskDB\\commBorn3.db'
db = SQLAlchemy(app)
migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
manager.run()
I ran the standard commands :
python app.py db init
python app.py db migrate
python app.py db upgrade
The resulting database was a file of the same name with about the same size in kb but only one table, "alembic_version" which had nothing in it. I tried to downgrade and found all my tables returned but they were empty. What did I do wrong? Where is all the data hiding (same kb size of file)?
You should always check the migration file in migrations/versions created after db migrate, and execute db upgrade only when everything looks alright.
The problem is that in models.py you import a db = SQLAlchemy(app) instance from your "normal" app, not from the migration script. So in the migration script you actually don't define any model, and this is why it deletes all your tables in the database.
The solution is easy: just use the migration script's app context when you import the models:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + 'C:\\flaskDB\\commBorn3.db'
db = SQLAlchemy(app)
# Import database models with app context
with app.app_context():
from models import *
migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
manager.run()

Flask db migrate doesn't affect my database tables

I'm trying to implement the Flask manager for SQLalchemy.
When I run python run.py db migrate then python run.py db upgrade, my tables aren't affected. I just removed a field from my models.py file that should be removed from the table.
Here are my files :
root/run.py :
#!flask/bin/python
import sys
sys.path.append("/app")
from app import app
app.run(debug = True)
root/app/__init__.py :
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.script import Manager
from flask.ext.migrate import Migrate, MigrateCommand
from app.database import db, db_session, init_db
app = Flask(__name__)
app.config.from_object('settings')
init_db()
migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
manager.run()
from catalog.views import catalog
app.register_blueprint(catalog)
root/app/database.py :
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine('mysql://root:root#127.0.0.1/mydb', convert_unicode=True)
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
db = declarative_base()
db.query = db_session.query_property()
def init_db():
import app.models
db.metadata.create_all(bind=engine)
I think I'm doing it wrong with the manager.run() but I'm not clearly understanding how to run it.
EDIT :
I finally made more simple database settings after iurisilvio's advice :
root/app/__init__.py :
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.script import Manager
from flask.ext.migrate import Migrate
app = Flask(__name__)
app.config.from_object('settings')
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:root#127.0.0.1/mydb'
db = SQLAlchemy()
db.app = app
db.init_app(app)
migrate = Migrate(app, db)
manager = Manager(app)
from catalogue.views import catalogue
app.register_blueprint(catalogue)
root/run.py :
#!flask/bin/python
import sys
sys.path.append("/app")
from app import app, manager
from flask.ext.migrate import MigrateCommand
manager.add_command('db', MigrateCommand)
app.debug = True
manager.run()
Now it works pretty fine !
Flask-Migrate works with the Flask-SQLAlchemy session. You are creating your session with raw sqlalchemy.
I don't know if it is possible at all. You have to change your database.py to work with Flask-SQLAlchemy.

Categories

Resources