Flask SQLAlchemy ImportError: cannot import Form - python

I am building a small questionnaire with Flask and SQLAlchemy, and for development testing I try to recall a random form by it's id. The terminal gives an ImportError however, but I do not have any files named after modules (like other stackoverflow problems) or circular import as the error suggests. How can I query the AddEnqueteForm in this separate file?
enquete_algorithm.py:
from models import AddEnqueteForm
import random
from settings import *
from flask import request
def enq_results(form_id):
form = AddEnqueteForm.query.all(filter=form_id)
reliability_dict = {}
reliability_dict['stelling_set_1'] = algorithm(form.stelling1, form.stelling2)
And of course models.py:
from main import db
class AddEnqueteForm(db.Model):
id = db.Column(db.Integer, primary_key=True)
stelling1 = db.Column(db.String(4), nullable=False)
stelling2 = db.Column(db.String(4), nullable=False)
Error:
Traceback (most recent call last):
File "c:\Users\Enquete\enquete_algorithm.py", line 1, in <module>
from mods import AddEnqueteForm
File "c:\Users\Enquete\models.py", line 1, in <module>
from main import db
File "c:\Users\Enquete\main.py", line 9, in <module>
from routes import *
File "c:\Users\Enquete\routes.py", line 4, in <module>
from models import AddEnqueteForm
ImportError: cannot import name 'AddEnqueteForm' from partially initialized module 'models' (most likely due to a circular import) (c:\Users\Enquete\models.py)
I realized some variable names are a bit confusing: the AddEnqueteForm is a model, not a form. I built the forms entirely in HTML.

The problem is not with enquete_algorithm.py .The circular import is occurs between routes.py and models.py. You are importing main.py in models.py and main.py in place imports routes.py and routes.py is importing models.py.
For solving this I made a separate file database.py where I define the db and I import db from that file in both main.py and models.py. This prevents the circular import.
database.py:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def init_app(app):
db.init_app(app)
models.py :
from database import db
class AddEnqueteForm(db.Model):
id = db.Column(db.Integer, primary_key=True)
stelling1 = db.Column(db.String(4), nullable=False)
stelling2 = db.Column(db.String(4), nullable=False)
In main.py you need to import both models and database and use init_app() to initialize the database.
[...]
from database import db
from models import *
[...]
app = Flask(__name__)
database.init_app(app)
Now if you ever want to run command db.create_all() through terminal to create database. you need to use application context.
running the following commands will create the database.
from main import *
with app.app_context():
db.create_all()

Related

ImportError: cannot import name 'app' from partially initialized module 'market' (most likely due to a circular import)

I was trying to package my code as it was getting kind of complex for me to keep in one file and i encountered an import error when i tried to run the file that says circular import error, how do i solve this error? I have been analyzing the code and i cannot seem to be able to figure out what might be wrong.
run.py
from market import app
if __name__ == "__main__":
app.run(debug=True)
init.py
from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
from market import routes
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///market.db"
db = SQLAlchemy(app)
routes.py
from market import app
from flask import render_template
from market.models import Item
#app.route("/")
#app.route("/home")
def home():
return render_template("index.html")
#app.route("/market")
def market():
items = Item.query.all()
return render_template("market.html", items=items)
models.py
from market import db
class Item(db.Model):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(length=30), nullable=False, unique=True)
price = db.Column(db.Integer(), nullable=False)
barcode = db.Column(db.String(length=12), nullable=False, unique=True)
description = db.Column(db.String(length=1024), nullable=False, unique=True)
def __repr__(self):
return f"Item {self.name}"
project structure
error
Moving your routes import to the bottom of the file should help.
Just as you would do for example with blueprints in application factory. You import blueprints/views after you create app instance with app = Flask(__name__):
def create_app(config_filename):
app = Flask(__name__)
app.config.from_pyfile(config_filename)
from yourapplication.model import db
db.init_app(app)
from yourapplication.views.admin import admin
from yourapplication.views.frontend import frontend
app.register_blueprint(admin)
app.register_blueprint(frontend)
return app
Also check:
Is a Python module import at the bottom ok?
in your __init__.py you import routes
in routes.py you import app (defined in __init__.py)

How to fix "RuntimeError: Working outside of application context." when creating blueprints with Flask?

