Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
645 views
in Technique[技术] by (71.8m points)

python - What is the correct way to solve this circular import error with a Flask blueprint?

I had a problem with a circular import, so I moved my blueprint import below my app definition. However, I'm still having an import error.

Traceback (most recent call last):
  File "/Applications/PyCharm CE.app/Contents/helpers/pydev/pydevd.py", line 2217, in <module>
    globals = debugger.run(setup['file'], None, None)
  File "/Applications/PyCharm CE.app/Contents/helpers/pydev/pydevd.py", line 1643, in run
    pydev_imports.execfile(file, globals, locals)  # execute the script
  File "/Users/benjamin/Documents/Projects/website/server/app/app.py", line 15, in <module>
    from views import site
  File "/Users/benjamin/Documents/Projects/website/server/app/views.py", line 2, in <module>
    from models import User
  File "/Users/benjamin/Documents/Projects/website/server/app/models.py", line 3, in <module>
    from database_setup import db
  File "/Users/benjamin/Documents/Projects/website/server/app/database_setup.py", line 1, in <module>
    from app import app
  File "/Users/benjamin/Documents/Projects/website/server/app/app.py", line 15, in <module>
    from views import site
ImportError: cannot import name site

If I move the blueprint import and registration to if __name__ == '__main__':, the problem goes away, but I'm not sure if this is a good idea.

if __name__ == '__main__':
    from views import site
    app.register_blueprint(site)
    app.run()

Is this the right way to solve the problem, or is there another solution?


original app.py without __main__ "fix":

from flask import Flask

app = Flask(__name__)

from views import site
app.register_blueprint(site)

if __name__ == '__main__':
    app.debug = True
    app.run()

views.py:

from flask import Blueprint, render_template

site = Blueprint('site', __name__, template_folder='templates', static_folder='static')

@site.route('/', methods=['GET', 'POST'])
def index():
    return render_template('index.html')

database_setup.py:

from app import app
from flask_mongoengine import MongoEngine

app.config['MONGODB_SETTINGS'] = {'db': 'mst_website'}    
db = MongoEngine(app)

models.py:

from database_setup import db

class User(db.Document):
    # ...

My file structure is:

/server
  |-- requirements.txt
  |-- env/ (virtual environment)
  |-- app/ (my main app folder)
       |-- static/
       |-- templates/
       |-- __init__.py
       |-- app.py
       |-- database_setup.py
       |-- models.py
       |-- views.py
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You have a circular import in your code. Based on the traceback:

  1. app.py does from views import site
  2. views.py does from models import User
  3. models.py does from database_setup import db
  4. database_setup.py does from app import app
  5. app.py does from views import site

Based on these order of events, the app.py you've posted isn't the one that's actually causing your problem. Right now, app hasn't been defined before views is imported, so when further down the chain it tries to get app, it's not available yet.

You need to restructure your project so that everything that depends on app is imported after app is defined. From your question, it seems like you think you did, but perhaps there's still an import written above app that you missed.


Probably unrelated, but you are currently using "relative" imports, which are discouraged. Rather than doing from views import site, etc., you should do an absolute path: from app.views import site, or a relative path: from .views import site.


To answer the initial question of "is using __main__ to import blueprints a good idea?", it is not. The problem with that is that the __main__ guard is only executed when you run the module directly. When you go to deploy this using a real app server such as uWSGI or Gunicorn, none of your blueprints will be imported or registered.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...