Fields and Widgets
Hiding Hidden Field Garbas z3c.form Tutorial for Field and Widget Using Widgets in Simple HTML Templates
使用 z3c.form 時要加上 <include package="plone.app.z3c.form" />
Fieldset
snippet from Form Scheme Hints
from plone.supermodel import model class ISampleSchema(model.Schema): fieldset('extra', label=u'Extra Info', fields=['footer', 'dummy'] )
TextField from text/plain to text/html
# Add a New Item z3c.form-3.2.11-py2.7.egg/z3c/form/widget.py(131)update() -> if value not in (interfaces.NO_VALUE, PLACEHOLDER): (Pdb) value <NO_VALUE> (Pdb) dir() ['adapter', 'default_value', 'field', 'lookForDefault', 'pdb', 'self', 'value'] (Pdb) self <TextWidget 'form.widgets.title'> (Pdb) field <zope.schema._bootstrapfields.TextLine object at 0x7f081cf6afd0>
TextLine 如果沒有填值,並不會建立對應的變數,RichText 不管是否有填值,都會建立對應的變數,沒填值的會成為 None,Tuple 沒填值的會使用 missing_value=() 之類的預設值。
Default Value Tip and Example: select widget collective.nitf
數值欄位支援增減按鈕 <input type="number" name="quantity" min="1" max="5">
zope.schema 可選用的基本欄位定義在 _field.py 的 classImplements() 裡,像用了 Tuple 或 List 會出現 ComponentLookupError: ((<zope.schema._field.Tuple object at 0xb1c8e94c> 錯誤的話,可檢查是否指定 value_type 參數值。
TBA
<field name="audience" type="zope.schema.Set"> <title>Audience</title> <value_type type="zope.schema.Choice"> <values> <element>Beginner</element> <element>Advanced</element> <element>Professional</element> </values> </value_type> </field>
https://github.com/collective/Products.Poi/pull/23 Products.Poi 更新 Widget 範例 plone.app.dexterity/behaviors/metadata.py subjects Field (指定 required=True 的話可能導致 Module z3c.form.widget, line 132, in update Module z3c.form.converter, line 337, in toWidgetValue TypeError: 'NoneType' object is not iterable ):
- widget(subject=TextLinesFieldWidget) - subject = schema.List( + widget('subject', + AjaxSelectFieldWidget, + vocabulary='plone.app.vocabularies.Keywords') + subject = schema.Tuple( title=_(u'Subject'), description=_(u"Tags can be used to add arbitrary categorisation to " u"issues. The list below shows existing tags which "
collective.z3cform.widgets 可能要搭配舊版 plone.app.jquerytools,有人降級到 1.6.2 還是無效,指定 collective.z3cform.widgets 為 1.0b11 有成功。技術解法之一是執行 document.ready 的 Event Handler 來處理:
var removeDraggableDoBody = function() { // Abort if draggable behavior does not exists. if (!$.fn.draggable) { return; } var $body = $('body'); function removeDraggableFromBody() { if ($body.hasClass('ui-draggable')) { $body.draggable('destroy'); } } // Tries to remove behavior if already active. removeDraggableFromBody(); // Wait for behavior activation and immediately disables it. $body.on('dragcreate', function(event, ui) { removeDraggableFromBody(); }); };
plone.formwidget.recurrence 客製化範例: z3cform/interfaces.py IText, IWidget
plone.app.z3cform 版本在 Plone 4.3 vs 5.0 差距很大,可觀察 RichTextWidget 的改進變化,在 widget.py 1.0.x branch 只有 DateWidget DateteimeWidget,在 2.0.x branch 則新增 SelectWidget AjaxSelectWidget RelatedItemsWidget QueryStringWidget RichTextWidget LinkWidget SingleCheckBoxBoolWidget。
# multiple-input: value1;value2 my_data = schema.TextLine( title=_(u"My Data"), required=False, ) directives.widget( 'my_data', AjaxSelectFieldWidget, vocabulary='my.vocab.options' )
# multiple-input: (value1, value2) my_data = schema.Tuple( title=_(u"My Data"), required=False, value_type=schema.TextLine(), missing_value=(), ) directives.widget( 'my_data', AjaxSelectFieldWidget, vocabulary='my.vocab.options' ) <div tal:define="vals context/my_data|nothing" tal:condition="vals"> <tal:field i18n:translate="">My Data</tal:field>: <span tal:replace="python:view.t_title('my.vocab.options',vals[0])" /> </div>
Radio
Radio Button Widget: z3c.form.browser.radio.RadioFieldWidget
plone.app.widgets: Replace Specific DateTime Widgets in Plone 4.3 (pin versions for 4.3.3) and Replace All in Plone 5.x. upgrade from 1.4.0 to 1.6.0 (own jquery version)
讓 getVocabulary 在 non IPloneSiteRoot 情境裡也能運作
TextLinesFieldWidget 成為 plone.app.z3cform 預設值。
Collective.z3cform.KeywordWidget
annotation with z3c.form DictionaryField Hide Disable Read Write Permission
Conditional Fields Static Field Non Editable: 利用 Behavior Adapter Class 的 Read/Write Property "initial_editor" 和 IObjectAddedEvent Subscriber。
TypeError: ('Could not adapt', <Item at /mysite/photos/my-item>, <InterfaceClass collective.geo.geographer.interfaces.IWriteGeoreferenced>)
Relation
RelationChoice 用於單值欄位,RelationList 用於多值欄位。
Plone 4.2 之前的 RelationChoice/RelationList ContentTree Widget 以 plone.formwidget.autocomplete 為基礎,使用 2008 年代的 JavaScript 程式碼,在 plone.formwidget.autocomplete 2.0 開始使用 JQueryUI。
自訂 Dexterity 表單如果使用 Relation 欄位,應確認 setup.py 加進 plone.app.relationfield 相依關係,接著觀察是否會自動安裝相關套件 (在 Dexterity 1.0 時代會自動安裝),像是 plone.formwidget.contenttree, z3c.relationfield, plone.app.intid, five.intid, zope.intid, plone.formwidget.autocomplete, zc.relation, z3c.objpath, zope.app.container, zope.app.intid, zope.keyreference, zope.copypastemove;如果 (例如在 Dexterity 2.0 ) 預設沒有安裝 plone.formwidget.autocomplete 和 plone.formwidget.contenttree 必須考慮手動加進 setup.py 檔案。
Plone 5 預設內建 RelatedItemsWidget 不用再額外指定,但 Plone5 似乎朝 plone.app.vocabularies.catalog.CatalogSource 取代 Catalog 方向前進。
form.widget('slider_relation', RelatedItemsFieldWidget, vocabulary='plone.app.vocabularies.Catalog') slider_relation = RelationList( title=_(u"Slider Banners"), description=_(u"These banners will be used in the slider"), default=[], value_type=RelationChoice( title=_(u'Target'), source=ObjPathSourceBinder( object_provides=IBanner.__identifier__, )), required=False, )
想要使用別的 Widget 可以參考下列範例: 可以自動補齊,但只顯示比對到的文字,並無實際連到項目
from plone.autoform import directives directives.widget('presenter', AutocompleteFieldWidget)
Dexterity Version vs Archetypes Version
from z3c.relationfield.schema import RelationList, RelationChoice tags = RelationList( title = _(u'Tags'), default = [], value_type = RelationChoice( title = _(u'Tag'), source = ObjPathSourceBinder( navigation_tree_query = { ... }, portal_type = 'Document', ), ), required = False, )
tal:define="tpls context/temples|nothing"
tal:repeat="tpl tpls"
tpls type:list
tpl type:<class 'z3c.relationfield.relation.RelationValue'>
tpl.to_object type:<'Acquisition.ImplicitAcquisitionWrapper'>
tpl.to_id type:int
to_object 是 Relation 關係裡被指的物件,from_object 是起始物件。
z3c.form MultiWidget with RelationList as value_type
dictWithRelations = schema.Dict( title=u"Some Relations lists", required=False, key_type=schema.TextLine(title=_(u'afield')), value_type=relationfieldschema.RelationList( title=_(u'relations'), default=[], value_type=relationfieldschema.RelationChoice( source=CatalogSource(portal_type=['Document', 'Folder']) ), required=False, ) )
plone.portlet.collection 單一選項儲存 UID 的範例
uid = schema.Choice( title=_(u"Target Collection"), source=CatalogSource(portal_type=('Topic', 'Collection')), )
plone.app.relationfield 搭配 plone.app.contenttypes 在刪除連結後不會同步更新,過渡解法是利用 isBroken 來檢查。
ObjPathSourceBinder vs CatalogSource
Module plone.app.content.browser.vocabulary, line 220, in __call__ TypeError: 'NoneType' object has no attribute '__getitem__'
plone.formwidget.contenttree 處理 Empty Reference 問題
Back References: [1] [2] navigation_tree_query
from Acquisition import aq_inner from zope.component import getUtility from zope.intid.interfaces import IIntIds from zope.security import checkPermission from zc.relation.interfaces import ICatalog def back_references(source_object, attribute_name): """ Return back references from source object on specified attribute_name """ catalog = getUtility(ICatalog) intids = getUtility(IIntIds) result = [] for rel in catalog.findRelations( dict(to_id=intids.getId(aq_inner(source_object)), from_attribute=attribute_name) ): obj = intids.queryObject(rel.from_id) if obj is not None and checkPermission('zope2.View', obj): result.append(obj) return result
RelationChoice integration LookupError bug in Plone 4.3.3 RadioWidgets fails when the value is '--NOVALUE--' (self.noValueToken) Solgema.fullcalendar
z3c.relationfield 內建 Relation 欄位和 RelationValue 物件,透過 zc.relation 可以建立索引,透過 z3c.relationfieldui 可以建立使用者介面。
related_gender = z3c.relationfield.schema.RelationChoice( title=u'Related item', source=GenderSourceFactory(), required=False)
z3c.relationfield + BackReferences
Date Time
Plone 4.3.10 未啟用 plone.app.contenttypes 前,預設並不會安裝 plone.app.event,日期時間 Widget 使用傳統版本;啟用 plone.app.contenttypes 後,同時會啟用 plone.app.event。
the default datetime widget for dexterity < Plone 5:
https://github.com/collective/collective.z3cform.datetimewidget
the default datetime widget for plone.app.event < 1.2:
https://github.com/plone/plone.formwidget.datetime
this will be used in Plone 5 for most widgets and can already be used in Plone 4.3:
https://github.com/plone/plone.app.widgets
from zope import schema
date = schema.Date( title=_("Date"), )
Set Year Range collective.z3cform.datetimewidget 可以指定 min/max 值
from collective.z3cform.datetimewidget import DateWidget ... form.widget('birthday', DateWidget) birthday = schema.Date( title=_(u'Birthday'), description=_(u'your birthday'), required=True, min = date(1950,1,1), max = date(2015,1,1))
plone.formwidget.datetime Allows Empty Values jQuery Calendar Updated When Selection Changed dateable.chronos: calendar view
plone.formwidget.multifile: use plone.namedfile.interfaces.IFile instead of zope.app.file.interfaces.IFile plone.formwidget.recurrence Remove plone.formwidget.datetime Dependency
TypeError: 'datetime.datetime' object has no attribute 'getitem'
Change z3c.form Date Widget with JavaScript
When user wants to set Date or Datetime value and missed one of the fields (day, year, hour or minute) it silently sets it to None without error messages which input is not valid.
<form action="action_page.php"> Quantity (between 1 and 5): <input type="number" name="quantity" min="1" max="5"> <input type="submit"> </form>
eea.facetednavigation: Date Widget Reset Relative Date Widget Reset
Calendar
https://www.npmjs.com/package/snow-calendar
DataGrid
howto: Add collective.z3cform.datagridfield to buildout.cfg
Edit my_content.py
from collective.z3cform.datagridfield import DataGridFieldFactory from collective.z3cform.datagridfield import BlockDataGridFieldFactory
Create the schema for the table
class IAddress(form.Schema): address = schema.TextLine( title=(u"Address?"), required=True, )
Add it to the form schema
form.widget(address=BlockDataGridFieldFactory) address = schema.List(title=u"Address", required=False,
value_type=DictRow(title=u"Address", schema=IAddress, required=False))
Model Example: 注意 <defaultFactory /> 的設定位置
<field name="events" type="zope.schema.List" form:widget="collective.z3cform.datagridfield.DataGridFieldFactory"> <title>Events</title> <value_type type="collective.z3cform.datagridfield.DictRow"> <title>Events</title> <schema>myswimmingclub.content.swimming_meet_event.ISwimmingMeetEvent</schema> </value_type> <defaultFactory>myswimmingclub.content.defaults.DefaultStrokesFactory</defaultFactory> </field>
Context is no present in Vocabulary Factory
<field name="articles_list" type="zope.schema.Choice" lingua:independent="true"> <description /> <required>False</required> <title>Article List</title> <vocabulary>mdb_theme.ArticlesVocabulary</vocabulary> </field>
collective.z3cform.datagridfield sample code move collective.z3cform.datagridfield_demo separately pass list values for a choice field in a datagrid field in dexterity Vocabulary NO_VALUE DataGrid Inside DataGrid select2 widget
class MyWidget(CheckBoxWidget): ... @property def terms(self): catalog = getToolByName(self.context, 'portal_catalog') content = catalog( portal_type='my.type', ) return SimpleVocabulary([SimpleTerm(x.id, x, title=x.Title) for x in content])
RelationChoice Z3CFormValidation getSite() KSS
Using Relation patternslib clone for repeating fields
collective.datagridcolumns: DataGrid Field 延伸模組
MasterSelect
plone.formwidget.masterselect: plone5
MultiValue
collective.taxonomy: TaxonomySelectWidget: collective.z3cform.select2
Archetypes SelectionWidget Needs Populated
RichWidget URL Conversion by plone.outputfilter Plone5 的 plone.outputfilter 預設都是啟用 link-by-uid
欄位描述文字轉換成提示模式 Progress Bar Widget collective.upload
Model Driven Forms and Custom Fields
和 plone.app.registry GenericSetup 搭配的注意事項
#13450 datetime
Related Field: PloneConf 2012 UI Sprint Content Finder Demo from Mockup into plone.app.widgets
TokenInputFieldWidget: all keywords are loaded trimmed keywords
collective.z3cform.widgets 1.0b10 解決了 related.js 與 plone.formwidget.contenttree 衝突 draggable behaviour for entire page
collective.z3cform.datetimewidget min-max support
GeoLocation
Plone 早期有 Location 欄位,自由選填,沒有特別被應用。
EEA Geotags 提供 Map Picker 和 GeoNames 的查詢。
collective.z3cform.mapwidget 通常搭配 zope.schema.TextLine 使用
plone.formwidget.geolocation: leaflet maps integration
collective.geolocationbehavior
Model XML File
透過 plone.supermodel 可以使用 XML 格式來存取 Schema 設定值。
Multiple Selection 可參考 plone.app.layout/viewlets/keywords.pt 的 Filed under 範例修改 Template 來顯示多值
<field name="links" type="zope.schema.List"> <title>Related Items</title> <value_type type="zope.schema.Choice"> <title>Related</title> <source>plone.supermodel.tests.dummy_binder</source> </value_type> </field>
plone.supermodel XML Choosing Different Widgets Unicode-handling of Integer Values for IChoice
在 import 之前要先 load ZCML,不然會遇到 SupermodelParseError 錯誤。
Radio Button z3c.form.browser.radio RadioWidget
Obsolete RecurrenceField and use StringField
Remove annotation storage in behavior fields
Embedding z3c.form widget into Archetypes base_edit form
collective.tablepage Archetypes based
Primary Field
TypeError 'Could not adapt' IPrimaryFieldInfo
from plone.directives import form from zope import schema class IMyContentType(form.Schema): """ """ form.primary('some_field') some_field = schema.TextLine( title=u"Some field", ) another_field = schema.TextLine( title=u"Another field", )
搜尋指定欄位,例如所有 Image 欄位:
from plone.app.blob.interfaces import IBlobImageField from plone.dexterity.utils import iterSchemata from plone.namedfile.interfaces import INamedImageField from zope.schema import getFieldsInOrder ... image_fields = [] if getattr(aq_base(obj), 'Schema', None): # Archetypes for field in obj.Schema().values(): if not (IBlobImageField.providedBy(field) or INamedImageField.providedBy(field)): continue image_fields.append(field) else: # Dexterity for schemata in iterSchemata(obj): fields = getFieldsInOrder(schemata) for name, field in fields: if not (IBlobImageField.providedBy(field) or INamedImageField.providedBy(field)): continue image_fields.append(field) # Now iterate over all fields, whether AT or dexterity. for field in image_fields: field_instance = field.get(obj)
plone.supermodel 的 form 和 security 兩個 namespace 可以透過 plone.autoform Handler 來控制。
Solgema.ContextualContentMenu: Adds a right click menu that shows Plone's content and action menu
<model xmlns:i18n="http://xml.zope.org/namespaces/i18n" xmlns:security="http://namespaces.plone.org/supermodel/security" xmlns:marshal="http://namespaces.plone.org/supermodel/marshal" xmlns:form="http://namespaces.plone.org/supermodel/form" xmlns="http://namespaces.plone.org/supermodel/schema"> <schema> <field name="start_date" type="zope.schema.Date"> <description/> <title>Start Date</title> </field> <field name="end_date" type="zope.schema.Date"> <description/> <required>False</required> <title>End Date</title> </field> <field name="yes_no" type="zope.schema.Bool"> <description/> <required>False</required> <title>Yes No</title> <form:widget type="z3c.form.browser.radio.RadioFieldWidget"/> </field> <field name="single_choice" type="zope.schema.Choice"> <description/> <required>False</required> <title>Single Choice</title> <values> <element>Choice A</element> <element>Choice B</element> </values> </field> <field name="multiple_choice" type="zope.schema.Set"> <description/> <required>False</required> <title>Multiple Choice</title> <value_type type="zope.schema.Choice"> <values> <element>Item A</element> <element>Item B</element> <element>Item C</element> </values> </value_type> </field> </schema> </model>
start_date = schema.Date( title=_(u'Start Date'), ) yes_no = schema.Bool( title=_(u'Yes No'), ) directives.widget('yes_no', RadioFieldWidget) # not tested single_choice = schema.Choice( title=_(u'Single Choice'), required=False, vocabulary=single_option, ) multi_choice = schema.Set( title=_(u'Multiple Choice'), required=False, value_type=schema.Choice( vocabulary=multi_option, ) )