0

I am a bit confused on how to utilize blueprints in flask. Let me show you what I would like to do:

First of all, my project must have the following structure:

run.py
application
-- __init.py__
-- admin
-- -- templates
-- -- -- index.html
-- -- static
-- -- -- img
-- -- -- -- logo.png
-- -- models.py 
-- -- views.py 
-- landing
-- -- templates
-- -- -- index.html
-- -- static
-- -- -- img
-- -- -- -- logo.png
-- -- models.py 
-- -- views.py 

What I would like to do is define two blueprints in such a way that when I visit /admin the application/admin/templates/index.html page (and the corresponding logo) gets loaded but when I visit /landing the application/landing/templates/index.html page (and the corresponding logo) gets loaded.

This shouldn't be that difficult but I get confused for some reason.

Any help is appreciated!

EDIT

more specifically, does the following use of blueprints and jinja2 make sense? it doesn't seem to work as expected...

    $.backstretch([
        "{{ url_for('landing.static' , filename='img/bg/01.jpg') }}", 
        "{{ url_for('landing.static' , filename='img/bg/02.jpg') }}",
        "{{ url_for('landing.static' , filename='img/bg/03.jpg') }}"
    ], {duration: 3000, fade: 750});

    127.0.0.1 - - [31/Aug/2015 16:47:42] "GET /%7B%7B%20url_for('landing.static'%20,%20filename='img/bg/01.jpg')%20%7D%7D HTTP/1.1" 404 -
    127.0.0.1 - - [31/Aug/2015 16:47:42] "GET /%7B%7B%20url_for('landing.static'%20,%20filename='img/bg/02.jpg')%20%7D%7D HTTP/1.1" 404 -
    127.0.0.1 - - [31/Aug/2015 16:47:42] "GET /%7B%7B%20url_for('landing.static'%20,%20filename='img/bg/03.jpg')%20%7D%7D HTTP/1.1" 404 -
user706838
  • 5,132
  • 14
  • 54
  • 78

1 Answers1

7

The following files should help you achieve what you want:

run.py

from application.admin import admin
from application.landing import landing

from flask import Flask
app = Flask(__name__)

# Register the blueprints
app.register_blueprint(admin)
app.register_blueprint(landing)

app.debug = True

print app.url_map

app.run(host='0.0.0.0')

application/landing/init.py

from flask import Blueprint

landing = Blueprint('landing', __name__, template_folder='templates', url_prefix='/landing', static_folder='static')

from application.landing import views

application/admin/init.py

from flask import Blueprint

admin = Blueprint('admin', __name__, template_folder='templates', url_prefix='/admin', static_folder='static')

from application.admin import views

application/landing/views.py

from application.landing import landing

from flask import render_template


@landing.route('/')
def get_landing_index():
    return render_template('landing/index.html')

application/admin/views.py

from application.admin import admin

from flask import render_template


@admin.route('/')
def get_admin_index():
    return render_template('admin/index.html')

You should get the following routes:

<Rule '/landing/' (HEAD, OPTIONS, GET) -> landing.get_landing_index>,
<Rule '/admin/' (HEAD, OPTIONS, GET) -> admin.get_admin_index>,
<Rule '/landing/static/<filename>' (HEAD, OPTIONS, GET) -> landing.static>,
<Rule '/admin/static/<filename>' (HEAD, OPTIONS, GET) -> admin.static>,
<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>]

Note however that you would have to change the path at which you store your templates. The templates are located in:

  • /application/landing/templates/landing/index.html
  • /application/admin/templates/admin/index.html

Repeating the blueprint name in the templates folder is here to mitigate the bug/feature described here. If the templates share the same name (e.g. index.html), even though they are in different blueprints, one of them would always take precedence. More information in the link given above.

For info regarding how to link static files in templates when used together with blueprints, /application/admin/templates/admin/index.html may look like:

<!DOCTYPE html>
<html>
<head>
    <title>Admin page</title>
</head>
<body>
<h1>Welcome to Admin</h1>
<img src="{{ url_for('admin.static', filename='cat.jpg') }}"/>
</body>
</html>

The file cat.jpg would be available in /application/admin/static/cat.jpg. For landing, the template /application/landing/templates/landing/index.html could be made in the same way:

<!DOCTYPE html>
<html>
<head>
    <title>Landing page</title>
</head>
<body>
<h1>Welcome to Landing</h1>
<img src="{{ url_for('landing.static', filename='cat.jpg') }}"/>
</body>
</html>

The file cat.jpg would be stored in /application/landing/static/cat.jpg. No need to repeat the blueprint name here below /static/ as url_for() already gets it as argument.

Finally, don't forget to add __init__.py files wherever they are needed.

Community
  • 1
  • 1
Nicolas
  • 2,151
  • 1
  • 25
  • 29
  • hi, thanks for your answer (I'll mark your answer as correct - although I had already solved it based on the provided link). However, I don't see how to use blueprints/jinja2 within javascript. can you please give me some help? see my edit. – user706838 Aug 31 '15 at 13:26
  • It depends on how you serve your JS files: if they are static JS files (i.e. not rendered prior to delivery), you should go with absolute URLs (e.g. `/landing/static/img/bg/01.jpg` - notice the leading `/`). Otherwise, add logic to preprocess your JS scripts to render the Jinja2 markup they contain (and use the `{{ url_for() }}` function in your JS files) by serving them through a dedicated endpoint. Both are valid approches I think, but I prefer the first one. – Nicolas Aug 31 '15 at 13:43
  • I prefer the `url_for` solution but, again, doesn't look like to work.... I have updated my edit with the output for the debugger. please have a look if you don't mind. – user706838 Aug 31 '15 at 13:52
  • As I said, you need to create a dedicated endpoint to serve your JS files as if they were (because that's what they are after all here) templates: create a `/application/landing/templates/landing/js` folder, put your JS file in it (e.g. `index.js`) and create an endpoint to render the JS prior to serving it (in `/application/landing/views.py`): @landing.route('/js/') def get_rendered_js(filename): return render_template('landing/js/{filename}'.format(filename=filename)) And then, reference your JS file as `/landing/js/index.js`. – Nicolas Aug 31 '15 at 14:10
  • sorry, just to be clear: I have already made it work (just before you answer). in other words, I used `{{ url_for() }}` extensively in html files (templates) but I cannot use it (as you see in the debug output above) in javascript files. so, now, my problem is very specific. it doesn't have to do with blueprints (in general). any ideas? – user706838 Aug 31 '15 at 14:19