django的设计处处体现了高内聚,低耦合的设计思想。比如APP的设计,可轻松从一个project移植到另一个project中。django-cms内部各种功能也是插件的方式提供。
初次安装的django-cms,可能只有一个现呈的page模块,如果你需要更高级的功能还是同样需要设计APP。django-cms设计了一些方法可以很方便让我们自己的APP与Page一起工作。
编写插件
我们已经有了之前设计的Products APP,他有自己的模板,有自己访问的URL,但如果我想在首页显示我置顶的产品,那就需要制作一个django-cms的插件了。
django-cms的插件中把需要记录的参数(比如我要显示哪些分类共多少条置顶的产品)做为model, 在django-cms为placeholder添加你的插件时,这个model中的项会出现在界面上供你修改:
from cms.models import CMSPlugin
class ProductPlugin(CMSPlugin):
# 使用多对多关系admin中对应多选控件
cates = models.ManyToManyField(Categroy, related_name='plugins')
number = models.IntegerField(default = 6)
def __unicode__(self):
# 对于多对多的字段内部读取时可以用.all()来访问
return "%s [%s]" % ("|".join([t.title for t in self.cates.all()]), self.number)
有了这个model然后创建真正的插件文件cms_plugins.py:
from cms.plugin_base import CMSPluginBase
from cms.plugin_pool import plugin_pool
from products.models import ProductsPlugin as ProductsPluginModel
from products.models import Product, Categroy
from django.utils.translation import ugettext as _
class ProductsPlugin(CMSPluginBase):
model = ProductsPluginModel
name = _("Products Top Plugin")
render_template = "products/plugin_top.html"
def render(self, context, instance, placeholder):
pros = Product.objects.filter(categroy__in = instance.cates.all()).filter(is_top = True)[:instance.number]
context.update({'instance':instance, "products" : pros})
# context会传递到 render_template定义的模版中
return context
# 注册到django-cms的插件池中
plugin_pool.register_plugin(ProductsPlugin)
此时django-cms的page栏目里,你就可以为placeholder中添加名为’Products Top Plugin’的自定义插件了。
编写应用钩子
之前在project中的url里添加了一条正则把路径串联到APP中:
url(r'^products/', include("products.urls")),
如果需要django-cms中任意page自定义的页面进入我们的APP如何做到呢? 那需在制作一个app的钩子。
from cms.app_base import CMSApp
from cms.apphook_pool import apphook_pool
from django.utils.translation import ugettext_lazy as _
class ProductsApp(CMSApp):
name = _("Products App")
urls = ["products.urls"]
apphook_pool.register(ProductsApp)
有了这个,就可以把project中urls.py里的上述那条url正则去掉了。在创建的page的高级选项中,为”Application”选择我们创建的 “Products App”,那么访问这个page 时会自动进入products的url匹配。
菜单
django-cms中的菜单是可以自己定义的,你可以把任一page页面加入到菜单中,然后通过 ‘show_menu’ 标签调用。那我们自己编写的APP如何加入到菜单中呢。特别时APP也有子菜单的话,如何也显示这些子菜单?那需要 menu.py 出场了。
from cms.menu_bases import CMSAttachMenu
from menus.base import Menu, NavigationNode
from menus.menu_pool import menu_pool
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from products.models import Categroy
class ProductsMenu(CMSAttachMenu):
name = _("Product Menu")
def get_nodes(self, request):
nodes = []
for cate in Categroy.objects.all():
node = NavigationNode(
cate.title,
reverse('products.views.categroy', args=(cate.path,)),
cate.id,
cate.parent and cate.parent.id or None # 有没有父节点
)
nodes.append(node)
return nodes
menu_pool.register_menu(ProductsMenu)
ProductsMenu还需要添加到 cms_app.py中:
class ProductsApp(CMSApp):
name = _("Products App")
urls = ["products.urls"]
# 添加到这里
menu = ["products.menu"]
接下来的工作是告诉django这个菜单显示在哪个page下面。可以在page的高级设置中的 “Attached menu” 进行选择,最后就剩下在模板中调用了 ‘load menu_tags’并使用标签 ‘show_menu 0 100 100 100’ 显示所有菜单项。
show_menu的参数具体说明可参看: https://django-cms.readthedocs.org/en/2.3.5/getting_started/navigation.html#show-menu
好了,以上就是这次django-cms学习的一些记录,大致上可以应付自己的简单要求了,整个过程感觉django的设计非常巧妙,很多地方为程序员节省了很多工作。django-cms也充满DIY精神,为千变万化的定制需求提供了条件。
参考: