Ausserdem hat mich mein Gedächtnis ausgetrickst, uch hatte die Klasse PDecimal genannt und nicht PNumeric.
Zunächst mal die Basisklasse Param:
Code: Alles auswählen
import exceptions
from Cheetah.Template import Template
# What to do when validate fails
RAISE = 0 # Raise an exception
USE_DEFAULT = 1 # Use default value
ROBUST = 2 # Try to read what you can,
# even if some of the data
class ParamError(exceptions.TypeError):
def __init__(self, p, s=None):
exceptions.TypeError.__init__(self)
self.p = p
self.s = s
def __str__(self):
return "Parameter '%s' ist nicht vom Typ '%s'%s." % (
self.arg.display, self.arg.typeinfo,
self.s and (": " + s) or "")
class UncleanError(exceptions.TypeError):
def __init__(self):
exceptions.TypeError.__init__(self)
def __str__(self):
return "Parameter unvalidiert benutzt!"
class Param(Template):
"""
Encapsulates all functions and data related
to a parameter.
A parameter is something that is entered by a user
in a form and then used by a pice of code.
"""
def __init__(self, display, internal, value="", default=None, invalid=RAISE, *args, **kwargs):
Template.__init__(self, *args, **kwargs)
self.display = display
self.internal = internal
self.value = value
self.invalid = invalid
self.default = default
if self.default == None:
self.default = self.value
self.typeinfo = "Parameter"
self.is_clean = False
def validate(self):
"""Validate self.value, react as wanted on failure.
Override _clean() to validate your way."""
if not self._clean():
if self.invalid == RAISE:
raise ParamError(self)
else: # self.invalid in (ROBUST, USE_DEFAULT)
self.value = self.default
self.is_clean = True
def __str__(self):
"""Display the value in a nice form.
(Override _output() to make you own form)"""
if not self.is_clean:
#raise UncleanError(self)
# Be kind, validate now instead of complaining
self.validate()
return self._output()
# TODO: Move this to _input,
# And build a wrapper around it with a nice name
def input(self):
"""
Thats how the frontend may ask for self.value.
Note that its perfectly possible to choose
special in-/output-Methods for specific params
or classes at the frontend side.
"""
return """<input type="text" name="%s" value="%s" />""" % (self.internal, self.value)
def acquire(self, field):
"""
Read a "dirty" value from Field f.
"""
self.is_clean = False
_getfromfield(self, field)
def acquire_direct(self, v):
"""
Read a "dirty" value through argument v.
"""
self.is_clean = False
self._getdirect(v)
#
#
#
def _clean(self):
"""
If needed transform self.value to a type
pleasent for your Param-Class,
Return True if that went okay and self.value afterwards contains
some useable Data of your favourite type,
else return False.
"""
self.value = str(self.value)
return True
def _output(self):
"""Thats how the frontend may display self.value.
This function is meant to be overridden in subclasses."""
return str(self.value)
def _getfromfield(self, f):
"""
Override this method if you have
a different way of reading data.
Note that the type of value may change later in
clean(), just read here as far as you can get
WITHOUT error checking.
(i.e. dont raise an error here if the user
supplied something wrong or nothing or to much
or what ever can go wrong with the data.)
"""
self._getdirect(f.getfirst(self.internal))
def _getdirect(self, v):
"""
Override this method if you have
a different way of reading data directly.
You may call this from getfromfield.
Note that the type of value may change later in
clean(), just read here as far as you can get
WITHOUT error checking.
(i.e. dont raise an error here if the user
supplied something wrong or nothing or to much
or what ever can go wrong with the data.)
"""
self.value = v
Die heißt jetzt bei mir PTextBase weil ich von jeder Param-Klasse nochmal eine Cheetah-Klasse ableite, die hier z.B. PText heissen würde, wie gesagt, den cheetah-kram kann man vermeiden wenn man will.
Code: Alles auswählen
from Param import Param
from mod_python import apache
class PTextBase(Param):
"""
A parameter class for simple and short text.
"""
def __init__(self, display, internal, value="", maxlen=0, *args, **kwargs):
Param.__init__(self, display, internal, value, *args, **kwargs)
self.maxlen = maxlen
self.typeinfo = "Text" + (maxlen and (" der Länge %d" % maxlen) or "")
def _clean(self):
return (not self.maxlen) or len(self.value) <= self.maxlen
Ist zwar ein bisschen overhead, aber ich finds schöner als das in strings zu quoten.
(Ausserdem ist es damit als teil des Frontends austauschbar). Ich denke, der cheetah-code erklärt sich von selbst, wenn man python kann.
Code: Alles auswählen
#extends PTextBase
#def input
#set $sz = $maxlen and (" size=%d" % $maxlen) or ""
<input type="text" name="$internal" value="$value"$sz/>
#end def
Code: Alles auswählen
from Param import Param
class PDecimalBase(PText):
def __init__(self, display, internal, value="", digits=0, *args, **kwargs):
PTextBase.__init__(self, display, internal, value, *args, **kwargs)
self.typeinfo = "Dezimalzahl" + digits and (" mit %d Stellen" % digits) or "")
self.digits = digits
def _clean(self):
if (not self.digits) or len(self.value) == self.digits:
try:
self.value = int(self.value)
return True
except ValueError:
pass
return False
Code: Alles auswählen
from Param import Param, ParamError
class PListBase(Param):
"""
Encapsulates a List.
This means: The user can select one or more
items from a given list (choices).
The selection is the value.
"""
def __init__(self, display, internal, value="",
choices=(), multiple=False, *args, **kwargs):
Param.__init__(self, display, internal, value,
*args, **kwargs)
self.choices = choices
self.multiple = multiple
self.typeinfo = "Auswahl aus den Werten %s%s" % (
str(self.choices), (self.multiple and " (mehrere erlaubt)" or ""))
def _clean(self):
l = len(self.choices)
v = {}
if self.multiple:
v = {}
# self.value still is a list of
# (hopefully) indexes to choices
for x in self.value:
if type(x) == int and x in range(l):
v[x] = True # This is slightly ROBUST, but wont harm too much
else:
if not self.invalid == ROBUST:
return False
# Now self.values is something like
# {1: True, 4: True, 5: True}
# with all indices in range(l)
return True
else: # value should be an index for choices
try: self.value = int(self.value)
except: return False
return self.value in range(l)
def _output(self):
s = comma = ""
if self.multiple:
# Return a simple, comma-separated list. (Thats read- and parseable)
for i in range(len(self.choices)):
if i in self.value:
s += comma + self.choices[i]
comma = ", "
return s
else:
# Just return our value
return Param._output(self)
def _getfromfield(self, f):
if self.multiple: # We should receive a list
self.value = f.getlist(self.internal, [])
else: # Just get the value
super(PListBase, self).getfromfield(self, f)
Code: Alles auswählen
#extends PListBase
#def input
#set $ml = $multiple and ' multiple="multiple"' or ""
<select$ml>
#for $i in $range($len($choices))
#if $multiple
#set $sel = $value.has_key($i) and ' selected="selected"' or ""
#else
#set $sel = ($i == $value) and ' selected="selected"' or ""
#end if
<option value="$i"$sel>$choices[$i]</option>
#end for
</select>
#end def