1

我遇到了一个与这个 SO question非常相似的问题,但是我尝试应用这些以前的答案并没有通过,建议我将其作为一个新问题开始:

在下面的代码中,我定义了几个我认为会延迟循环引用的 getChoices() 函数,但不是!请问这里有什么问题吗?

# ns.content/ns/content/foo.py
from zope import schema
from plone.directives import form
from z3c.relationfield.schema import Relation, RelationChoice
from plone.formwidget.contenttree import ObjPathSourceBinder

class IFoo(form.Schema):

    def getBarChoices():
        # avoiding circular refs...
        from bar import IBar
        return ObjPathSourceBinder(object_provides=IBar.__identifier__)

    barChoices = getBarChoices()
    form.widget(bar=AutocompleteFieldWidget)
    bar = Relation(source= barChoices,required=False)

# ns.content/ns/content/bar.py
from zope import schema
from plone.directives import form
from z3c.relationfield.schema import Relation, RelationChoice
from plone.formwidget.contenttree import ObjPathSourceBinder

class IBar(form.Schema):

    def getFooChoices():
        # avoiding circular refs...
        from foo import IFoo
        return ObjPathSourceBinder(object_provides=IFoo.__identifier__)

    fooChoices = getFooChoices()
    form.widget(foo=AutocompleteFieldWidget)
    foo = Relation(source= fooChoices,required=False)

resultingError = """
  File ".../buildout-cache/eggs/martian-0.11.3-py2.7.egg/martian/scan.py", line 217, in resolve
    __import__(used)
  File ".../zeocluster/src/ns.content/ns/content/bar.py", line 32, in <module>
    class IBar(form.Schema):
  File ".../zeocluster/src/ns.content/ns/content/bar.py", line 48, in IBar
    fooChoices = getFooChoices()
  File ".../zeocluster/src/ns.content/ns/content/bar.py", line 38, in getFooChoices
    from ns.content.foo import IFoo
  File ".../zeocluster/src/ns.content/ns/content/foo.py", line 33, in <module>
    class IFoo(form.Schema):
  File ".../zeocluster/src/ns.content/ns/content/foo.py", line 73, in IFoo
    barChoices = getBarChoices()
  File ".../zeocluster/src/ns.content/ns/content/foo.py", line 39, in getBarChoices
    from ns.content.bar import IBar
zope.configuration.xmlconfig.ZopeXMLConfigurationError: File ".../zeocluster/parts/client1/etc/site.zcml", line 16.2-16.23
    ZopeXMLConfigurationError: File ".../buildout-cache/eggs/Products.CMFPlone-4.2.0.1-py2.7.egg/Products/CMFPlone/configure.zcml", line 102.4-106.10
    ZopeXMLConfigurationError: File ".../zeocluster/src/ns.content/ns/content/configure.zcml", line 18.2-18.27
    ImportError: cannot import name IBar
"""
4

1 回答 1

4

getBarChoices()在定义时调用 class IFoo。所以from bar import IBar将在解析foo.py导致循环导入时执行。

在我看来,你基本上有两种选择:

1) 使用字符串作为 object_provides 的标识符。

无论如何,您已经通过使用这样做了IFoo.__identifier__,但是如果您将其设为静态而不是动态,这将消除您的循环依赖:

source = ObjPathSourceBinder(object_provides='ns.content.bar.IBar')
bar = Relation(source=source,required=False)

无需导入IBar. foo.py这有一个明显的缺点,即 的位置IBar现在在您的代码中被硬编码,因此每当您更改名称或位置时,IBar您都需要在foo.py.

2) 标记接口

例如,另一种选择是让IFooIBar实现您保存在第三个文件中的标记接口ns/content/interfaces.py。这样你就可以按照以下方式做一些事情

接口.py

from zope.interface import Interface

class IBarMarker(Interface):
    """Marker interface for IBar objects.
    """

class IFooMarker(Interface):
    """Marker interface for IFoo objects.
    """

foo.py

from zope.interface import directlyProvides
from plone.directives import form
from plone.formwidget.contenttree import ObjPathSourceBinder
from plone.formwidget.autocomplete import AutocompleteFieldWidget
from z3c.relationfield.schema import RelationChoice

from ns.content.interfaces import IBarMarker
from ns.content.interfaces import IFooMarker


class IFoo(form.Schema):
    directlyProvides(IFooMarker)

    form.widget(bar=AutocompleteFieldWidget)
    bar = RelationChoice(source=ObjPathSourceBinder(
                            object_provides=IBarMarker.__identifier__),
                         required=False)

酒吧.py

class IBar(form.Schema):
    directlyProvides(IBarMarker)

    form.widget(foo=AutocompleteFieldWidget)
    foo = RelationChoice(source=ObjPathSourceBinder(
                            object_provides=IFooMarker.__identifier__),
                         required=False)
于 2012-09-05T17:48:03.723 回答