Greetings.

In Flask, the binding to the application of controllers, event handlers, etc. is usually done directly in the modules, but I wanted to bring these actions to an external file or to the Python dictionary. For example, this is how it would look (Yaml):

# это секция для настройки контроллеров view: [ { # это мы указываем вызываемый объект (например функцию index) action: application.view.index, # а тут шаблоны url`ов при совпадении с которыми вызывается функция index route: [/, /index] } ], 

A similar usual way would look like this:

 # application.view.index from app import app @app .route('/') @app .route('/index') def index(): return 'Hello, World' 

The advantage is that now we can, without getting inside the source, substitute handlers, controllers, etc. But ... the question is how does this approach correlate with the philosophy of Flask itself, and is it a good idea? Does anyone else have such needs when working with this framework?

Thanks for attention!

    2 answers 2

    In general, I will tell you this, if this method is not only acceptable to you, but is necessary, then a simple description in the project documentation will be enough to avoid any misunderstandings.

    • Well, I can't say the bill of necessity, but it will be much more convenient, I can say for sure, the main thing is that it does not complicate the understanding of the interaction of modules in the future - triplustri
    • All these philosophies are often just recommendations and if somewhere there are no clear rules that are written down as pep requiring strict adherence, then in principle they can be ignored. It is enough to simply describe in the dock that “this is the way it is, this structure in my opinion seems to be healthier and more correct in this project” and no one will say anything to you most likely. In short, yes, you are free to do whatever you want, you are a developer! And only you know how best it will be for the resulting product. - deterok

    The documentation here and here talks about it.

    There are methods that can help with this:

      add_url_rule(rule, endpoint=None, view_func=None, **options) 

    which works as a standard decorator:

     @app.route('/') def index(): pass 

    which is equivalent to

     def index(): pass app.add_url_rule('/', 'index', index) 

    If view_func not specified, then:

     app.view_functions['index'] = index 

    With request.method , respectively:

     def index(): if request.method == 'OPTIONS': # custom options handling here ... return 'Hello World!' index.provide_automatic_options = False index.methods = ['GET', 'OPTIONS'] app.add_url_rule('/', index) 

    If I understand you correctly, this is what you need. When generating a dictionary, you can automatically import exsons.

    This is how I automatically import Blueprints :

     def create_app(): ... register_routes(app) ... return app def register_routes(app): """Register routes.""" from . import controllers from flask.blueprints import Blueprint for module in _import_submodules_from_package(controllers): bp = getattr(module, 'bp') if bp and isinstance(bp, Blueprint): app.register_blueprint(bp) def _import_submodules_from_package(package): import pkgutil modules = [] for importer, modname, ispkg in pkgutil.iter_modules(package.__path__, prefix=package.__name__ + "."): modules.append(__import__(modname, fromlist="dummy")) return modules 

    And already in Blueprints themselves you can implement those same action games.

    This helper may also be useful:

     rules = {} for endpoint, _rules in iteritems(app.url_map._rules_by_endpoint): if any(item in endpoint for item in ['_debug_toolbar', 'debugtoolbar', 'static', 'admin']): continue rules[endpoint] = [{'rule': rule.rule} for rule in _rules] 

    Which makes it easy to get URLs for subsequent mapping, with a debugtoolbar , admin etc. bypass, for example, for the subsequent sitemap generation.

    Or, here’s a command for manage.py , so that you can always quickly see which URLs are currently registered:

     @manager.command def list_routes(): import urllib.request from flask import url_for output = [] for rule in app.url_map.iter_rules(): options = {} for arg in rule.arguments: options[arg] = "[{0}]".format(arg) methods = ','.join(rule.methods) url = url_for(rule.endpoint, **options) line = urllib.request.unquote("{:50s} {:20s} {}".format(rule.endpoint, methods, url)) for line in sorted(output): print (line)