Flask structure -- can't import application from __init__.py - python

I'm a beginner with python and I've been having a lot of trouble setting up the structure of my applications using __init__.py even after searching through several tutorials.
At the moment, my current directory structure looks like the following
/parent
/myapp
__init__.py
views.py
/virtualenv
Previously, I had (if it makes any difference)
/parent
/myapp
/bin
/include
/lib
The contents of __init__.py are below:
from flask import Flask
app = Flask(__name__)
and my views.py
from myapp import app
#app.route('/')
def test():
return 'This is a new test'
if __name__ == '__main__':
app.run(debug=True)
If myapp is being initialized with the init file, why can't I call it into the views? I get an error stating 'I cannot import app and I have no module named myapp'. If I remove the init file and copy the contents into the top of the views.py file, everything works fine.

You are using views as the main script. You cannot put a script inside a package; the directory it is in cannot be treated as such. Python adds the parent/myapp directory to the Python path, not the parent path.
Add a separate script at the top level (next to myapp):
from myapp import app
if __name__ == '__main__':
app.run(debug=True)
and add an import to __init__.py to import your views:
from flask import Flask
app = Flask(__name__)
import views
and remove the if __name__ == '__main__': block from views.py.

Related

Flask can't route to certain url with blueprint

I am trying to organize my flask project, but there's something wrong.
I have this directory:
app/
__init__.py
views/
pages.py
On my __init__.py file I've imported the pages object and
registered it as a blue print.
This is the code on my pages.py file.
from flask import Blueprint, render_template
pages = Blueprint('pages', __name__) #no prefix
#pages.route('/')
def index():
return '<h1>in index.html</h1>'
#pages.route('/home')
def home():
return '<h1>in home.html</h1>'
If I run the flask app, open the browser, and go to localhost:5000,
I will see the headline 'in index.html'.
But if I go to localhost:5000/home, I will get the message 404 Not Found message.
Does anyone know the reason for this behavior?
Ok, first the folder structure:
app/
__init__.py
main.py
views/
__init__.py
test.py
Contents of main.py:
from flask import Flask
from views.test import pages
app = Flask(__name__)
app.register_blueprint(pages) <-- blueprint registration
Contents of test.py:
from flask import Blueprint
pages = Blueprint('pages', __name__) #no prefix
#pages.route('/')
def index():
return '<h1>in index.html</h1>'
#pages.route('/home')
def home():
return '<h1>in home.html</h1>'
I believe the register_blueprint was the only thing missing.
When stuff like that happen, just turn off everything, reset your computer.
Sometimes the bug is not yours.

Import statement flow

My app layout
my_app
__init__.py
my_app
__init__.py
startup
__init__.py
create_app.py
create_users.py
common_settings.py
core
__init__.py
models.py
views.py
errors
__init__.py
errors.py
Inner __init__.py
from flask import Flask
from flask_script import Manager
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__) # The WSGI compliant web application object
db = SQLAlchemy(app) # Setup Flask-SQLAlchemy
manager = Manager(app) # Setup Flask-Script
from my_app.startup.create_app import create_app
create_app()
create_app.py
def create_app(extra_config_settings={}):
# Load all blueprints with their manager commands, models and views
from my_app import core
return app
core/__init__.py
# from . import views
views.py
from my_app import app, db
from flask import Flask, request
#app.errorhandler(Error)
def handle_invalid_usage(error):
response = jsonify(data=error.to_dict())
response.status_code = error.status_code
return response
I based this code on a tutorial I found. Everything works fine as long as I leave the __init__.py in the core folder empty.
When I don't, I get a NameError: name Error is not defined in my views.py. Error comes from errors.py.
I have three questions:
1) Why does this happen only when I leave the import statement in core/__init__.py.
2)
create_app.py
app.config.from_envvar('ENV_SETTINGS_FILE')
# Other app.config commands here
from my_app import core
return app
What happens when from my_app import core runs?
3) Finally when I return app, is this to ensure that Inner __init__.py file contains the updated app object?
Any explanations would be greatly appreciated!
Trying to build and configure an app with dynamic imports is really bad news and confusing for the reasons you are discovering. A much better and understandable pattern would be a more typical factory:
def create_app():
app = Flask(__name__)
configure_app(app, config)
register_db(app)
add_views(app)
add_manager(app)
return app
if __name__ == '__main__':
app = create_app()
app.run()
But since you're asking, your problem is here:
from my_app import app, db
from flask import Flask, request
#app.errorhandler(Error) # Error is not imported
def handle_invalid_usage(error):
response = jsonify(data=error.to_dict())
response.status_code = error.status_code
return response
The error occurs because views.py is imported, the code compiler comes across Error and cannot find a reference to it.
For your second question: from my_app import core causes core.__init.__ to run, which (presumably) adds the views onto the app object.

Flask unable to find templates

