I'm trying to import an object named db (SQLAlchemy object) in in a module of my Flask Project in order to use the SQLAlchemy in my models (models.py). Assuming my package is named Foo and contains the db object in his __init__.py file , when i try to do a from Foo import db, i get the following error:
ImportError: cannot import name db
I'm using Flask Blueprint to dispatch my project into two applications (dashboard and frontend) and each of them contains an __init__.pyfile. Only the models.py is throwing this error, i got some imports in my views file (as importing the login manager) and everything goes well.
Any idea of what it could be ?
UPDATE : The traceback
Traceback (most recent call last):
File "run.py", line 4, in <module>
from kuchiyose import app
File "/path_to_project/kuchiyose/kuchiyose/__init__.py", line 60, in <module>
from kuchiyose import dashboard, frontend
File "/path_to_project/kuchiyose/kuchiyose/dashboard/__init__.py", line 10, in <module>
from dashboard import views
File "/path_to_project/kuchiyose/kuchiyose/dashboard/__init__.py", line 10, in <module>
from dashboard import views
File "/path_to_project/kuchiyose/kuchiyose/dashboard/views.py", line 8, in <module>
from kuchiyose.dashboard.models import User
File "/path_to_project/kuchiyose/kuchiyose/dashboard/models.py", line 3, in <module>
from kuchiyose import db
ImportError: cannot import name db
First, thanks for the help. Concerning my second question : "How to import Flask models into views without having a circular import issue (when using SQLAlchemy)", i found a solution. It consists to setup the SQLAlchemy object not into the application __init__.pyfile but into the models.pyfile itself. With that, you can import it in your views.pyfile without problem.
My models.py file, now:
from kuchiyose import app
from flask.ext.sqlalchemy import SQLAlchemy
db = SQLAlchemy(app)
And my views.py
from kuchiyose.dashboard import models
This is an old one but showed up as a top result in my search.
I have a project that has model declarations in a few different places rather than a consolidated models.py file so this solution wouldn't be ideal. I found importing your views AFTER establishing the db object works as well.
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config.from_object('config')
db = SQLAlchemy(app)
# Now Register routes
# db is now defined so app import db will now work)
from routes.user import user as user_routes
app.register_blueprint(user_routes)
there appears to be circular imports:
kuchiyose/__init__.py imports from kuchiyose.dashboard.views
kuchiyose/dashboard/views.py imports from kuchiyose.dashboard.models
kuchiyose/dashboard/models.py imports from kuchiyose
see e.g. Circular (or cyclic) imports in Python for more info...
Related
I am trying to build an app using Flask and a pre existing sqlite database which has 3 tables. I tried checking what the issue is by trying to import the DB in terminal with a minimal app.
As suggested in this tutorial I used the following code, where city is a table in the db:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////path/test.sqlite'
db = SQLAlchemy(app)
class city(db.Model):
__tablename__ = 'city'
Following this method I was able to import the db and the table in terminal using the following command.
from yourapplication import db
However when I try to do the same with following method as suggested here in the same tutorial, since my project is getting a little bigger and it is the recommended method in the book I am following as well as Flask tutorial, I get the above mentioned error.
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
SQLALCHEMY_DATABASE_URI = 'sqlite:////path/test.sqlite'
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
db.init_app(app)
return app
class city(db.Model):
__tablename__ = 'city'
Start of the error message as it might be relevant:
from yourapplication import db
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/path/yourapplication.py", line 14, in <module>
class city(db.Model):
Now I am not sure the second method is done in the right way in my code since documentation doesn't mention what to do to provide address of the database but I am getting the same error that I have been getting in my original project. My main app also works when all the views and code other than the templates are in the same file.
Since I can import the db in the first method, I assume that problem isn't with the DB and it has primary key. I also know that because the db works perfectly fine in first method and I created the db from a pandas dataframe using the following code:
df1.to_sql("city", conn, dtype={'pkc': 'INTEGER PRIMARY KEY'}, if_exists='replace', index=False)
where pkc has the same value as the index of df1.
This is the book I am following.
TL;DR: How do I use a metadata object from a Blueprint to create the Flask-SQLAlchemy instance? The only place I can see to provide the declarative base metadata object is in the initial SQLAlchemy() call. But when I import it from the Blueprint in my extensions.py file, the Blueprint's code needs the db object and the loading fails due to a circular import.
I have several model classes which I would like to use both in and outside of Flask. I am using the declarative method to do this, and my app is set up to use the App Factory model and Blueprints. The way the models get registered with SQLAlchemy is through the use of the metadata argument when the db object is created. In the context of my application, it makes sense to declare the metadata object in a Blueprint, instead of in the main app Blueprint. (This is where most of the code which references it will be, including the non-Flask utility script used for initially populating the database.) However, importing the model class from the second Blueprint ends up in a circular import.
$ flask db migrate
Error: While importing "my_app", an ImportError was raised:
Traceback (most recent call last):
File "my_app/venv/lib/python3.7/site-packages/flask/cli.py", line 235, in locate_app
__import__(module_name)
File "my_app/my_app.py", line 1, in <module>
from app import create_app
File "my_app/app/__init__.py", line 7, in <module>
from app.extensions import *
File "my_app/app/extensions.py", line 10, in <module>
from turf.models import metadata
File "my_app/turf/__init__.py", line 1, in <module>
from .routes import bp
File "my_app/turf/routes.py", line 14, in <module>
from app.extensions import db
ImportError: cannot import name 'db' from 'app.extensions' (my_app/app/extensions.py)
As mentioned in this general question on circular imports for Blueprints, a solution which works is to import the db object from inside each function in the second Blueprint, thus side-stepping the import during initialization of the extensions.py file. But in addition to being annoying, this just feels extremely hacky.
Ideally, I would be able to pass the metadata object I've created to SQLAlchemy's init_app() method. That would resolve this issue at a stroke. Unfortunately, init_app() doesn't take a metadata argument. Is there some other way to register metadata with an SQLAlchemy instance after initialization? Or have I missed some other key element of the declarative model approach?
I should say that the non-Flask portion of this is working just fine. My utility script is able to import the models and use them to add objects to the database. It's only the Flask imports which are giving me trouble.
Here is the hierarchy:
.
├── app
│ ├── __init__.py
│ └── extensions.py
└── turf
├── __init__.py
├── models.py
└── routes.py
And the relevant code which fails due to circular import:
app/__init__.py:
from app.extensions import *
def create_app():
app = Flask(__name__)
with app.app_context():
import turf
app.register_blueprint(turf.bp)
db.init_app(app)
app/extensions.py:
from turf.models import metadata
db = SQLAlchemy(metadata=metadata)
turf/__init__.py:
from .routes import bp
turf/models.py:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import MetaData
metadata = MetaData()
Base = declarative_base(metadata=metadata)
# All the turf models are declared in this file
class Boundary(Base):
# ...etc...
turf/routes.py:
from .models import *
from app.extensions import db
bp = Blueprint('Turf', __name__, url_prefix='/turf')
#bp.route('/')
def index():
return render_template('turf/index.html')
It turns out you can declare the MetaData object in the extensions.py file and then import that in the Blueprint. I was sure this would fail, because the metadata object is now being populated after the db object is created, but I've verified that the models are indeed available and work as expected. And no more circular dependency. I've actually broken this part out into its own file to allow Blueprint code to import as little as possible.
app/base.py:
from sqlalchemy import MetaData
from sqlalchemy.ext.declarative import declarative_base
metadata = MetaData()
Base = declarative_base(metadata=metadata)
app/extensions.py:
from flask_sqlalchemy import SQLAlchemy
from .base import metadata
db = SQLAlchemy(metadata=metadata)
turf/models.py:
from app.base import Base
# All the turf models are declared in this file
class Boundary(Base):
# ...etc...
This also answers another question I had with my original approach: how would it work if I had a second Blueprint which also had model objects which needed to be available from non-Flask code? Now, I have created a single Base object and can use that to implement new classes in different Blueprints as needed.
One minor annoyance with this approach, though. In the non-Flask DB population script, I was originally able to use from models import * to refer to the sibling module (file) containing the models. This let me call the script directly, à la cd turf; python populate_db.py --arg. That no longer works because the models.py file now references a different package, app.extensions. So instead I have to use this workaround:
turf/populate_db.py:
try:
from .models import *
except:
print("You have to run this from outside the 'turf' directory like so: $ python -m turf.populate_db [...]")
sys.exit(1)
I've had a look at a very similar issue, but the solution isn't working for me, and I was wondering if I could get some guidance.
This is my application structure:
mosiman/
__init__.py
blog/
__init__.py
blogconfig.py
blog.py
static/
...
templates/
...
I really wanted a way to build separate apps but manage them from one application instance so I wouldn't have to touch the WSGI layer, and blueprints seemed like the best way.
Here's what I think the relevant files are:
# mosiman/__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import blog.blog as blog
...
...
db = SQLAlchemy()
...
...
def create_app():
app = Flask(__name__)
db_path = os.path.join(os.path.dirname(__file__), 'mosiman.db')
app.config["SQLALCHEMY_DATABASE_URI"] = 'sqlite:///{}'.format(db_path)
app.config["SQLALCHEMY_BINDS"] = {'blog': os.path.join(os.path.dirname(__file__), 'blog/blog.db')
db.init_app(app)
app.register_blueprint(blog.blog, url_prefix='/blog')
return app
if __name__ == '__main__':
app = create_app()
app.run(debug=True)
I also have in my mosiman/blog/blog.py file:
#mosiman/blog/blog.py
<<< all of the usual flask imports and SQLAlchemy, etc >>>
from .__init__ import db
blog = Blueprint('blog', __name__)
...
...
class Entry(db.Model):
__bind_key__ = "blog"
id = db.Column(db.Integer, primary_key = True)
title = db.Column(db.String(150))
...
...
Here is my problem: I actually don't have a "default" database, so I have no classes for it. But I do want to initialize my blog database with the class Entry.
The default procedure for initializing the database seems to be to pop into the python REPL, import the database, and run db.create_all()
Well, I can't just import db and run db.create_all() because db hasn't been attached to an app yet (done in create_app()) This is how I proceed:
# pop open a REPL at mosiman/
>>> from __init__ import db
>>> from __init__ import create_app
>>> app = create_app()
>>> db.init_app(app)
>>> from blog.blog import Entry
>>> db.init_app(app)
# At this point, db still isn't attached to an engine?
>>> db
<SQLAlchemy engine=None>
>>> with app.app_context():
... db.create_all()
...
>>>
Now, when I go to mosiman/blog/ I find that blog.db has been created, but when I check the schema and tables in SQLite3 nothing turns up.
1 solved their problem by changing from __init__ import db to from mosiman import db
If I try to do that inside mosiman/:
>>> from mosiman import db
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'mosiman'
even though I've got an __init__.py in there.
If I run it from ../ (the directory above mosiman):
>>> from mosiman import db
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/users/d49chan/mosiman/__init__.py", line 3, in <module>
import blog.blog as blog
ModuleNotFoundError: No module named 'blog'
I'm not sure how to proceed. Maybe it's because I need sleep, but I've been trying to understand why nothing works for the past many hours. If you could point me in the right direction or possibly clear up some of my misunderstandings I'd be very grateful.
1) You don't namely import __init__.py. You should import it with the name of the directory (package) it's in.
2) You shouldn't import like this: import blog.blog. Instead you should: from blog import blog.
3) Be sure you have an __init__.py file in every directory so that the python importer can treat it as a package (directory) it can import from.
4) There's a difference between relative importing and absolute importing.
Relative importing:
# l3_module.py in l3_package
from ..l1_package import l1_module
This imports a module located two packages (directories) up in relation to the module importing it.
Now assuming l3_package is in an l2_package which is in an l1_module, You can also import it as such
Absolute importing:
# l3_moudle.py in l3_package
from l1_package import l1_module
This will also work, but then it sometimes messes stuff up, depending on your env.
Here's an excellent answer that can clear some stuff up for you: Relative imports for the billionth time.
Hope that helped :)
I am using sphinx and was trying to generate documentation for my Django project. I decided to first try to document the models so in my .rst file I did this
wdland\.models
==============
.. automodule:: wdland.models
:members:
:undoc-members:
:show-inheritance:
But the get the following errors
WARNING: /home/fabou/wdlandenvpy3/source/docs/wdland.rst:9: (WARNING/2) autodoc: failed to import module 'wdland.models'; the following exception was raised:
Traceback (most recent call last):
File "/home/fabou/wdlandenvpy3/lib/python3.5/site-packages/sphinx/ext/autodoc.py", line 657, in import_object
__import__(self.modname)
File "/home/fabou/wdlandenvpy3/source/wdland/models.py", line 35, in <module>
class Device(models.Model):
File "/home/fabou/wdlandenvpy3/lib/python3.5/site-packages/django/db/models/base.py", line 118, in __new__
"INSTALLED_APPS." % (module, name)
RuntimeError: Model class wdland.models.Device doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.
After some google search I found a solution here Django 1.9 deprecation warnings app_label see comment from Роман Арсеньев on “Jan 11 '16 at 14:54”
I went in my models.py and added “class Meta: app_label” as per above post to every single class I had in models.py. This fixed the problem and I was able to generate the documentation for my models using the sphinx-build script.
Now I wanted to do the same for views.py and did this in my .rst file
wdland\.views
=============
.. automodule:: wdland.views
:members:
:undoc-members:
:show-inheritance:
But on compile I get this new similar error and I have been unable to find a solution for it nor did understand the previous fix for models.
WARNING: /home/fabou/wdlandenvpy3/source/docs/wdland.rst:19: (WARNING/2) autodoc: failed to import module 'wdland.views'; the following exception was raised:
Traceback (most recent call last):
File "/home/fabou/wdlandenvpy3/lib/python3.5/site-packages/sphinx/ext/autodoc.py", line 657, in import_object
__import__(self.modname)
File "/home/fabou/wdlandenvpy3/source/wdland/views.py", line 2, in <module>
from . import views
File "/home/fabou/wdlandenvpy3/source/wdland/views.py", line 19, in <module>
from .forms import TicketForm, TicketAmendForm
File "/home/fabou/wdlandenvpy3/source/wdland/forms.py", line 1, in <module>
from django.contrib.auth.forms import AuthenticationForm
File "/home/fabou/wdlandenvpy3/lib/python3.5/site-packages/django/contrib/auth/forms.py", line 12, in <module>
from django.contrib.auth.models import User
File "/home/fabou/wdlandenvpy3/lib/python3.5/site-packages/django/contrib/auth/models.py", line 6, in <module>
from django.contrib.contenttypes.models import ContentType
File "/home/fabou/wdlandenvpy3/lib/python3.5/site-packages/django/contrib/contenttypes/models.py", line 139, in <module>
class ContentType(models.Model):
File "/home/fabou/wdlandenvpy3/lib/python3.5/site-packages/django/db/models/base.py", line 118, in __new__
"INSTALLED_APPS." % (module, name)
RuntimeError: Model class django.contrib.contenttypes.models.ContentType doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.
Here the relevant sphinx configuration
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import django
import os
import sphinx_rtd_theme
import sys
from django.conf import settings
sys.path.insert(0, os.path.abspath('../'))
settings.configure()
django.setup()
wdland is a Django app an is listed in my INSTALLED_APPS tuple in the settings file. The sphinx docs folder is at the same level as the wdland folder.
Reading similar threads on the topic seem to point to modules that are not yet loaded when being called. I have no clue how to fix as not experienced in either sphinx and Django. Any idea on how I can fix this?
Trying to document urls.py would yield similar errors.
EDIT:
Here the begining of my view.py
import datetime
from django.core.urlresolvers import reverse
from django.db.models import Q
from django.http import Http404, HttpResponse
from django.template.loader import render_to_string
from django.shortcuts import render, HttpResponseRedirect
from django.views import generic
from random import randint
from script.serversnmp import get_ubuntu_snmp, get_esxi_snmp
from script.wdlandtools import get_monthly_sess_hour_stats,\
get_monthly_sess_nb_stats,\
get_monthly_ticket_stats,\
get_ticket_category_stats,\
clean_usersession_tbl, update_usertotals_tbl,\
send_email_notification, get_adsl_usage
from wdland.models import Device, UserSession, SupportTicket, News, UserTotals,\
SavedUsrSess
from .forms import TicketForm, TicketAmendForm
from jchart import Chart
from jchart.config import Axes, DataSet, rgba
My solution was to create a BaseModel abstract class on your models.py within your app, on your error this may be:
class BaseModel(models.Model):
class Meta:
abstract = True # specify this model as an Abstract Model
app_label = 'wdland'
And made all models inherit from this instead of the usual models.Model.
To solve it, I went to the basics of trying to figure out the error message, which states:
Model class wdland.models.Device doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.
I also had the same error with a different app. Adding the requested "app_label" solved the issue.
I think you don't have django.contrib.contenttypes this in INSTALLED_APPS of django settings.So add it in INSTALLED_APPS of django settings
I'm building django application and i encounter som import problems. My file structure:
project/
my_app/
models/
__init__.py
Article.py
StockMovementProduct.py
tools/
__init__.py
Synchronizer.py
project/my_app/models/_init_.py:
from Article import *
from StockMovementProduct import *
project/my_app/models/Article.py:
from django.db import models
class Article(models.Model):
[...]
project/my_app/models/StockMovementProduct.py:
from django.db import models
from my_app.tools import Synchronizer
class StockMovementProduct(models.Model):
def sync_articles(self):
sync = Synchronizer(self)
[...]
project/my_app/tools/_init_.py is empty
project/my_app/tools/Synchronizer.py:
from my_app.models import Article
from my_app.models import StockMovementProduct
class Synchronizer():
[...]
When i run my code this error is raise:
File "/home/bux/Projets/project/my_app/models/__init__.py", line 7, in <module>
from StockMovementProduct import *
File "/home/bux/Projets/project/my_app/models/StockMovementProduct.py", line 5, in <module>
from my_app.tools import Synchronizer
File "/home/bux/Projets/project/my_app/tools/Synchronizer.py", line 2, in <module>
from my_app.models import StockMovementProduct
ImportError: cannot import name StockMovementProduct
I don't understand why (in Synchronizer.py) Article import work and StockMovementProduct import don't.
In Synchronizer.py i also try:
from my_app.models import Article
from ..models import StockMovementProduct
But without success. What i'm missing with import methodology ?
You have a circular import in your code, namely your StockMovementProduct.py imports Synchronizer.py and yet Synchronizer.py imports StockMovementProduct.py. This is a pretty common problem and there are already a lot of help on that: Circular dependency in Python.
You have a circular import. StockMovementProduct imports Synchronizer, and Synchronizer imports StockMovementProduct.
You need to re structure and maybe move the common dependancies into a 3rd file. It's difficult to suggest a solution though without knowing the content