flask url_for() treats argument like a query string
flask, python
Solution
You've made a mistake that newer issues of Flask will actually throw an error to let you know about it. When I ran this with Flask 10.1, I get the following error:
Traceback (most recent call last):
File "flask_app.py", line 33, in <module>
methods=['POST'])
File "/home/mark/temp/test/local/lib/python2.7/site-packages/flask/app.py", line 62, in wrapper_func
return f(self, *args, **kwargs)
File "/home/mark/temp/test/local/lib/python2.7/site-packages/flask/app.py", line 984, in add_url_rule
'existing endpoint function: %s' % endpoint)
AssertionError: View function mapping is overwriting an existing endpoint function: c
The issue is with endpoints, and specifically how you are naming them. When you do `url_for('c', code='O7A')`, the first argument you provide is the "endpoint". Basically, it is a string that uniquely identifies a URL rule.
Most times, you don't actually specify the endpoint, because Flask magically does that for you; if you don't provide the endpoint, Flask will use the name of the function that was passed to the `view_func` argument. In your case, you are using the `MethodView` helper, so really, the endpoint is the argument that you pass to `as_view`. Thus, when you do..
app.add_url_rule('/c/<code>',
view_func=C.as_view('c'),
methods=['GET'])
...you are saying that you want to define a route `/c/<code>`, with the specified view func, and only allow requests on that route with the GET method. Because you don't specify an endpoint, Flask assigns an endpoint to it (the argument of `as_view`) of `c`.
Next you have this....
app.add_url_rule('/c/',
view_func=C.as_view('c'),
methods=['POST'])
...which does almost the exact same thing. Thus, it ALSO tries to define this route to have the endpoint of `c`. This means that the new endpoint will be overriding the old endpoint!
To resolve this, you should pick different endpoint names, like the following...
app.add_url_rule('/c/<code>',
view_func=C.as_view('c_GET'),
methods=['GET'])
app.add_url_rule('/c/',
view_func=C.as_view('c_POST'),
methods=['POST'])
Then, when you do your `url_for` call, you can do...
print url_for('c_GET', code='O7A')
Problem
Because 'code' is an argument to the get method of the MethodView class C below, when I call url_for('c', code='O7A'), I expect the resulting url to be : /c/O7A Instead of the expected value, I'm seeing this: /c/?code=O7A ``` from flask import Flask, url_for from flask.views import MethodView app = Flask(__name__) class B(MethodView): def get(self): return 'ok' def post(self): print url_for('c', code='O7A') return 'ok' app.add_url_rule('/b', view_func=B.as_view('b'), methods=['GET', 'POST']) class C(MethodView): def get(self, code): return 'ok' def post(self): return 'ok' app.add_url_rule('/c/<code>', view_func=C.as_view('c'), methods=['GET']) app.add_url_rule('/c/', view_func=C.as_view('c'), methods=['POST']) print app.url_map if __name__ == "__main__": app.run() ```