Skip to content. | Skip to navigation

Personal tools

Navigation

You are here: Home / Tips / View Component

View Component

View 是 Plone 負責顯示功能或處理表單內容的元件機制,在功能上可以完整取代舊的 Skin Layer 機制,不過在 Plone 3 到 Plone 4 時期,View 和 Skin Layer 同時存在運行,在 Plone 5 之際預設已取消 Skin Layer。

View 是新式 Python 網站框架的重要元件,通常由下列兩者組成:

  • Python Class (使用 .py 檔名)
  • Page Template (使用 .pt 檔名)

如果有需要,也會搭配 JavaScript 或 CSS 等資源檔,可以用來顯示統計表單,或是上傳檔案的提示頁面。除了產生 HTML 檔案外,也可以輸出成 JSON 或 Excel 檔案格式,或是匯出資料到 SQL 資料庫

在 Plone 環境裡,Browser View 是最常見的應用方式,通常也會搭配 ViewletLayer,設定進階的控制細節。

背景知識

Skin Layer 是 Plone 2 時代,顯示動態網頁的傳統機制,它通常透過 Restricted Python 來執行程式邏輯,包括副檔名是 .cpy 的 Controller Script 檔案,再由 Page Template 顯示畫面。但這類 Python Script 並不是一般的 Python 程式,它們只允許執行特定功能,如果存取超過安全範圍的功能,就會出現 Unauthorized: The container has no security assertions 的錯誤。

另一個常見問題是,Skin Layer 的 Script 或 Template 可以在任何 context 裡執行。以 plone_content 的 document_view 為例,通常它該和 Page 搭配,但在 /some-news-item/document_view 的情況下,Zope 仍會試圖執行它,這樣很容易遇到 AttributeError 的錯誤。

當然,也有些 Script 或 Template 屬於通用類型的設計,在多種 context 裡都適合執行,以 plone_forms 裡的 content_status_history 為例,只要內容型別實作 Workflow 功能,就適合搭配它來執行。無論如何,到了 Plone 5 之際,Skin Layer 將被 View 機制取代。

從技術底層來看,View 是 Zope Component Architecture (ZCA) 的一種 Component,它是 Multi Adapter。在 Plone 5 之際,包括 plone_content 在內的 Skin Layer 被改寫成 Browser View 了。

從範例認識運作方式

從 Plone 網站根目錄,可以看到「目錄 (Folder)」包括好幾種「顯示方式 (Display)」:

  • Standard view
  • Summary view
  • Tabular view
  • All content
  • Album view
  • Event Lising
  • Select a content item as default view

上述畫面裡的 Item: Welcome to Plone 表示顯示方式是「Select a content item as default view」而且「選了 front-page 這個 Page 當作 default view」。

具體的 View 和 Template 檔案,預設在 browser 目錄裡,檔案通常是 view.py 或 mytype.pt 命名,其中的 .pt 指的就是 Page Template 檔案。以 Page 的顯示功能為例,它有用到 Page Template,具體的檔案位置在 plone/app/contenttypes/browser/templates/document.pt

檔案裡的 <div tal:...></div> 和 <metal></metal> 就是 Page Template 裡的標籤語法。

新增一行 Page Template 程式碼,測試下列的語法效果:

試試把 <span tal:content=”string:Hello World!”></span> 改成:

<span tal:content="context/title"></span>

或是:

<span tal:content="context/created"></span>

從上述範例,可以知道 context/titlecontext/created 是動態存取的變數值,更多關於變數值的控制細節,可參考 View and Template 文件說明。

View Class Example

檔名範例是 browser/views.py,內容範例如下:

from Products.Five.browser import BrowserView

class MyView(BrowserView):
    def __init__(self, context, request):
        self.context = context
        self.request = request
    # def __call__():

除了 context 和 request 當作基本參數設定外,不要在 __init__() 裡執行程式邏輯,它無法知道 View 的 parent 或 hierarchy,就算 helper 也無法生效,如果有錯的話,zope.component 會把它對應到 View not found 或 Traversal Error,慣例是使用 setup() 之類的程式碼,再由 __call__() 去呼叫執行。__call__() 是 View 的進入點,它會執行 self.index() 對應 ViewPageTemplateFile 來讀取 Template 內容。

下列是 index 在 View Class 裡的設定範例,同樣的功能也能透過 ZCML 達成:

from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile

class MyView(BrowserView):
    index = ViewPageTemplateFile("my-template.pt")

程式碼範例: pretaweb.healthcheck

Registration

使用 Browser View 之前,要向系統註冊必要的資訊,包括作用對象、負責程式邏輯的檔案位置,這點和 Skin Layer 的運作方式不同。它使用 ZCML 語法和 XML 格式,檔名慣例是 browser/configure.zcml,註冊範例如下:

<browser:page
  name="list-contents"
  for=".interfaces.IMyType"
  permission="zope2.View"
  class=".views.MyView" />

上述 index 指定 my-template.pt 的範例,與下列註冊方式同義:

<browser:page
  name="list-contents"
  for=".interfaces.IMyType"
  permission="zope2.View"
  class=".views.MyView"
  template="my-template.pt" />

也就是說,即使搭配最簡化的 View Class 程式碼:

class MyView(BrowserView):
    pass

它預設也會執行下列內容:

from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile

class MyView(BrowserView):
    # This may be overridden in ZCML
    index = ViewPageTemplateFile("my-template.pt")

    def render(self):
        return self.index()

    def __call__(self):
        return self.render()

在 Products/CMFPlone/browser/configure.zcml 檔案裡,找得到更多範例:

<browser:page
  for="*"
  name="plone"
  class=".ploneview.Plone"
  permission="zope.Public"
  allowed_interface=".interfaces.IPlone" />

BrowserView 定義在 Zope2 的 Products.Five/browser/__init__.py 裡,在 Products.Five/__init__.py 有提供載入介面,因此,透過 from Products.Five 或 from Products.Five.browser 都能 import BrowserView。

Manual View Look-up

View 是 ZCA 裡的 multi-adapter registration,可以透過名稱 (@@view-name 形式) 來查找,而不是 Traversing 機制。解析過程會用到的 Interface 包括:

  • context: 預設使用 zope.interface.Interface (相當於 for="*" 註冊方式)
  • request: 使用 zope.publisher.interfaces.browser.IBrowserRequest
  • layer: 預設使用 zope.publisher.interfaces.browser.IDefaultBrowserLayer

進階技巧包括:動態指定新的 Template 內容 指派多個 Template 檔案 覆蓋模組裡的 View Class 重複利用 View Template 或嵌入在其他 View 裡

利用 manage_propertiesForm 來管理 layout 設定

http://plone.org/documentation/kb/customization-for-developers/zope-3-browser-views

http://plone.org/documentation/kb/creating-a-custom-template-for-a-plone-content-type

Example: Products.PloneKeywordManager

Traversable Adapter Utility

Every attempt to access a content named "_foo" using a browser lead to a NotFound error:

if name[0] == '_':
    # Never allowed in a URL.
    raise NotFound, name

collective.folderishtraverse is an alternative to a default page

Listing Registered Browser Resources

get_size nocall:...
fileSize python: get_size(chapter)

quick search and issue button: Products.Poi

ImageView: Products.RoleAwarePortlet

BrowserView 舊的 __of__ 不再推薦使用: collective.geo.bundle 範例 AttributeError: 'MapWidgets' object has no attribute '__of__'

Related content
View and Template