I am writing a Flask site for which I would like to have routes like this:
@app.route('/')
@app.route('/<page_id>')
@app.route('/<page_id>/<subpage_id>')
def page(page_id=None, subpage_id=None):
...
While it seems like this should work in theory, it looks like this actually breaks static resources located in the root static/ directory. I assume the reason for this is that my dynamic route actually matches 'static/style.css' and thus overrides the normal handler for static files.
Is there any way around this? Is there a 'static' handler I can forward the request to if I detect that page_id=='static'?
Edit: Here is a working sample
@app.route('/<page_id>/<subpage_id>/<subsubpage_id>')
def xxx(page_id=None, subpage_id=None, subsubpage_id=None):
return 'hello'
If you open http://127.0.0.1:5000/static/css/style.css
now you should get a 'hello' instead of the file.
Regarding the root of your problem:
Yes. I have Page objects in my database, which I load and display based on the page_id/subpage_id/subsubpage_id when the method is called. Is there a better way to do this? I was thinking of adding separate routes for each of the pages when the app is initialized, but I could not find a good way of making that work in conjunction with url_for.
You can register route handlers directly by using app.add_url_rule
. It will use the function's name for url_for
by default, yes, but you can override that by passing an endpoint
argument.
So maybe you'd have something like this:
from functools import partial
def actual_handler(page):
return u'hello'
for page in session.query(Page):
route = u'/{0}/{1}/{2}'.format(page.id1, page.id2, page.id3)
app.add_url_rule(
route,
page.name, # this is the name used for url_for
partial(actual_handler, page=page),
)
Getting the session may or may not be tricky, and may or may not involve work like manually calling session.remove()
; I haven't tried using SQLAlchemy outside a Flask handler before. Assuming you're using SQLA in the first place.
Also see the documentation on route handling.
As for the original question of routes taking priority over static files, I genuinely don't know; based on my reading of the Flask and Werkzeug docs, that shouldn't happen. If you still wish to solve this by manually serving static files, perhaps send_from_directory
will help. Presumably your web server will serve static files directly in production, anyway, so it might not be worth the metaprogramming gunk above.
PS: An afterthought; Pyramid's traversal might be a better fit if your entire site lives in a database. It examines path components one at a time dynamically, rather than having a fixed list of static routes.
This is a horrible hack but you could probably just do something akin to:
@app.route('/<page_id>/<subpage_id>/<subsubpage_id>')
def xxx(page_id=None, subpage_id=None, subsubpage_id=None):
if page_id == 'static': # or whatever the path is to your assets
# make a response where you've filled the request yourself
return 'hello'