flask-nav
flask-nav copied to clipboard
Problem with endpoints which have multiple routes
My packages' version:
Flask (0.12)
Flask-Bootstrap (3.3.7.1)
flask-nav (0.6)
I have a function with multiple routes as below:
from flask_nav.elements import Navbar, View
from flask import Flask
from flask_nav import Nav
nav = Nav()
app = Flask(__name__)
nav.init_app(app)
@app.route('/<profile>/trang-<int:page>/order-<order>-<order_dir>/', )
@app.route('/<profile>/', defaults={'page': 1, 'order': 'sequence', 'order_dir': 'asc'}, )
def index(profile, page, order, order_dir):
...
@nav.navigation()
def mk_navbar():
...
return Navbar(
...
View(u'Home', 'index', profile=pf),
...
)
When I tried to access http://localhost:5000/kkm/trang-1/order-list_price-asc/
, I got the exception as below:
Traceback (most recent call last):
...
File "/miniconda2/envs/flecom/lib/python2.7/site-packages/flask_nav/elements.py", line 24, in render
self))
File "/miniconda2/envs/flecom/lib/python2.7/site-packages/visitor/__init__.py", line 48, in visit
return meth(node)
File "/miniconda2/envs/flecom/lib/python2.7/site-packages/flask_bootstrap/nav.py", line 53, in visit_Navbar
bar_list.add(self.visit(item))
File "/miniconda2/envs/flecom/lib/python2.7/site-packages/visitor/__init__.py", line 48, in visit
return meth(node)
File "/miniconda2/envs/flecom/lib/python2.7/site-packages/flask_bootstrap/nav.py", line 99, in visit_View
if node.active:
File "/miniconda2/envs/flecom/lib/python2.7/site-packages/flask_nav/elements.py", line 89, in active
append_unknown=not self.ignore_query)
File "/miniconda2/envs/flecom/lib/python2.7/site-packages/werkzeug/routing.py", line 806, in build
add(self._converters[data].to_url(values[data]))
KeyError: 'page'
As I tried to debug, I find the problem may lie in active
method in flask_nav/elements.py
(line 89):
@property
def active(self):
if not request.endpoint == self.endpoint:
return False
# rebuild the url and compare results. we can't rely on using get_url()
# because whether or not an external url is created depends on factors
# outside our control
_, url = request.url_rule.build(self.url_for_kwargs,
append_unknown=not self.ignore_query)
if self.ignore_query:
return url == request.path
# take query string into account.
# FIXME: ensure that the order of query parameters is consistent
return url == request.full_path
I set a breakpoint at _, url = request.url_rule.build(self.url_for_kwargs,
and inspected some variables:
>>> request.endpoint
'index'
>>> self.endpoint
'index'
>>> request.url_rule
'<Rule \\'/<profile>/trang-<page>/order-<order>-<order_dir>/\\' (HEAD, OPTIONS, GET) -> index>'
>>> self.url_for_kwargs
{'profile': u'kkm'}
So the rule requires profile
, page
, order
and order_dir
. But url_for_kwargs
only has profile
.
If I change:
_, url = request.url_rule.build(self.url_for_kwargs,
append_unknown=not self.ignore_query)
to:
url = url_for(request.endpoint, **self.url_for_kwargs, )
It would work:
>>> url = url_for(request.endpoint, **self.url_for_kwargs)
>>> url
'/kkm/'
That resolved the issue for me. However, I do not know if that would break something else.
Regards, Hieu