4

I have a Route named search: @app.route('/search') Is it possible to add multiple optional parameters to it? Example:

@app.route('/search/pg/<int:pg>')
@app.route('/search/types/<types>')
@app.route('/search/number/<int:number>')
@app.route('/search/subject/<subject>')

The order in the URL shouldnt matter, so I could call /search/pg/2, or /search/subject/MySubject/pg/2 or /search/types/posts/subject/MySubject/pg/2

I tried this, but it only works with the full paths and all the parameters:

@app.route('/search/pg/<int:pg>/types/<types>/subject/<subject>', methods=['GET', 'POST'])
@app.route('/search/subject', defaults={'subject', None})
@app.route('/search/pg/<int:pg>/types/<types>', methods=['GET', 'POST'])
@app.route('/search/types', defaults={'types', None})
@app.route('/search', defaults={'pg': 1}, methods=['GET', 'POST'])
@app.route('/search/pg/<int:pg>', methods=['GET', 'POST'])
def search(pg, types=None, subject=None):
    pass
1
  • Use a query string and parse the options in the request to build the query Commented Jul 12, 2017 at 19:17

3 Answers 3

11

You can use filter in the URL instead of "sub-resources". Then you can put search arguments in any order in your request: /search?pg=<pg>&types=<types>

Inside the flask view function you can retrieve parameters from the request object:

@app.route('/search/')
def search():
    pg = request.args.get('pg')
    ...
Sign up to request clarification or add additional context in comments.

Comments

2

@David, 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)

Comments

2

If you are trying to route a user based on multiple, optional form values as route parameters, then I found a useful workaround.

First, create an intermediate route that will create the query string. This route will only allow for POST methods (since the 1 or more of the form values would be submitted by the form).

@app.route('/example', methods=['POST']
def createQueryParams():
  form = ExampleForm()
  # Retrieve/cleanse/validate form data
  example1 = form.example_field1.data
  example2 = form.example_field2.data
  return redirect(url_for('app.route', example1=example1, example2=example2))  

Note that each keyword argument in the redirect(url_for()) needs to either be a parameter used in app.route or something you expect to add as a query parameter.

Next, alter your app.route() to have a GET method and extract the query parameters like @lee-pai-long mentioned

@app.route('/search', methods=['GET'])
def search():
  if len(request.args) > 0:
    example1 = request.args.get('example1')
    example2 = request.args.get('example2')
    # Do stuff

Finally, in the .html template where the form is submitted, make sure the form action directs to the createQueryParams route, not the search route. Such as

<form action="{{ url_for('app.createQueryParams') }}" method="POST">
  <!-- Flask form stuff -->
</form>

I used this structure to create a page where users could filter posts based on up to X different criteria (title search, date sort, tags, etc.). I wanted to be able to have an optimized query parameter, but without the intermediary createQueryParams route, I was not able to determine what form values were selected until after the url was created, since the single route owned both methods.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.