我遇到的问题与this 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
"""
答案 0 :(得分:4)
在定义班级getBarChoices()
时,您在定义时调用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)标记界面
另一种选择是让IFoo
和IBar
实现您保存在第三个文件中的标记接口,例如ns/content/interfaces.py
。这样你就可以按照
<强> interfaces.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)
bar.py
class IBar(form.Schema):
directlyProvides(IBarMarker)
form.widget(foo=AutocompleteFieldWidget)
foo = RelationChoice(source=ObjPathSourceBinder(
object_provides=IFooMarker.__identifier__),
required=False)