【问题标题】:Serve static files from blueprints without url prefix从没有 url 前缀的蓝图中提供静态文件
【发布时间】:2013-10-11 04:05:13
【问题描述】:

对于开发,我想从蓝图的静态文件夹中提供静态文件。但是,我不想通过蓝图的 url 前缀加载所有文件。是否有可能配置烧瓶,所以它会查看所有蓝图的静态文件夹并返回它找到的第一个文件? 这样做的原因是,当我部署应用程序时,构建过程会拉取我们的所有蓝图文件,并将它们放入一个单独的文件夹中(类似于 Django 的 collectstatics)。

换句话说,我有 2 个蓝图:foobar

app
  +--- foo
  |    +--- assets
  |    |     +--- css
  |    |     |
  |    |     +--- js
  |    +
  |    |
  |    +--- __init__.py:  foo_blueprint = Blueprint('foo', __name__, static_folder='assets')
  |
  +--- bar
       +
       |
       +--- __init__.py: bar_blueprint = Blueprint('bar', __name__, static_folder='assets')

我希望特定 js 子文件夹中的所有 js 文件都可以从 url /static/js/file.js 获得。这可能吗?

【问题讨论】:

    标签: python static-files flask


    【解决方案1】:

    你不能使用默认的flask 机制。

    在您的示例中,您将为静态文件夹创建 3 条规则:

    Rule "/assets/<path:filename>" for "static" endpoint
    Rule "/assets/<path:filename>" for "foo.static" endpoint
    Rule "/assets/<path:filename>" for "bar.static" endpoint
    

    当flask 将匹配您的URL 以规则它首先匹配并返回它。在这种情况下,它返回 static 端点规则。之后将为此端点调度函数,例如一个文件夹。

    PS。我不确定到底是static 端点,最好检查Map.update 方法。

    但您始终可以编写自己的请求描述符,它将查看蓝图文件夹:

    class MyApp(Flask):
        def static_dispatchers(self):
            yield super(MyApp, self).send_static_file
            for blueprint in self.blueprints.values():
                yield blueprint.send_static_file
    
        def send_static_file(self, filename):
            last_exception = None
            for static_dispatcher in self.static_dispatchers():
                try:
                    return static_dispatcher(filename)
                except NotFound as e:
                    last_exception = e
            raise last_exception
    

    PS。此示例不包含蓝图注册序列,因为它存储在 dict 中。

    但如果您有两个同名文件,则将处理第一个文件。例如,如果您有下一个结构:

    /static
    /static/app.js "console.log('app');"
    /foo/static/app.js "console.log('foo app');"
    /foo/static/blue.js "console.log('foo blue');"
    /foo/static/foo.js "console.log('foo self');"
    /bar/static/app.js "console.log('bar app');"
    /bar/static/blue.js "console.log('foo blue');"
    /bar/static/bar.js "console.log('bar self');"
    

    并在页面中包含脚本:

    <script src="{{ url_for('static', filename='app.js') }}"></script>
    <script src="{{ url_for('foo.static', filename='app.js') }}"></script>
    <script src="{{ url_for('bar.static', filename='app.js') }}"></script>
    <script src="{{ url_for('foo.static', filename='blue.js') }}"></script>
    <script src="{{ url_for('bar.static', filename='blue.js') }}"></script>
    <script src="{{ url_for('foo.static', filename='foo.js') }}"></script>
    <script src="{{ url_for('bar.static', filename='bar.js') }}"></script>
    

    你会得到下一个结果:

    app
    app
    app
    foo blue (or bar blue)
    foo blue (or bar blue)
    foo self
    bar self
    

    对于 js 和 css 可以连接相同路径的文件,但不能对图片这样做。

    但是我更喜欢为每个蓝图使用唯一的 URL 前缀,因为它使用 url_for 很简单。

    【讨论】:

    • 感谢您的回复。您是否也在生产中从蓝图文件夹中为它们提供服务?您是否使用 require.jsr.js 优化来合并您的 js 文件?如果是这样,如果您最终只有 1 个 js 文件,这是否适用于 URL 前缀?
    • 我没有依赖静态文件的蓝图,但是您可以尝试收集所有静态文件并放到nginx或CDN进行生产。我现在不使用require.js,但我相信它可以很好地使用 URL 前缀作为开发模块。使用很少的脚本就可以轻松收集和编译您的模块以用于生产。
    • +1 非常优雅地解决了这个问题。关心的人请注意 - 如果您需要确保每次对蓝图进行排序时都使用相同的顺序,那么在多个文件的情况下查找将始终导致相同的文件。
    • 只是为了确定,顺序只是同名js文件的问题,对吧?如果我确实有唯一的文件名,这将不是问题。
    • 是的。如果要将序列保存为蓝图注册顺序,则可以覆盖register_blueprint 并存储此序列。或者您可以尝试按照上面的建议连接这些文件。或引发异常以避免这种情况。
    猜你喜欢
    • 2014-06-06
    • 2016-06-12
    • 1970-01-01
    • 2015-10-26
    • 2017-05-19
    • 1970-01-01
    • 1970-01-01
    • 2017-01-27
    • 1970-01-01
    相关资源
    最近更新 更多