Split this separate question from Plone.autoform - object has no attribute __iro__
I am experimenting with making an object that is generated on the fly by SQLA behave along the lines of a regular Dexterity content type. My goal is to modernize example.trajectory.
In my view, I intend to use @@ploneform-render-widget to render all fields and their values. However, unless I define each field as a property in the view wrapper, the widgets will have no value.
Since I plan on creating several new content types along these lines, How do I avoid having to define dozens of properties for each of the new content types?
Given that I subclass the Dexterity object from a SQLA base class, do I still require this wrapper?
Here are my various parts...
A schema:
@provider(IFormFieldProvider)
class IInvoicIn(model.Schema):
""" Form interface for InvoicIn content type
"""
document_id = schema.TextLine(
title = _(u'Invoice Number'),
description = u'',
required=True
)
document_date = schema.TextLine (
title = _(u'Date'),
description = u'',
required=False,
)
document_type = schema.TextLine (
title = _(u'Type'),
description = u'',
required=False,
)
originator_reference_id = schema.TextLine (
title = _(u'Originator'),
description = u'',
required=False,
)
A SQLA base class:
class InvoicInBase(Base):
__tablename__ = 'invoic_in'
document_id = Column(types.Unicode(20), primary_key=True)
document_date = Column(types.Date(), default=null())
document_type = Column(types.Unicode(3), default=null())
originator_reference_id = Column(types.Unicode(20), default=null())
The Dexterity subclass:
@implementer(IInvoicIn)
@adapter(IDexterityContent, Interface)
class InvoicIn(InvoicInBase, object):
""" My InvoicIn Content
"""
def __init__(self, context):
self.context = context
My view:
@implementer(IDexterityContent)
class InvoicInView(DefaultView):
""" Default view for InvoicIn content
"""
def __init__(self, context, request):
self.context = context
self.request = request
def __call__(self, content_type=None, *args, **kw):
context = self.context
request = self.request
return super(InvoicInView, self).__call__()
The view wrapper:
@implementer(IInvoicIn)
class InvoicInWrapper(Model):
"""A simple object representing the SQLAlchemy content within the Plone
context.
"""
portal_type = 'InvoicIn'
document_id = None
def __init__(self, document_id):
self.document_id = document_id
self.invoic_in = get_invoic_in_by_id(document_id)
def Title(self):
return self.invoic_in.document_id
def Description(self):
return u''
@property
def document_date(self):
return self.invoic_in.document_date
@property
def document_type(self):
return self.invoic_in.document_type
@property
def originator_reference_id(self):
return self.invoic_in.originator_reference_id
@property
def originator_reference_date(self):
return self.invoic_in.originator_reference_date
InitializeClass(InvoicInWrapper)
def get_invoic_in_by_id(invoic_in_id):
"""Given an invoic_in_id, return a SQLAlchemy InvoicIn object with that document_id."""
session = session_client(dbconnection)
result = session.query(InvoicIn).filter(InvoicIn.document_id == invoic_in_id).scalar()
return result
My zcml:
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser"
xmlns:i18n="http://namespaces.zope.org/i18n"
i18n_domain="pnz.erpediem.core">
<!-- Set up trajectory adapters, allowing us to view InvoicIns at
/invoic_ins/{id}
-->
<include package="collective.trajectory" />
<adapter factory="collective.trajectory.components.Traverser"
for="pnz.erpediem.core.interfaces.IInvoicInContainer
zope.publisher.interfaces.IRequest"/>
<!-- Make 'view', provide as a default view for a InvoicIn object -->
<browser:defaultView
name="view"
for=".model.IInvoicIn"
layer="...interfaces.IPnzErpediemCoreLayer"
/>
<browser:page
name="view"
for=".model.IInvoicIn"
class=".browser.InvoicInView"
permission="zope2.View"
layer="...interfaces.IPnzErpediemCoreLayer"
template="view.pt"
/>
</configure>
And the view:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal"
xmlns:i18n="http://xml.zope.org/namespaces/i18n"
lang="en"
metal:use-macro="context/@@main_template/macros/master"
i18n:domain="plone">
<body>
<metal:content-core fill-slot="content-core">
<metal:content-core define-macro="content-core">
<form id="form" class="enableFormTabbing pat-autotoc autotabs"
data-pat-autotoc="levels: legend; section: fieldset; className: autotabs">
<fieldset id="form-groups-main-content">
<legend i18n:translate="" >
<span tal:omit-tag i18n:translate="">Seite</span> 1
</legend>
<tal:block repeat="widget view/widgets/values" >
<tal:widget tal:replace="structure widget/@@ploneform-render-widget"/>
</tal:block>
</form>
</metal:content-core>
</metal:content-core>
</body>
</html>
Resulting in: