前言
CMS插件是一个可重复使用内容发布者,它能够嵌入到django CMS页面上,或者利用django CMS placeholder嵌入到任意内容。它们不需要进一步的干预就能够自动的发布信息。这就意味着,当你发布网页内容时,不管是什么内容,总能保持最新。
它就像一个魔术,但是更快。
如果你的需求在内嵌的或者第三方的插件里都实现了,那么你很幸运,否则的话,你需要去实现自己的CMS插件。但是不用太担心,写一个CMS插件非常简单。
为什么需要写一个插件
如果要把django应用集成到django CMS页面上,插件是最方便的方法。例如:如果你在部署一个唱片公司的django CMS站点,你可能想在主页上放一个"最新发布"的版块,这样可能需要经常编辑该页面去更新信息。然而,一个明智的唱片公司同样会在django里管理它的目录,这样的话django就已经知道这周它要发布什么。
这是一个很好的机会去利用这些信息来简化你的工作,你所需要做的事就是创建一个CMS插件把它插入到你的主页上,让它去完成发布信息的工作。
插件是可重复使用的,这样你可能只需要稍作修改就可以用于类似目的。
概述
一个django CMS插件基本上由三部分组成
- editor插件:在每次部署时进行配置
- publisher插件:自动完成决定发布哪些内容
- template插件:渲染网页信息
这些与MVT (Model-View-Template)模式是一致的
- model插件存储配置信息
- view插件完成显示
- template插件渲染信息
所以,要编写你自己的plugin,你需要从下面开始
- 一个cms.models.pluginmodel.CMSPlugin子类去存储你的插件实例的配置
- 一个cms.plugin_base.CMSPluginBase子类定义你的操作逻辑
- 一个模板去渲染你的插件
cms.plugin_base.CMSPluginBase
注意事项
cms.plugin_base.CMSPluginBase 实际上是 django.contrib.admin.ModelAdmin 子类
因为 CMSPluginBase 从 ModelAdmin 子类化,所以 ModelAdmin 的几个重要的选项对CMS plugin开发者也适用。下面这些选项经常被用到::
- exclude
- fields
- fieldsets
- form
- formfield_overrides
- inlines
- radio_fields
- raw_id_fields
- readonly_fields
然而,并不是ModelAdmin的所有的操作在CMS plugin都能用,特别是一些ModelAdmin的changelist专用的那些选项是无效的。下面这些选项在CMS中需要被忽略:
- actions
- actions_on_top
- actions_on_bottom
- actions_selection_counter
- date_hierarchy
- list_display
- list_display_links
- list_editable
- list_filter
- list_max_show_all
- list_per_page
- ordering
- paginator
- preserve_fields
- save_as
- save_on_top
- search_fields
- show_full_result_count
- view_on_site
关于model及配置的旁白
Model插件从cms.models.pluginmodel.CMSPlugin继承而来,实际上它是可选的。
如果它永远只做同一件事,你的插件可以不去配置,例如:如果你的插件永远只是发布过去几天里销量最好的唱票。很明显,这个不够灵活,他并不能发布过去几个月销量最好的。
通常,如果你发现你需要去配置你的插件,这就需要定义一个model。
最简单插件、
你可以用python manage.py startapp去设置基本的应用布局(记得把你的插件加入INSTALLED_APPS),或者,你也可以只需要在当前的django应用里加入一个叫cms_plugins.py的文件。
可以把你的插件内容放到这个文件里,例如,你可以加入以下代码:
from cms.plugin_base import CMSPluginBase
from cms.plugin_pool import plugin_pool
from cms.models.pluginmodel import CMSPlugin
from django.utils.translation import ugettext_lazy as _
@plugin_pool.register_plugin
class HelloPlugin(CMSPluginBase):
model = CMSPlugin
render_template = "hello_plugin.html"
cache = False
这样,基本上就完成了。剩下的只需要去添加模板。在模板根目录添加hello_plugin.html文件
<h1>Hello {% if request.user.is_authenticated %}{ { request.user.first_name }} { { request.user.last_name}}{% else %}Guest{% endif %}</h1>
该插件会在页面上显示欢迎信息,如果是登录用户,显示名字,否则显示Guest。
在cms_plugins.py文件,你会子类化cms.plugin_base.CMSPluginBase,这些类会定义了不同的插件。
有两个属性是这些类必须的:
model:model用于存储你的插件信息。如果你不打算存储一些特别信息,直接用cms.models.pluginmodel.CMSPlugin就可以了。在一个正常的admin class,你不需要提供这个信息。
name:显示在admin上的你的插件名字。通过,实际工作中我们会通过django.utils.translation.ugettext_lazy()将改字符串设成可翻译的。
如果render_plugin设为True,下面内容必须定义
render_template:插件的渲染模板
get_render_template:返回渲染插件模板的路径
除了这些属性,你也可以重写render()方法,该方法决定渲染插件的模板上下文变量。默认情况下,这个方法只会把instance和placeholder对象添加到你的context,插件可以通过重写这个方法添加更多的上下文内容。
你也可以重写其他的CMSPluginBase子类的方法,详细信息参考CMSPluginBase 。
调试
因为插件的modules通过django的importlib加载,你可能会碰到路径环境导致的问题。如果你的cms_plugins不能加载或者访问,尝试下面的操作:
$ python manage.py shell
>>> from importlib import import_module
>>> m = import_module("myapp.cms_plugins")
>>> m.some_test_function()
存储配置
许多情况下,你需要给你的插件实例存储配置。例如:如果你有一个插件显示最新的发布博客,你可能也希望能够选择显示条目的数量。
去实现这些功能,你需要在已安装的models.py文件里,创建一个model子类化cms.models.pluginmodel.CMSPlugin
接下来,我们来改进一下上面的HelloPlugin,给未授权用户添加可配置的名字
在models.py文件,添加如下内容
from cms.models.pluginmodel import CMSPlugin
from django.db import models
class Hello(CMSPlugin):
guest_name = models.CharField(max_length=50, default='Guest')
这个跟正常的model定义没有太大差别,唯一不同是它是从cms.models.pluginmodel.CMSPlugin 继承而不是django.db.models.Model.
现在,我们需要修改我们的插件定义来使用这个model,新的cms_plugins.py如下
from cms.plugin_base import CMSPluginBase
from cms.plugin_pool import plugin_pool
from django.utils.translation import ugettext_lazy as _
from .models import Hello
@plugin_pool.register_plugin
class HelloPlugin(CMSPluginBase):
model = Hello
name = _("Hello Plugin")
render_template = "hello_plugin.html"
cache = False
def render(self, context, instance, placeholder):
context = super(HelloPlugin, self).render(context, instance, placeholder)
return context
我们修改model属性,并且将model实例传递给context.
最后,更新模板,在模板里使用新的配置信息。
<h1>Hello { % if request.user.is_authenticated %}
{ { request.user.first_name }} { { request.user.last_name}}
{ % else %}
{ { instance.guest_name }}
{ % endif %}</h1>
这儿,我们使用{ { instance.guest_name }}来取代固定的Guest字符串
关系处理
每次你的页面发布时,如果自定义插件在页面里,那么它就会被拷贝。所以,你的自定义插件有ForeignKey (from或者to)或者m2m,你需要拷贝这些关联对象。它不会自动帮你完成。
每个插件model会从基类继承空方法