I'm trying to create a Blueprint and ran into this problem:
Traceback (most recent call last):
File "C:\Users\Max\PycharmProjects\python1\flask_first\__init__.py", line 3, in <module>
from models import db
File "C:\Users\Max\PycharmProjects\python1\flask_first\models.py", line 5, in <module>
current_app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.sqlite3.html' # access to the SQL
File "C:\python3.9\lib\site-packages\werkzeug\local.py", line 347, in __getattr__
return getattr(self._get_current_object(), name)
File "C:\python3.9\lib\site-packages\werkzeug\local.py", line 306, in _get_current_object
return self.__local()
File "C:\python3.9\lib\site-packages\flask\globals.py", line 52, in _find_app
raise RuntimeError(_app_ctx_err_msg)
RuntimeError: Working outside of application context.
This typically means that you attempted to use functionality that needed
to interface with the current application object in some way. To solve
this, set up an application context with app.app_context(). See the
documentation for more information.
I've already done a lot of research and nothing works for me (or I'm just not looking properly enough).
This is the models.py code:
from flask_sqlalchemy import SQLAlchemy
from flask import current_app
current_app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.sqlite3.html' # access to the SQL
current_app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(current_app)
class users(db.Model):
__tablename__ = 'users'
_id = db.Column('id', db.Integer, primary_key=True)
name = db.Column(db.String(80))
email = db.Column(db.String(120))
password = db.Column(db.Integer)
def __init__(self, name, email, password):
self.name = name
self.email = email
self.password = password
And this is the __init__.py:
from datetime import timedelta
from flask import Flask
from models import db
from flask_first.admin.second import second
def create_app():
app = Flask(__name__)
with app.app_context():
db.init_app(app)
return app
create_app.secret_key = 'hello world'
create_app.permanent_session_lifetime = timedelta(minutes=5) # setting the time for long-lasting session
if __name__ == '__main__':
db.create_all()
create_app.run(debug=True)
Here is a screenshot of my structure:
Here I'll expand on my comment into an answer.
Python executes your code line-by-line, and that includes import statements. As the error indicates, when it entered __init__.py and got to the from models import db line, it immediately jumped to models.py, and started executing your lines there.
Traceback (most recent call last):
File "...\__init__.py", line 3, in <module>
from models import db
File "...\models.py", line 5, in <module>
current_app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.sqlite3.html'
At this point, the imported current_app does not exist yet, because the create_app from __init__.py seems to have not been called yet. This is where you'll get the common Flask error of "working outside of application context:
RuntimeError: Working outside of application context.
This typically means that you attempted to use functionality that needed
to interface with the current application object in some way. To solve
this, set up an application context with app.app_context(). See the
documentation for more information.
Most of the time you get this type of error, the solution is to reorder your initialization codes. Make sure that the Flask app instance is already created before you do anything else. It should usually be the first thing your code does.
Following the Quickstart tutorial from flask-sqlalchemy, you can put the db object initialization near the app initialization.
# Create app object
app = Flask(__name__)
# Set configs
app.config['...'] = ...
# Create db object
db = SQLAlchemy(app)
The app and db objects typically reside together in some top-level main module. Then, in your other sub-modules (controllers, models, etc.) where you need to setup each component separately, import the app and/or db from the main module:
from some_main_module import app, db
# Do stuff with app and db

ImportError: cannot import name 'db'

I am working on adding flask admin to a preexisting flask boiler plate project. I've been able to get the basic project working at https://github.com/kc1/flask-base (SCREENSHOT). I now need to add modelviews to add basic CRUD functionality. To do this I changed the code to :
adm = Admin(app,name='flaskadmin')
from app.models import User
adm.add_view(ModelView(User, db.session))
You can see that it works. But if I import the User model with the rest of the imports at the top of app/init I get:
Traceback (most recent call last):
File "...flask-base/manage.py", line 10, in <module>
from app import create_app, db
File "E:\ENVS\r3\flask-base\app\__init__.py", line 17, in <module>
from app.models import User
File "E:\ENVS\r3\flask-base\app\models\__init__.py", line 6, in <module>
from .user import * # noqa
File "E:\ENVS\r3\flask-base\app\models\user.py", line 7, in <module>
from .. import db, login_manager
ImportError: cannot import name 'db'
Why?
User is a Flask-SQLAlchemy model that wraps models using SQLalchemy's API. It inherits all of its models from a db object, which I assume you are instantiating or registering inside a create_app method.
So, you should have something like this
db = SQLAlchemy()
def create_app(config):
app = Flask(__name__)
db.init_app(app)
adm = Admin(app,name='flaskadmin')
from app.models import User
adm.add_view(ModelView(User, db.session))
return app
Whenever you import User from user.py you are basically importing db.Model, which requires for db to exists and actually contain data. Be wary of circular imports in Flask and in Python in general.
The error you are receiving is clearly stated in the error traceback
File "E:\ENVS\r3\flask-base\app\models\user.py", line 7, in <module>
from .. import db, login_manager
ImportError: cannot import name 'db'
This is, in user.py there is an import of db from ../__init__.py but in that file there is an import of User happening before the definition of db.
A db object emulates the declarative approach from SQLAlchemy, where the object holds data about every other Class that inherited from it.

SQLAlchemy inheritance not working