My project structure is like below
run.py
lib/
mysite/
conf/
__init__.py (flask app)
settings.py
pages/
templates/
index.html
views.py
__init__.py
This is mysite.conf.__init__
from flask import Flask
app = Flask(__name__)
app.debug = True
My idea is to now import app to every other module to use it to create views. Here in this case there is a module pages.
In pages.views I have some code like
from flask import render_template
from mysite.conf import app
#app.route('/')
def index():
return render_template('index.html')
The index.html is placed in pages/templates
When I run this app from run.py which is like below
from mysite.conf import app
app.run()
I'm getting template not found error.
How to fix it? and why is this happening!
I'm basically a django guy, and facing a lot of inconvenience with importing the wsgi object every time to create a view in every module! It kinda feels crazy -- Which in a way encourages circular imports. Is there any way to avoid this?
Flask expects the templates directory to be in the same folder as the module in which it is created; it is looking for mysite/conf/templates, not mysite/pages/templates.
You'll need to tell Flask to look elsewhere instead:
app = Flask(__name__, template_folder='../pages/templates')
This works as the path is resolved relative to the current module path.
You cannot have per-module template directories, not without using blueprints. A common pattern is to use subdirectories of the templates folder instead to partition your templates. You'd use templates/pages/index.html, loaded with render_template('pages/index.html'), etc.
The alternative is to use a Blueprint instance per sub-module; you can give each blueprint a separate template folder, used for all views registered to that blueprint instance. Do note that all routes in a blueprint do have to start with a common prefix unique to that blueprint (which can be empty).
I ran in to this problem as well being brand new to Flask.
The solution for my situation was to create an __init__.py file in the main app directory so as to turn app/ in to a module since, as Martijn Pieters pointed out, flask expects templates to be in the main module directory by default. And to restate from his answer, you can reassign the default directory when instantiating the Flask class, e.g. Flask(__name__, template_folder=any/relative/path/from/app/dir/or/absolute/path/youd/like)
A simple directory structure should therefore look like this:
app/
run.py
templates/
sample_template.html
__init__.py # <---- This was the missing file in my case.
... where app.py might look like this:
from flask import Flask, render_template
app = Flask(__name__) # or e.g. Flask(__name__, template_folder='../otherdir')
#app.route("/")
def home():
return "Hello world"
#app.route("/hello/again")
def hello_again():
return render_template("hello_again.html")
if __name__ == "__main__":
app.run()
I'm pretty sure you made a mistaking spelling "template" on main folder. Just rename it
or:
do something like this (template_folder = 'the name of the folder your file belongs to')
from flask import Blueprint
from flask import render_template
views = Blueprint('views',__name__,template_folder='tamplate')
#views.route('/')
def home():
return render_template("home.html")

Running the flask/python code in linux? Basic flask code

I have been learning flask/ python from this tutorial http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world
This blog is pretty good and it explain very well. In the first tutorial, if you notice,
he asks us to create a init.py file, a views.py file and a main run.py file.
root
/microblog
/apps
/__init__.py
views.py
I created the two files. He asks us to create a run.py file and put it in the root file. then
chmod a+x run.py
./run.py
It says the file does not exist.
If I,
python run.py
It says App module not defined.
I cannot figure out the problem, I put the run.py file in all the files, it doesnt not work what so ever.
I will also include the code so that it would be easier to answer instead of going to the above link
init.py
from flask import Flask
app = Flask(__name__)
from app import views
views.py
from app import app
#app.route('/')
#app.route('/index')
def index():
return 'Hello world'
run.py
#!flask/bin/python
from app import app
app.run(debug = True)
My questions:
Where should I put the run.py file?
Why are we creating different files? Why cant all of them be in one
full file?
init.py -->
he is importing flask which is normal. then assigning app =
(name). why is that? Then why is he importing views from apps?
views.py -->
from app import app? is app an existing module here or the one we
just created? what does #app.route('/') or
#app.route('/index')do?
Can some one put the code together and explain it?
It says App module not defined
You misspelled package name: you have apps in your directory tree and you try to import app
Where should I put the run.py file?
Anywhere you want as long app is in PYTHONPATH. Or you can put it inside microblog directory.
he is importing flask which is normal. then assigning app = (name). why is that?
# Create reference to flask WSGI application object
app = Flask(__name__)
Why? Because you need application to run. See official docs: Flask object
Then why is he importing views from apps?
from app import views
means: From package named app import module named views
Naming convention could be probably different but if you don't see the difference you should probably spend more learning python basics before starting with more sophisticated stuff.
from app import app? is app an existing module here or the one we just created? what > does #app.route('/') or #app.route('/index')do?
#app.route('/')
def index():
return 'Hello world'
Short answer: if app receives request for url '/' responds using function foo
For more see official docs: add_url_rule and URL Route Registrations
Update
Why are we creating different files? Why cant all of them be in one full file?
Actually nothing stops you from putting everything inside one file but most of the time it is really bad idea. If you ask about reasoning in this specific example it is mostly about separating modules that have different responsibilities.

How does python import order affect names?

I'm doing a flask tutorial (http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world) and I came upon a behaviour that I couldn't explain.
The main directory structure of the tutorial is :
microblog
|
|---- app
| |---- __init__.py
| |---- views.py
|
|---- flask
|---- run.py
and the contents of the files are :
microblog/run.py
#!flask/bin/python
from app import app
app.run(debug=True)
microblog/app/init.py
from flask import Flask
app = Flask(__name__)
from app import views
microblog/app/views.py
from app import app
#app.route("/")
#app.route("/index")
def index():
return "Hello World!"
everything works but if I transpose these two lines:
app = Flask(__name__)
from app import views
in views.py and then I execute run.py I get:
ImportError: cannot import name app
Why does that happen?
Because you're trying to import from the newly created variable app. If you want to import variable modules, then use importlib package:
my_module = importlib.import_module(app, 'view')
Contrary to what the other answer says, this is a circular import problem. app.__init__ tries to import app.views, which tries to import the app.app Flask created in app.__init__. If the Flask is created before app.__init__ imports app.views, app.views finds app.app. If the Flask is created after the import, it isn't there yet when app.views tries to find it.
Circular imports cause all sorts of horrible problems. It might be difficult, but the best way to handle them is generally to reorganize your code so there aren't circular imports.

Categories

Resources