Using defaults with app.add_url_rule in Flask

13,635

Solution 1

It turns out I need to register two endpoints when using defaults.

Because {'instid': None} is passed into get() in my ContactAPI view as a kwarg, I need to tell Flask to set instid to None when the URL /contact is hit.

When I hit /contact/1, I need to use <int:instid>. To do this, I need to remove the defaults kwarg in my call to add_url_rule().

manager.py

from xxx import ContactAPI
from xxx.models import Contact

# self.app is my Flask app
# self.session is SQLAlchemy Session

api_name = 'contact'
instance_endpoint = '/%s/<int:instid>' % api_name
collection_endpoint = '/%s' % api_name

methods = ['GET']

api_view = ContactAPI.as_view(api_name, self.session,
                              Contact, app)

self.app.add_url_rule(instance_endpoint, methods=methods, 
                      view_func=api_view)

self.app.add_url_rule(collection_endpoint, methods=methods, 
                      defaults={'instid': None},
                      view_func=api_view)

Relevant Werkzeug docs: http://werkzeug.pocoo.org/docs/routing/#werkzeug.routing.Rule

Thanks to asdf in the #flask IRC channel for pointing this out.

Solution 2

A complete example of a similar thing is there in the flask docs - https://flask.palletsprojects.com/en/1.1.x/views/

Share:
13,635

Related videos on Youtube

Chris McKinnel
Author by

Chris McKinnel

Bridging the gap between business and tech humans.

Updated on June 04, 2022

Comments

  • Chris McKinnel
    Chris McKinnel over 1 year

    I am setting a url endpoint with the following:

    manager.py

    from xxx import ContactAPI
    from xxx.models import Contact
    
    # self.app is my Flask app
    # self.session is SQLAlchemy Session
    
    api_name = 'contact'
    instance_endpoint = '/%s/<int:instid>' % api_name
    methods = ['GET']
    
    api_view = ContactAPI.as_view(api_name, self.session,
                                  Contact, app)
    
    self.app.add_url_rule(instance_endpoint, methods=methods, 
                          defaults={'instid': None},
                          view_func=api_view)
    

    And overriding get() in my ContactAPI class:

    views.py

    from flask.views import MethodView
    
    class ContactAPI(MethodView):
    
        def __init__(self, session, model, app, *args, **kwargs):
            super(ContactAPI, self).__init__(*args, **kwargs)
    
        def get(self, instid):
            print instid
    

    When I hit the URL /contact/1 I get instid printed as None.

    When I remove the defaults={'instid': None}, line from manager.py, I get instid printed as 1.

    Why is having the defaults line in my call to add_url_rule overriding what I'm putting in my URL?