您的位置:首页 > 移动开发

django-cms 代码研究(八)app hooks

2014-09-16 17:08 405 查看
app钩子,啥玩意呢?就是把现有的app,集成到cms的一种手段。有两种实现方式:1) 定义cms_app.py,如下:
from cms.app_base import CMSApp
from cms.apphook_pool import apphook_pool
from django.utils.translation import ugettext_lazy as _

class MyApphook(CMSApp):
name = _("My Apphook")
urls = ["myapp.urls"]

apphook_pool.register(MyApphook)
官方文档查看这里:http://docs.django-cms.org/en/latest/extending_cms/app_integration.html#app-hooks加载逻辑,通过discover_apps的load('cms_app')来加载(前提是在settings.py中未定义 CMS_APPHOOKS):在所有的installed_app中,查找cms_app模块,并自动import_module2) 在setting.py中定义CMS_APPHOOKS
APPHOOKS=(
'yourmodule.you_object1','yourmodule.you_object2',...
)
这是从源码中分析的来的,如下:C:\Python27\Lib\site-packages\django_cms-3.0.3-py2.7.egg\cms\apphook_pool.py (45~57)
def discover_apps(self):
self.apphooks = get_cms_setting('APPHOOKS')

if self.apphooks:
for cls in iterload_objects(self.apphooks):
try:
self.register(cls, discovering_apps=True)
except AppAlreadyRegistered:
pass

else:
load('cms_app')

self.discovered = True
iterload_objects,是一个生成器,如下:
def iterload_objects(import_paths):
"""
Load a list of objects.
"""
for import_path in import_paths:
yield load_object(import_path)
load_object
def load_object(import_path):
if '.' not in import_path:
raise TypeError(
"'import_path' argument to 'django_load.core.load_object' must "
"contain at least one dot."
)
module_name, object_name = import_path.rsplit('.', 1)
module = import_module(module_name)
return getattr(module, object_name)
顺便分析下 C:\Python27\Lib\site-packages\django_cms-3.0.3-py2.7.egg\cms\apphook_pool.py的源码:实例变量:
def __init__(self):
self.apphooks = []
self.apps = {}
self.discovered = False
方法:clear/register/discover_apps/get_apphooks/get_apphook其中: discover_apps上面已经分析过了。clear,清空实例变量,如下(作者说,python不需要clear,会自动回收,这个方法该砍掉了):
def clear(self):
# TODO: remove this method, it's Python, we don't need it.
self.apphooks = []
self.apps = {}
self.discovered = False
register,用于注册app,app的基类如下:
class CMSApp(object):
name = None
urls = None
menus = []
app_name = None
permissions = True
register,本质是把app放到apphook_pool实例的apps中,不过之前会有一些验证,如下:
def register(self, app, discovering_apps=False):
if self.apphooks and not discovering_apps:
return

if app.__name__ in self.apps:
raise AppAlreadyRegistered(
'A CMS application %r is already registered' % app.__name__)

if not issubclass(app, CMSApp):
raise ImproperlyConfigured(
'CMS application must inherit from cms.app_base.CMSApp, '
'but %r does not' % app.__name__)

if not hasattr(app, 'menus') and hasattr(app, 'menu'):
warnings.warn("You define a 'menu' attribute on CMS application %r, "
"but the 'menus' attribute is empty, did you make a typo?" % app.__name__)

self.apps[app.__name__] = app
其干活的代码只有最后一句:
self.apps[app.__name__] = app
get_apphooks, 返回一个列表 [(app,app.name)....],并按照app.name排序,如下:
def get_apphooks(self):
hooks = []

if not self.discovered:
self.discover_apps()

for app_name in self.apps:
app = self.apps[app_name]

if app.urls:
hooks.append((app_name, app.name))

# Unfortunately, we loose the ordering since we now have a list of tuples. Let's reorder by app_name:
hooks = sorted(hooks, key=lambda hook: hook[1])

return hooks
get_apphook,根据app名字查找app,代码如下:
def get_apphook(self, app_name):
if not self.discovered:
self.discover_apps()

try:
return self.apps[app_name]
except KeyError:
# deprecated: return apphooks registered in db with urlconf name instead of apphook class name
for app in self.apps.values():
if app_name in app.urls:
return app

raise ImproperlyConfigured('No registered apphook %r found' % app_name)
  

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: