77

In Flask, when I have several routes for the same function, how can I know which route is used at the moment?

For example:

@app.route("/antitop/")
@app.route("/top/")
@requires_auth
def show_top():
    ....

How can I know, that now route was called using /top/ or /antitop/?

UPDATE

I know about request.path I don't want use it, because the request can be rather complex, and I want repeat the routing logic in the function. I think that the solution with url_rule it the best one.

Mohamed Diaby
  • 136
  • 2
  • 10
Igor Chubin
  • 57,130
  • 8
  • 114
  • 135

5 Answers5

105

Simply use request.path.

from flask import request

...

@app.route("/antitop/")
@app.route("/top/")
@requires_auth
def show_top():
    ... request.path ...
falsetru
  • 336,967
  • 57
  • 673
  • 597
69

the most 'flasky' way to check which route triggered your view is, by request.url_rule.

from flask import request

rule = request.url_rule

if 'antitop' in rule.rule:
    # request by '/antitop'

elif 'top' in rule.rule:
    # request by '/top'
Martin Thoma
  • 108,021
  • 142
  • 552
  • 849
thkang
  • 10,747
  • 12
  • 62
  • 81
  • 4
    This is a good solution but consider @marcinkuzminski 's solution . I think it is more elegant. – Ezequiel May 09 '19 at 14:33
  • This fails if the route is a [variable rule](https://flask.palletsprojects.com/en/2.0.x/quickstart/#variable-rules) `@app.route('/user/')` – gerardw Jun 26 '21 at 16:23
  • @gerardw `request.url_rule.rule` is the thing. It returns `/user/` as really needed. – winwin Sep 29 '21 at 13:54
56

Another option is to use endpoint variable:

@app.route("/api/v1/generate_data", methods=['POST'], endpoint='v1')
@app.route("/api/v2/generate_data", methods=['POST'], endpoint='v2')
def generate_data():
    version = request.endpoint
    return version
marcinkuzminski
  • 1,671
  • 14
  • 11
  • That shows the route with dots instead of slashes. That is, `subunit.page` instead of `/subunit/page` – gerardw Jun 26 '21 at 20:53
9

If you want different behaviour to each route, the right thing to do is create two function handlers.

@app.route("/antitop/")
@requires_auth
def top():
    ...

@app.route("/top/")
@requires_auth
def anti_top():
    ...

In some cases, your structure makes sense. You can set values per route.

@app.route("/antitop/", defaults={'_route': 'antitop'})
@app.route("/top/", defaults={'_route': 'top'})
@requires_auth
def show_top(_route):
    # use _route here
    ...
iurisilvio
  • 4,727
  • 1
  • 26
  • 31
1

It seems to me that if you have a situation where it matters, you shouldn't be using the same function in the first place. Split it out into two separate handlers, which each call a common fiction for the shared code.

Daniel Roseman
  • 567,968
  • 59
  • 825
  • 842