在settins.py中注册的Django应用程序的自动发现小部件

Lud*_*mer 4 django django-templates

标题可能有点令人困惑,但我不知道怎么称呼它.

我想创建一个Django项目,其中包含大量应用程序,您可以使用INSTALLED_APPSsettings.py中的选项任意打开或关闭(您显然还需要编辑urls.py并运行syncdb).打开应用后应该能够自动:

  1. 在网站范围的搜索中注册它的内容.幸运的是django-haystack有这个内置功能,所以这不是问题.

  2. 注册cron工作.django-cron正是如此.不是问题.

  3. 注册应显示在主页上的小部件.主页应包括具有不同应用程序的小部件的框列表.

    我考虑过包含标签,因为您可以将它们放在页面上的任何位置,它们可以控制内容和演示文稿.问题是我不知道如何自动获取我的应用程序提供的包含标记列表,并在主页上逐个显示它们.我需要一种方法以某种方式注册它们,然后显示所有注册的标签.

Clé*_*ent 5

我不确定使用包含标签实际上是你最好的选择......没有简单的方法,AFAIK,从模板动态调用模板标签(而且这不是模板标签的重点:-).

我想我可以对你的小部件做出以下假设,如果我错了,请纠正我:

  • 窗口小部件呈现功能不需要模板上下文中的参数
  • 顶多,它最终将需要当前request对象(以便它可以访问user,session等...)

有了这个,您可以将您的小部件视为迷你视图,返回字符串而不是响应:

def my_widget(request):
    ...
    # Here too, the function control both presentation and content
    return render_to_string('my_widget.html', {'foo': bar})
Run Code Online (Sandbox Code Playgroud)

现在有两个问题需要解决:

  1. 如何为模板中提供的所有已安装应用程序创建所有窗口小部件功能的动态列表?
  2. 如何在模板中调用这些小部件函数?

第一点:

一种简单的方法是依靠惯例.template_widgets.py在所有应用程序的模块中都有一个统一命名的函数列表,例如:

## myapp/template_widgets.py

def shopping_cart(request):
    # do something with the session/user
    ...
    return render_to_string('myapp/widgets/cart.html', {'cart': cart})

# Another widget func, not defined here
from myapp.views import another_widget_func

# The list of widget functions declared by this app
widgets = (shopping_cart, another_widget_func,)
Run Code Online (Sandbox Code Playgroud)

然后,您可以通过查看加载全局窗口小部件列表INSTALLED_APPS,并在所有模板中自动使用它(使用上下文处理器).当然,最好是懒洋洋地加载这个列表,以确保不会浪费CPU周期来构建它,如果你不打算使用它.

## myproject/context_processors.py
from django.utils.importlib import import_module
from django.utils.functional import lazy

def widgets(request):
    def get_all_widgets(request):
        from django.conf import settings
        widgets_list = []
        for app in settings.INSTALLED_APPS:
            try:
                mod = import_module(app+'.template_widgets')
                widgets_list.extend(mod.widgets)
            except ImportError:
                pass
            except AttributeError:
                # Couldn't find a widgets variable in app.template_widgets module,
                # probably better to raise a custom exception
                raise
        return widgets_list
    return {'widgets': lazy(get_all_widgets, list)(request)}
Run Code Online (Sandbox Code Playgroud)

第二点:

现在,您可以在每个模板中获得可用且延迟加载的小部件列表.使用它的方便语法如下:

## home.html
...
<div id="widgets">
    {% for widget in widgets %}
        <div class="widget">
            {{ widget }}
        </div>
    {% endfor %}
</div>
Run Code Online (Sandbox Code Playgroud)

但这不起作用,{[widget}}这里是一个可调用的,需要一个request参数.Djano不允许您使用模板中的参数调用callables,因此您必须修改上下文处理器以返回(lazily)评估的widget函数列表.

## myproject/context_processors.py
...
        # replace `return widgets_list` with the following
        return map(lambda w: lazy(w, str)(request), widgets_list)
...
Run Code Online (Sandbox Code Playgroud)

而且,上面的模板代码现在应该正常工作.

备注:

  • 列表中小部件的顺序取决于INSTALLED_APPS每个widgets列表中和每个列表中的应用程序的顺序.由您决定为您选择正确的排序方法(例如,使用加权,使用dict按名称访问小部件功能等).
  • 不要忘记加载上下文处理器,并始终使用RequestContext.