如何使用django-compressor离线压缩表单媒体

时间:2015-09-07 07:50:31

标签: django django-compressor

Django模板(包含带媒体的表单)包含类似下面的代码片段,当使用带有COMPRESS_OFFLINE=True的django-compressor时会抛出错误,因为当离线压缩时form不可用执行:

# Template snippet
{% compress js %}
{{ form.media.js }}
{% endcompress %}

一般来说,django-compressor提供COMPRESS_OFFLINE_CONTEXT设置来处理类似的情况。但是,如果网站包含许多此类表格或小部件与媒体,此解决方案并非理想。

例如,目前,我在settings.py中执行类似的操作(对于每个小部件的媒体):

# settings.py
...
from my_app1.widgets import Widget1
from my_app1.widgets import Widget2
from my_app1.widgets import Widget3
...
widgets = {
    'my_widget1': Widget1(),
    'my_widget2': Widget2(),
    'my_widget3': Widget3(),
    ...
}
for name, widget in widgets.items():
    COMPRESS_OFFLINE_CONTEXT['{}_css'.format(name)] = widget.media['css']
    COMPRESS_OFFLINE_CONTEXT['{}_js'.format(name)] = widget.media['js']

然后在模板中,我这样做:

{% compress js %}
{{ my_widget1_js }}
{% endcompress %}

有没有办法以更接近Django {{ form.media }}方法的方式处理这种情况,或者可能无需枚举特定媒体到每个窗口小部件或每个窗体(包含媒体)网站?

1 个答案:

答案 0 :(得分:0)

您可以使用__getattr__方法使用某个自定义类来简化设置。这样,如果您将该对象传递给模板并尝试调用

{{ obj.my_widget1_js }}

__getattr__内的逻辑可以搜索项目中的指定小部件并返回它的媒体。

将自动发现每个小部件的类示例:

class WidgetImporter(object):

    def __getattr__(self, name):
        path = name.split('__') # this will split path on double underscore, so you can define submodule here
        path = [(node, "".join(part.capitalize() for part in node.split('_'))) for node in path] # this will convert underscore_names to CamelCase names.

        # determining for each module if it's name is CamelCased or underscored
        real_path = []
        for underscored, cameled in path:
            try:
                __import__(".".join(real_path + [underscored])) # first trying to import umderscored module
            except ImportError:
                try:
                    __import__(".".join(real_path + [cameled])) # now try with cameled
                except ImportError:
                    return "" # or raise some exception here if you like
                else:
                    real_path.append(cameled)
            else:
                real_path.append(underscored)

        last_node = real_path[len(real_path) - 1]
        return getattr(__import__(".".join(real_path), fromlist=[last_node]), last_node)() # returning actual class instance

这样你可以在settings.py文件中使用它:

COMPRESS_OFFLINE_CONTEXT = {
    'widgets': WidgetImporter(),
}

并在您的模板中使用:

{{ widgets.my_app1__widgets__widget1.media.css }}

类将尝试将my_app1__widgets__widget1解析为您的类的实际路径,并尝试导入它。如果成功,将打印media['css']。它不是100%最佳代码和100%安全(如果有人可以访问您的模板,可能会有一些漏洞),但它会完成这项工作。