I'm using Flask and SQLAlchemy. I have used my own abstract base class and inheritance. When I try to use my models in the python shell I get the following error:
>>> from schedule.models import Task
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/teelf/projects/schedule/server/schedule/models.py", line 14, in <module>
class User(Base):
File "/home/teelf/projects/schedule/server/venv/lib/python3.4/site-packages/flask_sqlalchemy/__init__.py", line 536, in __init__
DeclarativeMeta.__init__(self, name, bases, d)
File "/home/teelf/projects/schedule/server/venv/lib/python3.4/site-packages/sqlalchemy/ext/declarative/api.py", line 55, in __init__
_as_declarative(cls, classname, cls.__dict__)
File "/home/teelf/projects/schedule/server/venv/lib/python3.4/site-packages/sqlalchemy/ext/declarative/base.py", line 254, in _as_declarative
**table_kw)
File "/home/teelf/projects/schedule/server/venv/lib/python3.4/site-packages/sqlalchemy/sql/schema.py", line 393, in __new__
"existing Table object." % key)
sqlalchemy.exc.InvalidRequestError: Table 'user' is already defined for this MetaData instance. Specify 'extend_existing=True' to redefine options and columns
on an existing Table object.
How do I fix this?
Code:
manage.py:
#!/usr/bin/env python
import os, sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from flask.ext.migrate import Migrate, MigrateCommand
from flask.ext.script import Manager
from server import create_app
from database import db
app = create_app("config")
migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command("db", MigrateCommand)
if __name__ == "__main__":
manager.run()
__init__.py:
from flask import Flask
from flask.ext.login import LoginManager
from database import db
from api import api
from server.schedule.controllers import mod_schedule
def create_app(config):
# initialize Flask
app = Flask(__name__)
# load configuration file
app.config.from_object(config)
# initialize database
db.init_app(app)
api.init_app(app)
# initialize flask-login
login_manager = LoginManager(app)
# register blueprints
app.register_blueprint(mod_schedule)
return app
database.py:
from flask.ext.sqlalchemy import SQLAlchemy
db = SQLAlchemy()
models.py:
from sqlalchemy.dialects.postgresql import UUID
from database import db
class Base(db.Model):
__abstract__ = True
id = db.Column(UUID, primary_key=True)
class User(Base):
__tablename__ = "user"
username = db.Column(db.String)
password = db.Column(db.String)
first_name = db.Column(db.String)
last_name = db.Column(db.String)
authenticated = db.Column(db.Boolean, default=False)
def __init__(self, first_name, last_name, username):
self.first_name = first_name
self.last_name = last_name
self.username = username
def is_active(self):
""" All users are active """
return True
def get_id(self):
return self.username
def is_authenticated(self):
return self.authenticated
def is_anonymous(self):
""" Anonymous users are not supported"""
return False
controllers.py:
from flask import Blueprint
from flask.ext.restful import reqparse, Resource
from api import api
from server.schedule.models import User
mod_schedule = Blueprint("schedule", __name__, url_prefix="/schedule")
class Task(Resource):
def put(self):
pass
def get(self):
pass
def delete(self):
pass
api.add_resource(Task, "/tasks/<int:id>", endpoint="task")
Try adding
__table_args__ = {'extend_existing': True}
to your User class right under __tablename__=
cheers
Another option, if you don't already have data in your pre-existing database, is to drop it, recreate it without the tables. Then interactively run your "models.py" script (you would need to add a little code at the bottom to allow this), then in the interactive Python console do "db.create_all()" and it should create the tables based on your classes.
I had the same problem and found the solution here:
https://github.com/pallets-eco/flask-sqlalchemy/issues/672#issuecomment-478195961
So, basically we hit the union of two problems:
Having left over .pyc files on the disk.
Git Ignoring empty directories full of files in .gitignore
Deleting the directories and cleaning the .pyc files solved the problem.

Running init_db() in the console won't work

Whenever I try to import init db in the python console:
>>from app.database import init_db
>>init_db()
init db
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "app\database.py", line 18, in init_db
import models
ImportError: No module named models
This is the content of my app.database function:
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from config import SQLALCHEMY_DATABASE_URI
engine = create_engine(SQLALCHEMY_DATABASE_URI, 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 all modules here that might define models so that
# they will be registered properly on the metadata. Otherwise
# you will have to import them first before calling init_db()
print "init db"
import models
Base.metadata.create_all(bind=engine)
Why is it like this?
UPDATE: This is the structure of my project.
app/
filebase/
init.py
models.py
users/
init.py
models.py
projects/
init.py
models.py
init.py
database.py (this is where the init_db was defined
As for the structure on why it looked like that, the reason is to make the project modular in its form.
You need the parent directory of models.py (or, of the models package) to be in your sys.path. You can put it there in your console session, or, in the shell, add it to environment variable PYTHON_PATH so it will be set at entry to the console session.

Categories