Добавление префикса ко всем маршрутам колбы



У меня есть префикс, что я хочу добавить к каждому маршруту. Прямо сейчас я добавляю константу в маршрут при каждом определении. Есть ли способ сделать это автоматически?



PREFIX = "/abc/123"

@app.route(PREFIX + "/")
def index_page():
return "This is a website about burritos"

@app.route(PREFIX + "/about")
def about_page():
return "This is a website about burritos"
674   8  

8 ответов:

ответ зависит от того, как вы служите это приложение.

подсоединен внутри другого контейнера WSGI

предполагая, что вы собираетесь запустить это приложение внутри контейнера WSGI (mod_wsgi, uwsgi, gunicorn и т. д.); Вам нужно на самом деле mount, с этим префиксом приложение как часть этого контейнера WSGI (все, что говорит WSGI будет делать) и установить ваш APPLICATION_ROOT значение config в префикс:

app.config["APPLICATION_ROOT"] = "/abc/123"

@app.route("/")
def index():
    return "The URL for this page is {}".format(url_for("index"))

# Will return "The URL for this page is /abc/123/"

задание APPLICATION_ROOT значение конфигурации просто ограничивает cookie сеанса Flask этим префиксом URL. Все остальное будет автоматически обрабатываться для вас с помощью Flask и Werkzeug отличные возможности обработки WSGI.

пример правильного подсоединения вашего приложения

если вы не уверены, что означает первый абзац, взгляните на этот пример приложения с колбой, установленной внутри это:

from flask import Flask, url_for
from werkzeug.serving import run_simple
from werkzeug.wsgi import DispatcherMiddleware

app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/abc/123'

@app.route('/')
def index():
    return 'The URL for this page is {}'.format(url_for('index'))

def simple(env, resp):
    resp(b'200 OK', [(b'Content-Type', b'text/plain')])
    return [b'Hello WSGI World']

app.wsgi_app = DispatcherMiddleware(simple, {'/abc/123': app.wsgi_app})

if __name__ == '__main__':
    app.run('localhost', 5000)

проксирование запросов к приложению

