[gen] Added field.persist to avoid storing values for fields that do not require it (like master fields only used to determine selectable values among slave fields).
This commit is contained in:
parent
b8ceb66a49
commit
ea08d7981f
19 changed files with 106 additions and 75 deletions
|
@ -61,8 +61,7 @@ class Field:
|
|||
value=zobj.getFormattedFieldValue(name, rawValue, showChanges);
|
||||
requestValue=zobj.getRequestFieldValue(name);
|
||||
inRequest=req.has_key(name);
|
||||
errors=errors|();
|
||||
inError=name in errors;
|
||||
error=req.get('%s_error' % name);
|
||||
isMultiple=(field.multiplicity[1] == None) or \
|
||||
(field.multiplicity[1] > 1);
|
||||
masterCss=field.slaves and ('master_%s' % name) or '';
|
||||
|
@ -86,8 +85,8 @@ class Field:
|
|||
src=":url('help')"/></acronym>''')
|
||||
|
||||
# Displays validation-error-related info about a field.
|
||||
pxValidation = Px('''<x><acronym if="inError" title=":errors[name]"><img
|
||||
src=":url('warning')"/></acronym><img if="not inError"
|
||||
pxValidation = Px('''<x><acronym if="error" title=":error"><img
|
||||
src=":url('warning')"/></acronym><img if="not error"
|
||||
src=":url('warning_no.gif')"/></x>''')
|
||||
|
||||
# Displays the fact that a field is required.
|
||||
|
@ -107,7 +106,7 @@ class Field:
|
|||
layouts, move, indexed, searchable, specificReadPermission,
|
||||
specificWritePermission, width, height, maxChars, colspan,
|
||||
master, masterValue, focus, historized, sync, mapping, label,
|
||||
sdefault, scolspan, swidth, sheight):
|
||||
sdefault, scolspan, swidth, sheight, persist):
|
||||
# The validator restricts which values may be defined. It can be an
|
||||
# interval (1,None), a list of string values ['choice1', 'choice2'],
|
||||
# a regular expression, a custom function, a Selection instance, etc.
|
||||
|
@ -215,6 +214,10 @@ class Field:
|
|||
# Width and height for the search widget
|
||||
self.swidth = swidth or width
|
||||
self.sheight = sheight or height
|
||||
# "persist" indicates if field content must be stored in the database.
|
||||
# For some fields it is not wanted (ie, fields used only as masters to
|
||||
# update slave's selectable values).
|
||||
self.persist = persist
|
||||
|
||||
def init(self, name, klass, appName):
|
||||
'''When the application server starts, this secondary constructor is
|
||||
|
@ -584,26 +587,14 @@ class Field:
|
|||
res += '+'
|
||||
return res
|
||||
|
||||
def getOnChange(self, name, zobj, layoutType):
|
||||
def getOnChange(self, zobj, layoutType):
|
||||
'''When this field is a master, this method computes the call to the
|
||||
Javascript function that will be called when its value changes (in
|
||||
order to update slaves).'''
|
||||
if not self.slaves: return ''
|
||||
q = zobj.getTool().quote
|
||||
# Create the dict of request values for slave fields.
|
||||
rvs = {}
|
||||
req = zobj.REQUEST
|
||||
for slave in self.slaves:
|
||||
name = slave.name
|
||||
if not req.has_key(name): continue
|
||||
if not req[name]: continue
|
||||
rvs[name] = req[name]
|
||||
if rvs:
|
||||
rvs = ',%s' % sutils.getStringDict(rvs)
|
||||
else:
|
||||
rvs = ''
|
||||
return 'updateSlaves(this,null,%s,%s%s)' % \
|
||||
(q(zobj.absolute_url()), q(layoutType), rvs)
|
||||
return 'updateSlaves(this,null,%s,%s)' % \
|
||||
(q(zobj.absolute_url()), q(layoutType))
|
||||
|
||||
def isEmptyValue(self, value, obj=None):
|
||||
'''Returns True if the p_value must be considered as an empty value.'''
|
||||
|
@ -680,7 +671,7 @@ class Field:
|
|||
def store(self, obj, value):
|
||||
'''Stores the p_value (produced by m_getStorableValue) that complies to
|
||||
p_self type definition on p_obj.'''
|
||||
setattr(obj, self.name, value)
|
||||
if self.persist: setattr(obj, self.name, value)
|
||||
|
||||
def callMethod(self, obj, method, cache=True):
|
||||
'''This method is used to call a p_method on p_obj. p_method is part of
|
||||
|
|
|
@ -74,7 +74,7 @@ class Action(Field):
|
|||
move, indexed, False, specificReadPermission,
|
||||
specificWritePermission, width, height, None, colspan,
|
||||
master, masterValue, focus, historized, False, mapping,
|
||||
label, None, None, None, None)
|
||||
label, None, None, None, None, False)
|
||||
self.validable = False
|
||||
|
||||
def getDefaultLayouts(self): return {'view': 'l-f', 'edit': 'lrv-f'}
|
||||
|
|
|
@ -23,19 +23,17 @@ from appy.gen.layout import Table
|
|||
class Boolean(Field):
|
||||
'''Field for storing boolean values.'''
|
||||
|
||||
pxView = pxCell = Px('''
|
||||
<x><x>:value</x>
|
||||
<input type="hidden" if="masterCss"
|
||||
class=":masterCss" value=":rawValue" name=":name" id=":name"/>
|
||||
</x>''')
|
||||
pxView = pxCell = Px('''<x>:value</x>
|
||||
<input type="hidden" if="masterCss"
|
||||
class=":masterCss" value=":rawValue" name=":name" id=":name"/>''')
|
||||
|
||||
pxEdit = Px('''
|
||||
<x var="isChecked=field.isChecked(zobj, rawValue)">
|
||||
<input type="checkbox" name=":name + '_visible'" id=":name"
|
||||
class=":masterCss" checked=":isChecked"
|
||||
onclick=":'toggleCheckbox(%s, %s); %s' % (q(name), \
|
||||
q('%s_hidden' % name), field.getOnChange(name, zobj, \
|
||||
layoutType))"/>
|
||||
q('%s_hidden' % name), \
|
||||
field.getOnChange(zobj, layoutType))"/>
|
||||
<input type="hidden" name=":name" id=":'%s_hidden' % name"
|
||||
value=":isChecked and 'True' or 'False'"/>
|
||||
</x>''')
|
||||
|
@ -64,13 +62,14 @@ class Boolean(Field):
|
|||
specificWritePermission=False, width=None, height=None,
|
||||
maxChars=None, colspan=1, master=None, masterValue=None,
|
||||
focus=False, historized=False, mapping=None, label=None,
|
||||
sdefault=False, scolspan=1, swidth=None, sheight=None):
|
||||
sdefault=False, scolspan=1, swidth=None, sheight=None,
|
||||
persist=True):
|
||||
Field.__init__(self, validator, multiplicity, default, show, page,
|
||||
group, layouts, move, indexed, searchable,
|
||||
specificReadPermission, specificWritePermission, width,
|
||||
height, None, colspan, master, masterValue, focus,
|
||||
historized, True, mapping, label, sdefault, scolspan,
|
||||
swidth, sheight)
|
||||
swidth, sheight, persist)
|
||||
self.pythonType = bool
|
||||
|
||||
# Layout including a description
|
||||
|
|
|
@ -222,7 +222,7 @@ class Calendar(Field):
|
|||
layouts, move, False, False, specificReadPermission,
|
||||
specificWritePermission, width, height, None, colspan,
|
||||
master, masterValue, focus, False, True, mapping, label,
|
||||
None, None, None, None)
|
||||
None, None, None, None, True)
|
||||
# eventTypes can be a "static" list or tuple of strings that identify
|
||||
# the types of events that are supported by this calendar. It can also
|
||||
# be a method that computes such a "dynamic" list or tuple. When
|
||||
|
|
|
@ -70,7 +70,7 @@ class Computed(Field):
|
|||
specificReadPermission, specificWritePermission, width,
|
||||
height, None, colspan, master, masterValue, focus,
|
||||
historized, sync, mapping, label, sdefault, scolspan,
|
||||
swidth, sheight)
|
||||
swidth, sheight, False)
|
||||
self.validable = False
|
||||
|
||||
def getValue(self, obj):
|
||||
|
|
|
@ -173,7 +173,8 @@ class Date(Field):
|
|||
specificWritePermission=False, width=None, height=None,
|
||||
maxChars=None, colspan=1, master=None, masterValue=None,
|
||||
focus=False, historized=False, mapping=None, label=None,
|
||||
sdefault=None, scolspan=1, swidth=None, sheight=None):
|
||||
sdefault=None, scolspan=1, swidth=None, sheight=None,
|
||||
persist=True):
|
||||
self.format = format
|
||||
self.calendar = calendar
|
||||
self.startYear = startYear
|
||||
|
@ -186,7 +187,7 @@ class Date(Field):
|
|||
specificReadPermission, specificWritePermission, width,
|
||||
height, None, colspan, master, masterValue, focus,
|
||||
historized, True, mapping, label, sdefault, scolspan,
|
||||
swidth, sheight)
|
||||
swidth, sheight, persist)
|
||||
|
||||
def getCss(self, layoutType, res):
|
||||
# CSS files are only required if the calendar must be shown.
|
||||
|
|
|
@ -279,7 +279,7 @@ class File(Field):
|
|||
specificReadPermission, specificWritePermission, width,
|
||||
height, None, colspan, master, masterValue, focus,
|
||||
historized, True, mapping, label, sdefault, scolspan,
|
||||
swidth, sheight)
|
||||
swidth, sheight, True)
|
||||
|
||||
@staticmethod
|
||||
def getFileObject(filePath, fileName=None, zope=False):
|
||||
|
|
|
@ -58,7 +58,7 @@ class Float(Field):
|
|||
maxChars=13, colspan=1, master=None, masterValue=None,
|
||||
focus=False, historized=False, mapping=None, label=None,
|
||||
sdefault=('',''), scolspan=1, swidth=None, sheight=None,
|
||||
precision=None, sep=(',', '.'), tsep=' '):
|
||||
persist=True, precision=None, sep=(',', '.'), tsep=' '):
|
||||
# The precision is the number of decimal digits. This number is used
|
||||
# for rendering the float, but the internal float representation is not
|
||||
# rounded.
|
||||
|
@ -80,7 +80,7 @@ class Float(Field):
|
|||
specificReadPermission, specificWritePermission, width,
|
||||
height, maxChars, colspan, master, masterValue, focus,
|
||||
historized, True, mapping, label, sdefault, scolspan,
|
||||
swidth, sheight)
|
||||
swidth, sheight, persist)
|
||||
self.pythonType = float
|
||||
|
||||
def getFormattedValue(self, obj, value, showChanges=False):
|
||||
|
|
|
@ -34,6 +34,6 @@ class Info(Field):
|
|||
move, indexed, False, specificReadPermission,
|
||||
specificWritePermission, width, height, None, colspan,
|
||||
master, masterValue, focus, historized, False, mapping,
|
||||
label, None, None, None, None)
|
||||
label, None, None, None, None, False)
|
||||
self.validable = False
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
|
@ -54,13 +54,14 @@ class Integer(Field):
|
|||
specificWritePermission=False, width=5, height=None,
|
||||
maxChars=13, colspan=1, master=None, masterValue=None,
|
||||
focus=False, historized=False, mapping=None, label=None,
|
||||
sdefault=('',''), scolspan=1, swidth=None, sheight=None):
|
||||
sdefault=('',''), scolspan=1, swidth=None, sheight=None,
|
||||
persist=True):
|
||||
Field.__init__(self, validator, multiplicity, default, show, page,
|
||||
group, layouts, move, indexed, searchable,
|
||||
specificReadPermission, specificWritePermission, width,
|
||||
height, maxChars, colspan, master, masterValue, focus,
|
||||
historized, True, mapping, label, sdefault, scolspan,
|
||||
swidth, sheight)
|
||||
swidth, sheight, persist)
|
||||
self.pythonType = long
|
||||
|
||||
def validateValue(self, obj, value):
|
||||
|
|
|
@ -83,7 +83,8 @@ class List(Field):
|
|||
group, layouts, move, indexed, False,
|
||||
specificReadPermission, specificWritePermission, width,
|
||||
height, None, colspan, master, masterValue, focus,
|
||||
historized, True, mapping, label, None, None, None, None)
|
||||
historized, True, mapping, label, None, None, None, None,
|
||||
True)
|
||||
self.validable = True
|
||||
# Tuples of (names, Field instances) determining the format of every
|
||||
# element in the list.
|
||||
|
|
|
@ -54,7 +54,7 @@ class Ogone(Field):
|
|||
move, False, False,specificReadPermission,
|
||||
specificWritePermission, width, height, None, colspan,
|
||||
master, masterValue, focus, False, True, mapping, label,
|
||||
None, None, None, None)
|
||||
None, None, None, None, False)
|
||||
# orderMethod must contain a method returning a dict containing info
|
||||
# about the order. Following keys are mandatory:
|
||||
# * orderID An identifier for the order. Don't use the object UID
|
||||
|
|
|
@ -84,7 +84,9 @@ class Pod(Field):
|
|||
move, indexed, searchable, specificReadPermission,
|
||||
specificWritePermission, width, height, None, colspan,
|
||||
master, masterValue, focus, historized, False, mapping,
|
||||
label, None, None, None, None)
|
||||
label, None, None, None, None, True)
|
||||
# Param "persist" is set to True but actually, persistence for a pod
|
||||
# field is determined by freezing.
|
||||
self.validable = False
|
||||
|
||||
def isFrozen(self, obj):
|
||||
|
|
|
@ -286,7 +286,7 @@ class Ref(Field):
|
|||
uids=[o.UID() for o in \
|
||||
field.getLinkedObjects(zobj).objects]"
|
||||
name=":name" id=":name" size=":isMultiple and field.height or ''"
|
||||
onchange=":field.getOnChange(name, zobj, layoutType)"
|
||||
onchange=":field.getOnChange(zobj, layoutType)"
|
||||
multiple=":isMultiple">
|
||||
<option value="" if="not isMultiple">:_('choose_a_value')</option>
|
||||
<option for="ztied in zobjects" var2="uid=ztied.o.UID()"
|
||||
|
@ -328,8 +328,8 @@ class Ref(Field):
|
|||
label=None, queryable=False, queryFields=None, queryNbCols=1,
|
||||
navigable=False, searchSelect=None, changeOrder=True,
|
||||
sdefault='', scolspan=1, swidth=None, sheight=None,
|
||||
render='list', menuIdMethod=None, menuInfoMethod=None,
|
||||
menuUrlMethod=None):
|
||||
persist=True, render='list', menuIdMethod=None,
|
||||
menuInfoMethod=None, menuUrlMethod=None):
|
||||
self.klass = klass
|
||||
self.attribute = attribute
|
||||
# May the user add new objects through this ref ?
|
||||
|
@ -431,7 +431,7 @@ class Ref(Field):
|
|||
specificReadPermission, specificWritePermission, width,
|
||||
height, None, colspan, master, masterValue, focus,
|
||||
historized, sync, mapping, label, sdefault, scolspan,
|
||||
swidth, sheight)
|
||||
swidth, sheight, persist)
|
||||
self.validable = self.link
|
||||
|
||||
def getDefaultLayouts(self):
|
||||
|
@ -662,6 +662,7 @@ class Ref(Field):
|
|||
* a Zope object;
|
||||
* a Appy object;
|
||||
* a list of Appy or Zope objects.'''
|
||||
if not self.persist: return
|
||||
# Standardize p_value into a list of Zope objects
|
||||
objects = value
|
||||
if not objects: objects = []
|
||||
|
@ -759,6 +760,11 @@ class Ref(Field):
|
|||
res = self.masterValue(obj, masterValues)
|
||||
return res
|
||||
else:
|
||||
# If this field is a ajax-updatable slave, no need to compute
|
||||
# selectable objects: it will be overridden by method
|
||||
# self.masterValue by a subsequent ajax request (=the "if" statement
|
||||
# above).
|
||||
if self.masterValue and callable(self.masterValue): return []
|
||||
if not self.select:
|
||||
# No select method has been defined: we must retrieve all
|
||||
# objects of the referred type that the user is allowed to
|
||||
|
|
|
@ -110,7 +110,7 @@ class String(Field):
|
|||
withTranslations=True, withBlankValue=True)"
|
||||
name=":name" id=":name" class=":masterCss"
|
||||
multiple=":isMultiple and 'multiple' or ''"
|
||||
onchange=":field.getOnChange(name, zobj, layoutType)"
|
||||
onchange=":field.getOnChange(zobj, layoutType)"
|
||||
size=":isMultiple and field.height or 1">
|
||||
<option for="val in possibleValues" value=":val[0]"
|
||||
selected=":field.isSelected(zobj, name, val[0], rawValue)"
|
||||
|
@ -292,8 +292,9 @@ class String(Field):
|
|||
width=None, height=None, maxChars=None, colspan=1, master=None,
|
||||
masterValue=None, focus=False, historized=False, mapping=None,
|
||||
label=None, sdefault='', scolspan=1, swidth=None, sheight=None,
|
||||
transform='none', styles=('p','h1','h2','h3','h4'),
|
||||
allowImageUpload=True, inlineEdit=False):
|
||||
persist=True, transform='none',
|
||||
styles=('p','h1','h2','h3','h4'), allowImageUpload=True,
|
||||
inlineEdit=False):
|
||||
# According to format, the widget will be different: input field,
|
||||
# textarea, inline editor... Note that there can be only one String
|
||||
# field of format CAPTCHA by page, because the captcha challenge is
|
||||
|
@ -318,7 +319,7 @@ class String(Field):
|
|||
specificReadPermission, specificWritePermission, width,
|
||||
height, maxChars, colspan, master, masterValue, focus,
|
||||
historized, True, mapping, label, sdefault, scolspan,
|
||||
swidth, sheight)
|
||||
swidth, sheight, persist)
|
||||
self.isSelect = self.isSelection()
|
||||
# If self.isSelect, self.sdefault must be a list of value(s).
|
||||
if self.isSelect and not sdefault:
|
||||
|
@ -390,6 +391,7 @@ class String(Field):
|
|||
|
||||
def store(self, obj, value):
|
||||
'''When the value is XHTML, we perform some cleanup.'''
|
||||
if not self.persist: return
|
||||
if (self.format == String.XHTML) and value:
|
||||
# When image upload is allowed, ckeditor inserts some "style" attrs
|
||||
# (ie for image size when images are resized). So in this case we
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue