Can Flask have optional URL parameters?
Asked Answered
B

11

357

Is it possible to directly declare a flask URL optional parameter?

Currently I'm proceeding the following way:

@user.route('/<userId>')
@user.route('/<userId>/<username>')
def show(userId, username=None):
    pass

How can I directly say that username is optional?

Babbitt answered 25/12, 2012 at 15:50 Comment(0)
H
490

Another way is to write

@user.route('/<user_id>', defaults={'username': None})
@user.route('/<user_id>/<username>')
def show(user_id, username):
    pass

But I guess that you want to write a single route and mark username as optional? If that's the case, I don't think it's possible.

Hershberger answered 25/12, 2012 at 16:26 Comment(10)
Any problems using this method when referencing endpoints and url_for ?Willianwillie
Not that I know of. Even Flask docs contain similar example (you need to scroll down a bit to see it).Kopaz
You can try pip install flask_optional_routes. I created a pip for the functionality you are requesting b/c I needed it as well. The code is located at: github.com/sudouser2010/flask_optional_routes.Anthelion
upvoted! if you have multiple tabs on your home page where each one triggers something like /one /two /three /four and you want to load different content on the same page without reloading the page, should you use a single route or multiple routes?Antenatal
@Antenatal that cannot be achieved with just Flask and is purely a frontend featureEmbodiment
Possible to seperate those 2 route into 2 funcitons?Racklin
This is exactly what I needed, almost verbatimNewsprint
@user.route('/<user_id>/<username>') In this Application username is string . Like if I want to use bool(either True/False) in place of username, How is it to changeLibertylibia
This is generally OK, however it leaves you with potential for 308's to be returned when you pass in the default route param as part of the call (eg: if your username default were to be say "anonymous" and you pass that value in, you'd get a 308 redirecting to the route without a param instead of just getting a normal response back)Launalaunce
A better approach is @mogul answer below (see my comment above for why this answer isn't the best)Launalaunce
E
245

Almost the same as Audrius cooked up some months ago, but you might find it a bit more readable with the defaults in the function head - the way you are used to with python:

@app.route('/<user_id>')
@app.route('/<user_id>/<username>')
def show(user_id, username='Anonymous'):
    return user_id + ':' + username
Ebberta answered 15/5, 2013 at 15:42 Comment(3)
Also, the this works if username is not constant. defaults= freezes the default value in a dictionary.Sweatbox
Keep in mind there is a big caveat here: if you have multiple positional arguments and not all of them optional, flask won't understand how to build the URL properly. You can get something like /page?arg=foo where it should be /foo/page . @Audrius Kažukauskas answer works in that case, but this doesn'tBuckwheat
This also prevents flask redirecting with 308's when you omit the optional URI path param. ie if you use the defaults= approach with your above default value, and then specify as part of the URI the same Anonymous string as the username optional arg, you will get a 308 bouncing you to /<user_id>Launalaunce
F
90

If you are using Flask-Restful like me, it is also possible this way:

api.add_resource(UserAPI, '/<userId>', '/<userId>/<username>', endpoint = 'user')

a then in your Resource class:

class UserAPI(Resource):

  def get(self, userId, username=None):
    pass
Foolery answered 15/10, 2014 at 9:39 Comment(0)
W
35
@user.route('/<userId>/')  # NEED '/' AFTER LINK
@user.route('/<userId>/<username>')
def show(userId, username=None):
    pass

https://flask.palletsprojects.com/en/1.1.x/quickstart/#unique-urls-redirection-behavior

Wyn answered 27/1, 2015 at 9:1 Comment(0)
T
16
@app.route('/', defaults={'path': ''})
@app.route('/< path:path >')
def catch_all(path):
    return 'You want path: %s' % path

http://flask.pocoo.org/snippets/57/

Trolley answered 21/10, 2015 at 9:21 Comment(2)
You should add here the info from the external link because if that link will no longer be valid, your answer will be damaged.Love
The link is not valid anymore. Lucky us we have archive.org (web.archive.org/web/20190414194437/https://flask.pocoo.org/…)Paramour
D
15
@user.route('/<user_id>', defaults={'username': default_value})
@user.route('/<user_id>/<username>')
def show(user_id, username):
   #
   pass
Duffie answered 21/10, 2015 at 10:40 Comment(0)
D
8

Almost the same as skornos, but with variable declarations for a more explicit answer. It can work with Flask-RESTful extension:

from flask import Flask
from flask_restful import Resource, Api

app = Flask(__name__)
api = Api(app)

class UserAPI(Resource):
    def show(userId, username=None):
    pass

api.add_resource(UserAPI, '/<userId>', '/<userId>/<username>', endpoint='user')

if __name__ == '__main__':
    app.run()

The add_resource method allows pass multiples URLs. Each one will be routed to your Resource.

Dynah answered 22/5, 2019 at 5:52 Comment(0)
A
5

I know this post is really old but I worked on a package that does this called flask_optional_routes. The code is located at: https://github.com/sudouser2010/flask_optional_routes.

from flask import Flask

from flask_optional_routes import OptionalRoutes


app = Flask(__name__)
optional = OptionalRoutes(app)

@optional.routes('/<user_id>/<user_name>?/')
def foobar(user_id, user_name=None):
    return 'it worked!'

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=5000)
Anthelion answered 12/3, 2018 at 2:8 Comment(0)
S
0

You can write as you show in example, but than you get build-error.

For fix this:

  1. print app.url_map () in you root .py
  2. you see something like:

<Rule '/<userId>/<username>' (HEAD, POST, OPTIONS, GET) -> user.show_0>

and

<Rule '/<userId>' (HEAD, POST, OPTIONS, GET) -> .show_1>

  1. than in template you can {{ url_for('.show_0', args) }} and {{ url_for('.show_1', args) }}
Spherule answered 6/10, 2014 at 21:19 Comment(0)
A
-8

Since Flask 0.10 you can`t add multiple routes to one endpoint. But you can add fake endpoint

@user.route('/<userId>')
def show(userId):
   return show_with_username(userId)

@user.route('/<userId>/<username>')
def show_with_username(userId,username=None):
   pass
Avian answered 6/3, 2014 at 10:5 Comment(1)
What? Using flask 0.10.1 here and I can add multiple routes to one endpoint just fine.Coincidentally
M
-11

I think you can use Blueprint and that's will make ur code look better and neatly.

example:

from flask import Blueprint

bp = Blueprint(__name__, "example")

@bp.route("/example", methods=["POST"])
def example(self):
   print("example")
Ml answered 24/3, 2017 at 4:12 Comment(1)
This does not answer the question.Booker

© 2022 - 2024 — McMap. All rights reserved.