You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解决Plone词汇表工厂无法获取门户对象及读取注解数据问题

解决Plone词汇表工厂无法访问门户注解的问题

背景

我将JSON格式的术语定义存储在门户对象的注解中,更新定义时只需上传新的JSON文件即可。目前正尝试为内容类型创建一个行为:新增字段让用户从当前定义中选择术语。

问题

填充词汇表的函数无法访问注解,执行api.portal.get()时触发以下错误:

(Pdb) from plone import api
(Pdb) api.portal.get()
*** plone.api.exc.CannotGetPortalError: Unable to get the portal object.

当前代码

vocabulary.py

def generic_vocabulary(_terms, sort=True):
    """Returns a zope vocabulary from a dict or a list"""

    if _terms and isinstance(_terms, dict):
        _terms = _terms.items()
    elif _terms and isinstance(_terms[0], str):
        _terms = [(x, x) for x in _terms]

    if sort:
        _terms = sorted(_terms, key=lambda x: x[0])

    def factory(context):
        """Simple Vocabulary factory"""
        return SimpleVocabulary(
            [SimpleTerm(n, n.encode("utf-8"), term) for n, term in _terms]
        )

    return factory


_terms_list = (
    ("key1", "Value 1"),
    ("key2", "Value 2"),    
)


def generate_terms_list():
    import pdb

    pdb.set_trace()

    # TODO Get the list of terms from annotations
    # from plone import api
    # api.portal.get() ERROR HERE
    return _terms_list


terms_list = generic_vocabulary(generate_terms_list())
alsoProvides(terms_list, IVocabularyFactory)

configure.zcml

<utility
    name="my.add.on.terms"
    component=".vocabulary.terms_list"
    />

behavior.py

from plone.autoform import directives
from plone.autoform.interfaces import IFormFieldProvider
from plone.supermodel import model
from zope import schema
from zope.interface import provider


@provider(IFormFieldProvider)
class ICustomTermsListBehavior(model.Schema):
    
    terms_list = schema.List(
        title="Terms List",
        description="Select Terms",
        required=False,
        value_type=schema.Choice(vocabulary="my.add.on.terms"),
    )
    directives.write_permission(terms_list="cmf.ManagePortal")

我期望将演示术语替换为注解中的真实内容,预期读取注解的代码如下:

def get_annot():
    annot_key = 'TEST_KEY'
    container = api.portal.get()
    annotations = IAnnotations(container)
    return annotations[annot_key]

已尝试的方法(均失败)

(Pdb) from zope.component import getUtility
(Pdb) from Products.CMFCore.interfaces import ISiteRoot
(Pdb) portal = getUtility(ISiteRoot)
*** zope.interface.interfaces.ComponentLookupError: (<InterfaceClass Products.CMFCore.interfaces.ISiteRoot>, '')
(Pdb) site = api.portal.getSite()
(Pdb) site is None
True
(Pdb) from zope.component.hooks import getSite
(Pdb) getSite() is None
True

解决方案

问题核心是模块加载阶段就执行了generate_terms_list,此时Plone站点上下文尚未初始化,无法获取门户对象。正确做法是将动态获取术语的逻辑移到接收context参数的工厂函数内部,利用请求时传入的上下文定位门户。

修改后的vocabulary.py代码:

from plone import api
from zope.annotation.interfaces import IAnnotations
from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm
from zope.interface import alsoProvides, IVocabularyFactory


def generic_vocabulary(sort=True):
    """Returns a zope vocabulary factory that fetches terms from portal annotations"""

    def factory(context):
        """Vocabulary factory that uses context to access portal"""
        # 通过传入的上下文获取门户对象
        portal = api.portal.get(context=context)
        annot_key = 'TEST_KEY'
        annotations = IAnnotations(portal)
        # 从注解中读取术语数据,兼容字典或列表格式
        _terms = annotations.get(annot_key, {})
        
        if _terms and isinstance(_terms, dict):
            _terms = _terms.items()
        elif _terms and isinstance(_terms[0], str):
            _terms = [(x, x) for x in _terms]

        if sort:
            _terms = sorted(_terms, key=lambda x: x[0])
            
        return SimpleVocabulary(
            [SimpleTerm(n, n.encode("utf-8"), term) for n, term in _terms]
        )

    return factory


# 直接生成词汇表工厂,避免模块加载时提前执行数据获取逻辑
terms_list = generic_vocabulary()
alsoProvides(terms_list, IVocabularyFactory)

关键改动:

  • 将术语获取逻辑移到factory函数内部,利用请求时传入的context定位门户
  • 移除模块加载阶段执行的generate_terms_list,避免访问未初始化的上下文
  • 使用api.portal.get(context=context)确保在任意请求场景下都能正确获取门户对象

修改后,当表单调用词汇表时,会传入当前内容对象作为上下文,通过该上下文即可读取门户注解中的术语数据。

内容的提问来源于stack exchange,提问作者GhitaB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 04:45:03