если, с другой стороны, вы будете запускать приложение Flask в корне своего контейнера WSGI и проксировать запросы к нему (например, если это Fastcgi'D, или если nginx proxy_pass-ing запросы на суб-конечную точку для вашего автономного uwsgi/gevent сервер, то вы можете либо:

  • используйте чертеж, как указывает Мигель в его ответ.
  • или использовать DispatcherMiddleware С werkzeug (или PrefixMiddleware С су27 это) в суб-Маунт-приложения в изолированной тут WSGI-сервер вы используете. (См.пример правильного подсоединения вашего приложения выше для использования кода).

Вы можете поместить свои маршруты под копирку:

bp = Blueprint('burritos', __name__,
                        template_folder='templates')

@bp.route("/")
def index_page():
  return "This is a website about burritos"

@bp.route("/about")
def about_page():
  return "This is a website about burritos"

затем вы регистрируете схему элементов в приложении, используя префикс:

app = Flask(__name__)
app.register_blueprint(bp, url_prefix='/abc/123')

вы должны отметить, что APPLICATION_ROOT не для этой цели.

все, что вам нужно сделать, это написать промежуточного внести следующие изменения:

  1. изменить PATH_INFO чтобы справиться с префиксом URL-адреса.
  2. изменить SCRIPT_NAME для создания префиксного url.

такой:

class PrefixMiddleware(object):

    def __init__(self, app, prefix=''):
        self.app = app
        self.prefix = prefix

    def __call__(self, environ, start_response):

        if environ['PATH_INFO'].startswith(self.prefix):
            environ['PATH_INFO'] = environ['PATH_INFO'][len(self.prefix):]
            environ['SCRIPT_NAME'] = self.prefix
            return self.app(environ, start_response)
        else:
            start_response('404', [('Content-Type', 'text/plain')])
            return ["This url does not belong to the app.".encode()]

оберните свое приложение с помощью промежуточного программного обеспечения, например:

from flask import Flask, url_for

app = Flask(__name__)
app.debug = True
app.wsgi_app = PrefixMiddleware(app.wsgi_app, prefix='/foo')


@app.route('/bar')
def bar():
    return "The URL for this page is {}".format(url_for('bar'))


if __name__ == '__main__':
    app.run('0.0.0.0', 9010)

посетить http://localhost:9010/foo/bar,

вы получите правильный результат: The URL for this page is /foo/bar

и не забудьте установить домен cookie, если вам нужно.

это решение дано Larivact это. Элемент APPLICATION_ROOT не для этой работы, хотя она выглядит как. Это действительно сбивает с толку.

это скорее ответ python, чем ответ Flask/werkzeug; но это просто и работает.

если, как и я, вы хотите, чтобы ваши настройки приложения (загружается из .ini file) чтобы также содержать префикс вашего приложения Flask (таким образом, чтобы значение не устанавливалось во время развертывания, а во время выполнения), вы можете выбрать следующее:

def prefix_route(route_function, prefix='', mask='{0}{1}'):
  '''
    Defines a new route function with a prefix.
    The mask argument is a `format string` formatted with, in that order:
      prefix, route
  '''
  def newroute(route, *args, **kwargs):
    '''New function to prefix the route'''
    return route_function(mask.format(prefix, route), *args, **kwargs)
  return newroute

возможно, это несколько hackish и зависит от того, что функция маршрута колбы требует a route как первый позиционный аргумент.

вы можете использовать его как это:

app = Flask(__name__)
app.route = prefix_route(app.route, '/your_prefix')

NB: это ничего не стоит, что можно использовать переменную в префиксе (например, установив его в /<prefix>), а затем обработайте этот префикс в функциях, которые вы украшаете своим @app.route(...). Если вы это сделаете, вы, очевидно, должны объявить prefix параметр в ваших украшенных функциях. Кроме того, вы можете проверить отправленный префикс по некоторым правилам, и верните 404, если проверка не удалась. Для того, чтобы избежать 404 пользовательские повторной реализации, пожалуйста from werkzeug.exceptions import NotFound а то raise NotFound() если проверка не удалась.

Итак, я считаю, что правильный ответ на это: префикс должен быть настроен в фактическом серверном приложении, которое вы используете, когда разработка завершена. Apache, nginx и др.

однако, если вы хотите, чтобы это работало во время разработки при запуске приложения Flask в debug, взгляните на в этом суть.

колбы DispatcherMiddleware на помощь!

я скопирую код здесь для потомков:

"Serve a Flask app on a sub-url during localhost development."

from flask import Flask


APPLICATION_ROOT = '/spam'


app = Flask(__name__)
app.config.from_object(__name__)  # I think this adds APPLICATION_ROOT
                                  # to the config - I'm not exactly sure how!
# alternatively:
# app.config['APPLICATION_ROOT'] = APPLICATION_ROOT


@app.route('/')
def index():
    return 'Hello, world!'


if __name__ == '__main__':
    # Relevant documents:
    # http://werkzeug.pocoo.org/docs/middlewares/
    # http://flask.pocoo.org/docs/patterns/appdispatch/
    from werkzeug.serving import run_simple
    from werkzeug.wsgi import DispatcherMiddleware
    app.config['DEBUG'] = True
    # Load a dummy app at the root URL to give 404 errors.
    # Serve app at APPLICATION_ROOT for localhost development.
    application = DispatcherMiddleware(Flask('dummy_app'), {
        app.config['APPLICATION_ROOT']: app,
    })
    run_simple('localhost', 5000, application, use_reloader=True)

теперь, при запуске выше код в качестве отдельного приложения колбы,http://localhost:5000/spam/ появится Hello, world!.

в комментарии к другому ответу я выразил желание сделать что-то вроде этого:

from flask import Flask, Blueprint

# Let's pretend module_blueprint defines a route, '/record/<id>/'
from some_submodule.flask import module_blueprint

app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/api'
app.register_blueprint(module_blueprint, url_prefix='/some_submodule')
app.run()

# I now would like to be able to get to my route via this url:
# http://host:8080/api/some_submodule/record/1/

применение DispatcherMiddleware мой пример:

from flask import Flask, Blueprint
from flask.serving import run_simple
from flask.wsgi import DispatcherMiddleware

# Let's pretend module_blueprint defines a route, '/record/<id>/'
from some_submodule.flask import module_blueprint

app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/api'
app.register_blueprint(module_blueprint, url_prefix='/some_submodule')
application = DispatcherMiddleware(Flask('dummy_app'), {
    app.config['APPLICATION_ROOT']: app
})
run_simple('localhost', 5000, application, use_reloader=True)

# Now, this url works!
# http://host:8080/api/some_submodule/record/1/

Мне нужен был подобный так называемый"контекст-корень". Я сделал это в файле conf под /etc/httpd/conf.d / с помощью WSGIScriptAlias:

приложение.conf:

<VirtualHost *:80>
    WSGIScriptAlias /myapp /home/<myid>/myapp/wsgi.py

    <Directory /home/<myid>/myapp>
        Order deny,allow
        Allow from all
    </Directory>

</VirtualHost>

Так что теперь я могу получить доступ к моему приложению как:http://localhost:5000/myapp

смотрите руководство - http://modwsgi.readthedocs.io/en/develop/user-guides/quick-configuration-guide.html

другой совершенно другой способ - с mountpoints на uwsgi.

из документа о размещение нескольких приложений в одном процессе (ссылка).

в своем uwsgi.ini добавить

[uwsgi]
mount = /foo=main.py
manage-script-name = true

# also stuff which is not relevant for this, but included for completeness sake:    
module = main
callable = app
socket = /tmp/uwsgi.sock

если вы не вызываете свой файл main.py, вам нужно изменить оба mount и module

код main.py может выглядеть так:

from flask import Flask, url_for
app = Flask(__name__)
@app.route('/bar')
def bar():
  return "The URL for this page is {}".format(url_for('bar'))
# end def

и конфигурация nginx (опять же для полноты картины):

server {
  listen 80;
  server_name example.com

  location /foo {
    include uwsgi_params;
    uwsgi_pass unix:///temp/uwsgi.sock;
  }
}

называют example.com/foo/bar появится /foo/bar как возвращено колбы url_for('bar'), так как он автоматически адаптируется. Таким образом ваши ссылки будут работать без проблем префикс.

Я всегда предпочитаю использовать следующее, Когда речь идет о добавлении префикса на всю app:

app = Flask(__name__, root_path='/operators')

чистый и ясный.

Comments

    Ничего не найдено.