I am developing a rather big project in pyramid. I used django before. I really like the way it structures the project and encapsulate functionality into apps. I would like to achieve same structure with pyramid. I know pyramid is very flexible to get this, but I need some help to achieve same structure with loose coupling. The project structure should look something like:
Project/
app1/
models.py
routes.py
views.py
app2/
models.py
routes.py
views.py
Any suggestions?
Since Pyramid makes no assumptions about your package structure in the first place, any way you divide your app ends up being fairly similar in configuration. However, if you're breaking your app into some distinct packages, you can (optionally) take advantage of the config.include() directive to include each package into your main config.
For example:
# myapp/__init__.py (main config)
def main(global_config, **settings):
config = Configurator(...)
# basic setup of your app
config.include('pyramid_tm')
config.include('pyramid_jinja2')
# add config for each of your subapps
config.include('project.app1')
config.include('project.app2')
# make wsgi app
return config.make_wsgi_app()
# myapp/app1/__init__.py (app1's config)
def includeme(config):
config.add_route(...)
config.scan()
# myapp/app2/__init__.py (app2's config)
def includeme(config):
config.add_route(...)
config.scan()
In each of your subapps, you can then define views/models/etc.
In general you might want to create your SQLAlchemy (or other DB) session in the common setup, as likely your different apps are all using the same engine.
I have implemented a global appIncluder function which is imported as includeme with the init.py of the package to be included.
includeme (ApplicationIncluder) receives the config object, so it is then easy to use config.package and its variables/methods/classes (present in the same init.py and submodules.
Thanks a lot for this idea!
The code:
project: 'foo'
apps to be deployed in foo.foo.apps directory
Structure:
foo
|-foo
|- __init__.py
|- appincluder.py
|-apps
|-test
|- __init__.py
|- views.py
|- templates
|- test.jinja2
foo/foo/init.py:
config.include('foo.apps.test')
foo/foo/appincluder.py
def appIncluder(config):
app = config.package
prefix = app.prefix
routes = app.routes
for route,url in routes.items():
config.add_route(route,prefix + url)
config.scan(app)
log.info('app: %s included' % app.__name__)
foo/foo/apps/test/init.py
from foo.appincluder import appIncluder as includeme
prefix = '/test'
routes = {
'test': '/home'
}
foo/foo/apps/test/views.py
from pyramid.view import view_config
#view_config(route_name='test', renderer='templates/test.jinja2')
def test(request):
return {}
I hope it helps someone.
Related
I am trying to render the file home.html. The file exists in my project, but I keep getting jinja2.exceptions.TemplateNotFound: home.html when I try to render it. Why can't Flask find my template?
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/')
def home():
return render_template('home.html')
/myproject
app.py
home.html
You must create your template files in the correct location; in the templates subdirectory next to the python module (== the module where you create your Flask app).
The error indicates that there is no home.html file in the templates/ directory. Make sure you created that directory in the same directory as your python module, and that you did in fact put a home.html file in that subdirectory. If your app is a package, the templates folder should be created inside the package.
myproject/
app.py
templates/
home.html
myproject/
mypackage/
__init__.py
templates/
home.html
Alternatively, if you named your templates folder something other than templates and don't want to rename it to the default, you can tell Flask to use that other directory.
app = Flask(__name__, template_folder='template') # still relative to module
You can ask Flask to explain how it tried to find a given template, by setting the EXPLAIN_TEMPLATE_LOADING option to True. For every template loaded, you'll get a report logged to the Flask app.logger, at level INFO.
This is what it looks like when a search is successful; in this example the foo/bar.html template extends the base.html template, so there are two searches:
[2019-06-15 16:03:39,197] INFO in debughelpers: Locating template "foo/bar.html":
1: trying loader of application "flaskpackagename"
class: jinja2.loaders.FileSystemLoader
encoding: 'utf-8'
followlinks: False
searchpath:
- /.../project/flaskpackagename/templates
-> found ('/.../project/flaskpackagename/templates/foo/bar.html')
[2019-06-15 16:03:39,203] INFO in debughelpers: Locating template "base.html":
1: trying loader of application "flaskpackagename"
class: jinja2.loaders.FileSystemLoader
encoding: 'utf-8'
followlinks: False
searchpath:
- /.../project/flaskpackagename/templates
-> found ('/.../project/flaskpackagename/templates/base.html')
Blueprints can register their own template directories too, but this is not a requirement if you are using blueprints to make it easier to split a larger project across logical units. The main Flask app template directory is always searched first even when using additional paths per blueprint.
I think Flask uses the directory template by default. So your code should be like this
suppose this is your hello.py
from flask import Flask,render_template
app=Flask(__name__,template_folder='template')
#app.route("/")
def home():
return render_template('home.html')
#app.route("/about/")
def about():
return render_template('about.html')
if __name__=="__main__":
app.run(debug=True)
And you work space structure like
project/
hello.py
template/
home.html
about.html
static/
js/
main.js
css/
main.css
also you have create two html files with name of home.html and about.html and put those files in templates folder.
If you must use a customized project directory structure (other than the accepted answer project structure),
we have the option to tell flask to look in the appropriate level of the directory hierarchy.
for example..
app = Flask(__name__, template_folder='../templates')
app = Flask(__name__, template_folder='../templates', static_folder='../static')
Starting with ../ moves one directory backwards and starts there.
Starting with ../../ moves two directories backwards and starts there (and so on...).
Within a sub-directory...
template_folder='templates/some_template'
I don't know why, but I had to use the following folder structure instead. I put "templates" one level up.
project/
app/
hello.py
static/
main.css
templates/
home.html
venv/
This probably indicates a misconfiguration elsewhere, but I couldn't figure out what that was and this worked.
If you run your code from an installed package, make sure template files are present in directory <python root>/lib/site-packages/your-package/templates.
Some details:
In my case I was trying to run examples of project flask_simple_ui and jinja would always say
jinja2.exceptions.TemplateNotFound: form.html
The trick was that sample program would import installed package flask_simple_ui. And ninja being used from inside that package is using as root directory for lookup the package path, in my case ...python/lib/site-packages/flask_simple_ui, instead of os.getcwd() as one would expect.
To my bad luck, setup.py has a bug and doesn't copy any html files, including the missing form.html. Once I fixed setup.py, the problem with TemplateNotFound vanished.
I hope it helps someone.
Check that:
the template file has the right name
the template file is in a subdirectory called templates
the name you pass to render_template is relative to the template directory (index.html would be directly in the templates directory, auth/login.html would be under the auth directory in the templates directory.)
you either do not have a subdirectory with the same name as your app, or the templates directory is inside that subdir.
If that doesn't work, turn on debugging (app.debug = True) which might help figure out what's wrong.
I had the same error turns out the only thing i did wrong was to name my 'templates' folder,'template' without 's'.
After changing that it worked fine,dont know why its a thing but it is.
You need to put all you .html files in the template folder next to your python module. And if there are any images that you are using in your html files then you need put all your files in the folder named static
In the following Structure
project/
hello.py
static/
image.jpg
style.css
templates/
homepage.html
virtual/
filename.json
When render_template() function is used it tries to search for template in the folder called templates and it throws error jinja2.exceptions.TemplateNotFound when :
the file does not exist or
the templates folder does not exist
Create a folder with name templates in the same directory where the python file is located and place the html file created in the templates folder.
Another alternative is to set the root_path which fixes the problem both for templates and static folders.
root_path = Path(sys.executable).parent if getattr(sys, 'frozen', False) else Path(__file__).parent
app = Flask(__name__.split('.')[0], root_path=root_path)
If you render templates directly via Jinja2, then you write:
ENV = jinja2.Environment(loader=jinja2.FileSystemLoader(str(root_path / 'templates')))
template = ENV.get_template(your_template_name)
After lots of work around, I got solution from this post only,
Link to the solution post
Add full path to template_folder parameter
app = Flask(__name__,
template_folder='/home/project/templates/'
)
My problem was that the file I was referencing from inside my home.html was a .j2 instead of a .html, and when I changed it back jinja could read it.
Stupid error but it might help someone.
Another explanation I've figured out for myself
When you create the Flask application, the folder where templates is looked for is the folder of the application according to name you've provided to Flask constructor:
app = Flask(__name__)
The __name__ here is the name of the module where application is running. So the appropriate folder will become the root one for folders search.
projects/
yourproject/
app/
templates/
So if you provide instead some random name the root folder for the search will be current folder.
I'm trying to learn flask by creating a simple blog web site. My file structure for my project looks like this:
flaskBlog
setup.py
flaskBlog
__init__.py
views.py
templates
index.html
So I've got my templates directory at the same level as my __init__.py and views.py which looks like this:
# __init__.py
from flask import Flask
app = Flask('__name__')
import flaskBlog.views
# views.py
from flaskBlog import app
from flask import render_template
#app.route('/')
def index():
return render_template('index.html')
When I use flask run it starts like normal and tells me its running on localhost:5000, but when I try to navigate to it I get a jinja error saying jinja2.exceptions.TemplateNotFound index.html. Every similar question I've seen on here is answered by saying to ensure that my app and my templates folder are on the same level but I'm still getting this error. Why can't the index template be found?
You can either put the templates dir a level up (next to your blog app) or you can define the path you want to load the templates from like so:
https://flask.palletsprojects.com/en/1.1.x/api/#application-object (check the template_folder arg)
You can make your folder structure like this:
flaskBlog
templates
index.py
setup.py
flaskBlog
__init__.py
views.py
The templates folder should be in the same directory as your setup.py
I have a Flask app with blueprints. Each blueprint provides some templates. When I try to render the index.html template from the second blueprint, the first blueprint's template is rendered instead. Why is blueprint2 overriding blueprint1's templates? How can I render each blueprint's templates?
app/
__init__.py
blueprint1/
__init__.py
views.py
templates/
index.html
blueprint2/
__init__.py
views.py
templates/
index.html
blueprint2/__init__.py:
from flask import Blueprint
bp1 = Blueprint('bp1', __name__, template_folder='templates', url_prefix='/bp1')
from . import views
blueprint2/views.py:
from flask import render_template
from . import bp1
#bp1.route('/')
def index():
return render_template('index.html')
app/__init__.py:
from flask import Flask
from blueprint1 import bp1
from blueprint2 import bp2
application = Flask(__name__)
application.register_blueprint(bp1)
application.register_blueprint(bp2)
If I change the order the blueprints are registered, then blueprint2's templates override blueprint1's.
application.register_blueprint(bp2)
application.register_blueprint(bp1)
This is working exactly as intended, although not as you expect.
Defining a template folder for a blueprint only adds the folder to the template search path. It does not mean that a call to render_template from a blueprint's view will only check that folder.
Templates are looked up first at the application level, then in the order blueprints were registered. This is so that an extension can provide templates that can be overridden by an application.
The solution is to use separate folders within the template folder for templates related to specific blueprints. It's still possible to override them, but much harder to do so accidentally.
app/
blueprint1/
templates/
blueprint1/
index.html
blueprint2/
templates/
blueprint2/
index.html
Point each blueprint at its templates folder.
bp = Blueprint('bp1', __name__, template_folder='templates')
When rendering, point at the specific template under the templates folder.
render_template('blueprint1/index.html')
See Flask issue #1361 for more discussion.
I vaguely remember having trouble with something like this early on. You haven't posted all of your code, but I have four suggestions based on what you've written. Try the first, test it, and then if it still is not working, try the next ones, but independently test them to see if they work:
First, I cant't see your views.py file, so be sure you're importing the appropriate blueprint in your views.py files:
from . import bp1 # in blueprint1/views.py
from . import bp2 # in blueprint2/views.py
Second, you may need to fix the relative import statements in __init__.py as follows (note the period preceding the subfolders):
from .blueprint1 import blueprint1 as bp1
from .blueprint2 import blueprint2 as bp2
Third, since you're hardcoding the path to your templates in your render_template function, try removing template_folder='templates' from your blueprint definition.
Fourth, it looks like you named the url_prefix for your blueprint as "/bp1" when you registered it. Therefore, if the hard coded link to your file system still does not work:
render_template('blueprint1/index.html')
then also try this and see what happens:
render_template('bp1/index.html')
Again, I can't see your full code, but I hope this helps.
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")
Serve static file in bottlepy is as simple as this:
#route('statics/<filepath:path>')
def server_static(filepath):
return static_file(filepath, root='assets')
Thus the static file served should be in assets directory.
So, this one: http://127.0.0.1:8080/statics/jquery.js will refer to assets/jquery.js
So far, I don't find any problem.
But let's say, I want to make a framework with application folder contains some models, views and controllers.
The directory structure is like this:
|---applications
| |--- assets
|---start.py
|---core
|--- __init__.py
In core/__init__.py I put a function to run bottle and route assets directory
from bottle import route, run, static_file
#route('assets/<filepath:path>')
def _serve_assets(path):
# I want the root to be dynamic, because It is not always be applications
return static_file(path, root=os.path.join('applications', 'assets'))
def framework_start(application_path = 'applications', **kwargs):
# A lot of logic
run(**kwargs)
And on start.py i do this:
from core import framework_start
framework_start(application_path = 'applications')
So far the static files served as expected. But I want it to still works even after I change the code in start.py into this:
framework_start(application_path = 'app')
and the directory structure into this
|---apps
| |--- assets
|---start.py
|---core
|--- __init__.py
So, how to do that? How to make a static routing with dynamic root?
return static_file(filename, root=filefolder)
The first argument is the name only, and the second is the folder that contains it.
You know where the docs are...
From your comments I think I got it.
If you want the template to have the path, you need to send it to bottle by something like <input type="hidden" name="arch"... and recieve it with request.GET.get('arch', '') and use it with root=....