1

I can use url_for in a flask 2.0.1 template like

<!-- flask-template.html -->
<button onclick="window.location.href='{{ url_for( 'testimport') }}';" >Import</button>

along with

@app.route('/import/images')
def testimport():
  return "ok"

but I cannot do it with a resource in flask-restx 0.5.1.

api = Api(app, version='1.0',
          title='The Restx API',
          description='An API to initiate basic operations')
ns_detect = api.namespace('detect', path='/', description='Detection')
@ns_detect.route('/detect/recording')
class DetectRecording(Resource):
    def post(self):
        return {"status": "ok"}

Can anybody please explain, how to correctly use url_for in the flask-restx case above?

<button value="{{ url_for( 'ns_detect.DetectRecording') }}">1</button> <!-- can't build -->
<button value="{{ Api.url_for( 'DetectRecording') }}">2</button> <!-- Api undefined -->
<button value="{{ api.url_for( 'DetectRecording') }}">3</button> <!-- api undefined -->
<button value="{{ url_for( 'ns_detect.DetectRecording') }}">4</button> <!-- can't build -->
<button value="{{ url_for( 'api.DetectRecording') }}">5</button> <!-- can't build -->
<button value="{{ url_for( 'ns_detect.DetectRecording.post') }}">6</button> <!-- can't build -->
  

btw: I have installed
Werkzeug 2.0.3
Jinja2 3.1.2

x y
  • 911
  • 9
  • 27

3 Answers3

3

After some trial and error, I figured out, which magic key is required to make url_for work with flask-restx:
it's a combination of namespace and a modified classname.
Example:

ns = api.namespace('xxx', path='/', description='some description')  
@ns.route('/some/endpoint')
class DoSomething(Resource):
    def post(self):
        return {"status": "ok"}

then use url_for({{ 'xxx_do_something' }}).

Maybe the flask-restx documentation would benefit from such an example..

x y
  • 911
  • 9
  • 27
1

When using flask.Blueprint and flask_restx.Namespace together, you have to reference the blueprint, the namespace, and the class name of the route in your call of flask.url_for.

The format, as x y described, is "blueprint.namespace_route_name". Remember that the camelcase in the class's name is deconstructed to snake_case. (RouteName -> route_name, in the example above)

Example

The example below has the API registered as a flask.Blueprint and the flask_restx.Api object registered has two namespaces (Users and Books) each with a single GET routes. Both routes return their corresponding endpoints using flask.url_for

    
    # Create a Flask app
    app = Flask(__name__)
    
    # Create 'api' BLUEPRINT for the API, named "api"
    blueprint = Blueprint('api', __name__)
    
    # Create an instance of the Api class
    api = Api(blueprint)
    
    # Define the 'users' NAMESPACE
    users_ns = Namespace('users', description='Users related operations')
    
    # Define the 'UsersList' ROUTE in the 'users' NAMESPACE
    @users_ns.route('/')
    class UsersList(Resource):
        def get(self):
            return {'UsersList_url': url_for('api.users_users_list')}
    
    # Define the 'books' NAMESPACE
    books_ns = Namespace('books', description='Books related operations')
    
    # Define the "Books" ROUTE in the 'books' NAMESPACE
    @books_ns.route('/')
    class Books(Resource):
        def get(self):
            return {'Books_url': url_for('api.books_books')}
    
    # Register the namespaces with the API
    api.add_namespace(users_ns)
    api.add_namespace(books_ns)
    
    # Register the blueprint with the Flask app
    app.register_blueprint(blueprint)
    
    if __name__ == '__main__':
        app.run(debug=True)

sebvargo
  • 613
  • 7
  • 10
0

for me worked following,

from flask import Blueprint, render_template, url_for, make_response
...
blueprint = Blueprint('blueprintname', __name__, 
url_prefix='/api/v1.0')
api_extension = Api(
  blueprint,
  title='My title',
  version='1.0',
  description='My description',
  doc='/documentation'
)
...
namespaceAdmin = Namespace('admin')
api_extension.add_namespace(namespaceAdmin)
@namespaceAdmin.route('/password')
class ResetPassword(Resource):
  def get(self):
    headers = {'Content-Type': 'text/html'}
    return make_response(render_template('password.html'),200,headers)

and in template,

<form action="{{ url_for('blueprintname.admin_reset_password') }}" method="post">
</form>

use this syntax in url_for,

blueprint.namespace_classname

for ex.

blueprint = Blueprint('blueprint', __name__)
myNamespace = Namespace('namespace')
class ResetPassword(Resource):

in template (classname should be dashed below)

{{ url_for('blueprint.namespace_reset_password') }}
Burak Senel
  • 71
  • 2
  • 7