I have a flask app.
app.py
app = Flask(__name__)
from views import *
if __name__=="__main__":
app.run()
views.py
from app import app
#app.route('/')
def home():
return "Homepage"
So, here app.py is importing everything form views.py and views need app which is defined in app.py. But still its not causing circular import. Why?
I run this application using:
python app.py
This looks similar to the Larger Applications document which Flask allows you to do when creating apps.
From the docs:
Circular Imports
Every Python programmer hates them, and yet we just added some: circular imports (That’s when two modules depend on each other. In this case views.py depends on __init__.py). Be advised that this is a bad idea in general but here it is actually fine. The reason for this is that we are not actually using the views in __init__.py and just ensuring the module is imported and we are doing that at the bottom of the file.
If we try to follow what the program does, it is something like that:
app = Flask(__name__) # OK
from views import * # Goes into views.py
from app import app # Looks into app.py, finds it, import it
# Defines home
#app.route('/')
def home():
return "Homepage"
# import home and app, overriding app in app.py
# But views.app is the same as app.app, so it is still
# the same object
# Run main
if __name__=="__main__":
app.run()
I bet it computes something like that. Since app is defined before being imported, it's ok.
Related
I am taking over a Flask application that has a user module, but does not have a landing page. The structure of the project is:
|-application.py
|-manage.py
|-settings.py
|-/templates
|----base.html
|----index.html
|----navbar.html
|----/user
|--------views.py
application.py:
from flask import Flask
....
def create_app(**config_overrides):
app = Flask(__name__)
app.config.from_pyfile('settings.py')
app.config.update(config_overrides)
db.init_app(app)
from user.views import user_app
app.register_blueprint(user_app)
return app
user/views.py:
from flask import Blueprint, render_template, request, redirect, session, url_for, abort
...
user_app = Blueprint('user_app', __name__)
#user_app.route('login', methods = ('GET','POST'))
def login():
....
I placed index.html in the templates folder.
Should I place a view.py in the root directory where I would put a route to an index.html?
You can add additional routes anywhere you want.
However, since the package uses a create_app() app factory, you can't register those routes with an #app.route() decorator; the app is not created in a way you can just import.
So yes, creating a views.py module is a good organisational idea, but do create a Blueprint() there too, and register that blueprint in the create_app() function with the Flask() app instance.
In views.py:
from flask import Blueprint
bp = Blueprint('main', __name__)
#main.route('/')
def index():
# produce a landing page
and in create_app() in application.py, add
import views
app.register_blueprint(views.bp)
(I use a convention of using the bp variable name for all my blueprints, and then just importing the module and registering the module.bp attribute).
It's the explicit import and app.register_blueprint() call that ties any of the blueprints used in a Flask project into the final app's routes. Blueprints can share the same prefix, including having no prefix.
One thing to note: here the views module is now a top-level module next to application.py. It'd be better if everything was moved into a package, giving you more freedom over what names you use. All modules in a single package are namespaced, kept separate from other top-level modules such as json and time and flask, so there won't be clashes when you want to use the same name for one of the additional modules in your project.
You'd move everything but manage.py into a subdirectory, with a project-appropriate name, and move application.py to __init__.py. Imports can then use from . import ... to import from the current package, etc.
Directory Structure:
__init__:
from flask import flask
app = Flask(__name__)
if __name__ == '__main__'
app.run()
Views:
from app import app
#app.route('/')
def hello_world():
return 'Hello World!'
I hope someone can explain what I am doing wrong here -
I guess I'm not understanding how to properly import app. This results in a 404. However when views is moved back to __init__ everything works properly.
You need to explicitly import your views module in your __init__:
from flask import flask
app = Flask(__name__)
from . import views
Without importing the module, the view registrations are never made.
Do keep the script portion outside of your package. Add a separate file in Final_app (so outside the app directory) that runs your development server; say run.py:
def main():
from app import app
app.run()
if __name__ == '__main__'
main()
The problem is that IntelliJ Studio 13 doesn't want to recognize an import. I have my code like this
a folder named "app". Inside it
__init__.py
from flask import Flask
app = Flask(__name__)
from app import views, models
views.py
from flask import render_template, request
from models import *
from app import *
#app.route('/')
#app.route('/index')
def index():
return "123"
Now in views.py the "from app import *" is greyed as unused, and there's a red warning under #app with "unresolved reference "app".
Can anyone explain me why is this happening and what's the fix for this. Thanks in advance
from app import * will import the package contents into the current namespace. So the route function from the app package will be imported into the current namespace. Callable as route().
import app will import the app package into the current namespace as an object named app. Callable as app.route()
Generally the use of from app import * is frowned upon unless you are certain it is what you want to do. from app import route would be preferred.
I'm having trouble understanding how to split a flask app into multiple files.
I'm creating a web service and I want to split the api's into different files (AccountAPI.py, UploadAPI.py, ...), just so I don't have one huge python file.
I've read that you can do this with Blueprints, but I'm not entirely sure that route is the right one for me.
Ultimately I want to run one Main python file and include other files so that when it runs, they are considered one big file.
For example if I have Main.py and AccountAPI.py I want to be able to do this:
Main.py:
from flask import Flask
import AccountAPI
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
AccountAPI.py:
#app.route("/account")
def accountList():
return "list of accounts"
I know with this example it obviously won't work, but is it possible to do something like that?
Thanks
Yes, Blueprints are the right way to do it. What you are trying to do can be achieved like this:
Main.py
from flask import Flask
from AccountAPI import account_api
app = Flask(__name__)
app.register_blueprint(account_api)
#app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
AccountAPI.py
from flask import Blueprint
account_api = Blueprint('account_api', __name__)
#account_api.route("/account")
def accountList():
return "list of accounts"
If this is an option, you might consider using different URL prefixes for the different APIs/Blueprints in order to cleanly separate them. This can be done with a slight modification to the above register_blueprint call:
app.register_blueprint(account_api, url_prefix='/accounts')
For further documentation, you may also have a look at the official docs.
Using Blueprint you can add your routes in the routes directory.
Structure
app.py
routes
__init__.py
index.py
users.py
__init__.py
from flask import Blueprint
routes = Blueprint('routes', __name__)
from .index import *
from .users import *
index.py
from flask import render_template
from . import routes
#routes.route('/')
def index():
return render_template('index.html')
users.py
from flask import render_template
from . import routes
#routes.route('/users')
def users():
return render_template('users.html')
app.py
from routes import *
app.register_blueprint(routes)
If you want to add a new route file, say accounts.py, you just need to create the file accounts.py in the routes directory, just like index.py and users.py, then import it in the routes.__init__.py file
from .accounts import *
If you are using blueprints and want to route / redirect to a url of your blueprint inside a template you are using you need to use the correct url_for statement.
In your case if you would like to open the url account of your blueprint you have to state it like this in your template:
href="{{ url_for('account_api.account') }}"
and for the main app it would look like this:
redirect(url_for('account_api.account'))
Otherwise the werkzeug library will throw an error.
One another way to do this can be with lazy loading, where you would explicitly attach view functions on need basis.
My File Directory:
app/
app.py
app/server/
views.py
I don't get any import errors with views, but I am not able to URL route to Views - I can only do it from app.py - how can I fix this issue? I've been stuck on this for 6 hours.
Code from app.py - how I import views
sys.path.append(os.path.join(os.path.abspath('.'), 'server'))
import views
And my url routing seems fine, so I am not sure where the problem lies:
#app.route("/login/", methods=['GET', 'POST'])
def login():
doSomething()
I feel the problem is more to do with url routing than importing files though.
Try from views import * instead of import views.
Also, instead of doing sys.path.append, add an empty file named __init__.py to the server directory, and you should be able to do something like from server.views import *.
Solution: Also make sure your view import is towards the bottom of your app file, below the app initialization and config and such.