Package web :: Package web :: Module form
[hide private]
[frames] | no frames]

Source Code for Module web.web.form

  1  """ 
  2  HTML forms 
  3  (part of web.py) 
  4  """ 
  5   
  6  import copy, re 
  7  import webapi as web 
  8  import utils, net 
  9   
10 -def attrget(obj, attr, value=None):
11 if hasattr(obj, 'has_key') and obj.has_key(attr): return obj[attr] 12 if hasattr(obj, attr): return getattr(obj, attr) 13 return value
14
15 -class Form:
16 r""" 17 HTML form. 18 19 >>> f = Form(Textbox("x")) 20 >>> f.render() 21 '<table>\n <tr><th><label for="x">x</label></th><td><input type="text" id="x" name="x"/></td></tr>\n</table>' 22 """
23 - def __init__(self, *inputs, **kw):
24 self.inputs = inputs 25 self.valid = True 26 self.note = None 27 self.validators = kw.pop('validators', [])
28
29 - def __call__(self, x=None):
30 o = copy.deepcopy(self) 31 if x: o.validates(x) 32 return o
33
34 - def render(self):
35 out = '' 36 out += self.rendernote(self.note) 37 out += '<table>\n' 38 39 for i in self.inputs: 40 html = i.pre + i.render() + self.rendernote(i.note) + i.post 41 if i.is_hidden(): 42 out += ' <tr style="display: none;"><th></th><td>%s</td></tr>\n' % (html) 43 else: 44 out += ' <tr><th><label for="%s">%s</label></th><td>%s</td></tr>\n' % (i.id, net.websafe(i.description), html) 45 out += "</table>" 46 return out
47
48 - def render_css(self):
49 out = [] 50 out.append(self.rendernote(self.note)) 51 for i in self.inputs: 52 if not i.is_hidden(): 53 out.append('<label for="%s">%s</label>' % (i.id, net.websafe(i.description))) 54 out.append(i.pre) 55 out.append(i.render()) 56 out.append(self.rendernote(i.note)) 57 out.append(i.post) 58 out.append('\n') 59 return ''.join(out)
60
61 - def rendernote(self, note):
62 if note: return '<strong class="wrong">%s</strong>' % net.websafe(note) 63 else: return ""
64
65 - def validates(self, source=None, _validate=True, **kw):
66 source = source or kw or web.input() 67 out = True 68 for i in self.inputs: 69 v = attrget(source, i.name) 70 if _validate: 71 out = i.validate(v) and out 72 else: 73 i.set_value(v) 74 if _validate: 75 out = out and self._validate(source) 76 self.valid = out 77 return out
78
79 - def _validate(self, value):
80 self.value = value 81 for v in self.validators: 82 if not v.valid(value): 83 self.note = v.msg 84 return False 85 return True
86
87 - def fill(self, source=None, **kw):
88 return self.validates(source, _validate=False, **kw)
89
90 - def __getitem__(self, i):
91 for x in self.inputs: 92 if x.name == i: return x 93 raise KeyError, i
94
95 - def __getattr__(self, name):
96 # don't interfere with deepcopy 97 inputs = self.__dict__.get('inputs') or [] 98 for x in inputs: 99 if x.name == name: return x 100 raise AttributeError, name
101
102 - def get(self, i, default=None):
103 try: 104 return self[i] 105 except KeyError: 106 return default
107
108 - def _get_d(self): #@@ should really be form.attr, no?
109 return utils.storage([(i.name, i.get_value()) for i in self.inputs]) 110 d = property(_get_d) 111
112 -class Input(object):
113 - def __init__(self, name, *validators, **attrs):
114 self.name = name 115 self.validators = validators 116 self.attrs = attrs = AttributeList(attrs) 117 118 self.description = attrs.pop('description', name) 119 self.value = attrs.pop('value', None) 120 self.pre = attrs.pop('pre', "") 121 self.post = attrs.pop('post', "") 122 self.note = None 123 124 self.id = attrs.setdefault('id', self.get_default_id()) 125 126 if 'class_' in attrs: 127 attrs['class'] = attrs['class_'] 128 del attrs['class_']
129
130 - def is_hidden(self):
131 return False
132
133 - def get_type(self):
134 raise NotImplementedError
135
136 - def get_default_id(self):
137 return self.name
138
139 - def validate(self, value):
140 self.set_value(value) 141 142 for v in self.validators: 143 if not v.valid(value): 144 self.note = v.msg 145 return False 146 return True
147
148 - def set_value(self, value):
149 self.value = value
150
151 - def get_value(self):
152 return self.value
153
154 - def render(self):
155 attrs = self.attrs.copy() 156 attrs['type'] = self.get_type() 157 if self.value is not None: 158 attrs['value'] = self.value 159 attrs['name'] = self.name 160 return '<input %s/>' % attrs
161
162 - def rendernote(self, note):
163 if note: return '<strong class="wrong">%s</strong>' % net.websafe(note) 164 else: return ""
165
166 - def addatts(self):
167 # add leading space for backward-compatibility 168 return " " + str(self.attrs)
169
170 -class AttributeList(dict):
171 """List of atributes of input. 172 173 >>> a = AttributeList(type='text', name='x', value=20) 174 >>> a 175 <attrs: 'type="text" name="x" value="20"'> 176 """
177 - def copy(self):
178 return AttributeList(self)
179
180 - def __str__(self):
181 return " ".join(['%s="%s"' % (k, net.websafe(v)) for k, v in self.items()])
182
183 - def __repr__(self):
184 return '<attrs: %s>' % repr(str(self))
185
186 -class Textbox(Input):
187 """Textbox input. 188 189 >>> Textbox(name='foo', value='bar').render() 190 '<input type="text" id="foo" value="bar" name="foo"/>' 191 >>> Textbox(name='foo', value=0).render() 192 '<input type="text" id="foo" value="0" name="foo"/>' 193 """
194 - def get_type(self):
195 return 'text'
196
197 -class Password(Input):
198 """Password input. 199 200 >>> Password(name='password', value='secret').render() 201 '<input type="password" id="password" value="secret" name="password"/>' 202 """ 203
204 - def get_type(self):
205 return 'password'
206
207 -class Textarea(Input):
208 """Textarea input. 209 210 >>> Textarea(name='foo', value='bar').render() 211 '<textarea id="foo" name="foo">bar</textarea>' 212 """
213 - def render(self):
214 attrs = self.attrs.copy() 215 attrs['name'] = self.name 216 value = net.websafe(self.value or '') 217 return '<textarea %s>%s</textarea>' % (attrs, value)
218 249
250 -class Radio(Input):
251 - def __init__(self, name, args, *validators, **attrs):
252 self.args = args 253 super(Radio, self).__init__(name, *validators, **attrs)
254
255 - def render(self):
256 x = '<span>' 257 for arg in self.args: 258 if isinstance(arg, (tuple, list)): 259 value, desc= arg 260 else: 261 value, desc = arg, arg 262 attrs = self.attrs.copy() 263 attrs['name'] = self.name 264 attrs['type'] = 'radio' 265 attrs['value'] = arg 266 if self.value == arg: 267 attrs['checked'] = 'checked' 268 x += '<input %s/> %s' % (attrs, net.websafe(desc)) 269 x += '</span>' 270 return x
271
272 -class Checkbox(Input):
273 """Checkbox input. 274 275 >>> Checkbox('foo', value='bar', checked=True).render() 276 '<input checked="checked" type="checkbox" id="foo_bar" value="bar" name="foo"/>' 277 >>> Checkbox('foo', value='bar').render() 278 '<input type="checkbox" id="foo_bar" value="bar" name="foo"/>' 279 >>> c = Checkbox('foo', value='bar') 280 >>> c.validate('on') 281 True 282 >>> c.render() 283 '<input checked="checked" type="checkbox" id="foo_bar" value="bar" name="foo"/>' 284 """
285 - def __init__(self, name, *validators, **attrs):
286 self.checked = attrs.pop('checked', False) 287 Input.__init__(self, name, *validators, **attrs)
288
289 - def get_default_id(self):
290 value = utils.safestr(self.value or "") 291 return self.name + '_' + value.replace(' ', '_')
292
293 - def render(self):
294 attrs = self.attrs.copy() 295 attrs['type'] = 'checkbox' 296 attrs['name'] = self.name 297 attrs['value'] = self.value 298 299 if self.checked: 300 attrs['checked'] = 'checked' 301 return '<input %s/>' % attrs
302
303 - def set_value(self, value):
304 self.checked = bool(value)
305
306 - def get_value(self):
307 return self.checked
308
309 -class Button(Input):
310 """HTML Button. 311 312 >>> Button("save").render() 313 '<button id="save" name="save">save</button>' 314 >>> Button("action", value="save", html="<b>Save Changes</b>").render() 315 '<button id="action" value="save" name="action"><b>Save Changes</b></button>' 316 """
317 - def __init__(self, name, *validators, **attrs):
318 super(Button, self).__init__(name, *validators, **attrs) 319 self.description = ""
320
321 - def render(self):
322 attrs = self.attrs.copy() 323 attrs['name'] = self.name 324 if self.value is not None: 325 attrs['value'] = self.value 326 html = attrs.pop('html', None) or net.websafe(self.name) 327 return '<button %s>%s</button>' % (attrs, html)
328
329 -class Hidden(Input):
330 """Hidden Input. 331 332 >>> Hidden(name='foo', value='bar').render() 333 '<input type="hidden" id="foo" value="bar" name="foo"/>' 334 """
335 - def is_hidden(self):
336 return True
337
338 - def get_type(self):
339 return 'hidden'
340
341 -class File(Input):
342 """File input. 343 344 >>> File(name='f').render() 345 '<input type="file" id="f" name="f"/>' 346 """
347 - def get_type(self):
348 return 'file'
349
350 -class Validator:
351 - def __deepcopy__(self, memo): return copy.copy(self)
352 - def __init__(self, msg, test, jstest=None): utils.autoassign(self, locals())
353 - def valid(self, value):
354 try: return self.test(value) 355 except: return False
356 357 notnull = Validator("Required", bool) 358
359 -class regexp(Validator):
360 - def __init__(self, rexp, msg):
361 self.rexp = re.compile(rexp) 362 self.msg = msg
363
364 - def valid(self, value):
365 return bool(self.rexp.match(value))
366 367 if __name__ == "__main__": 368 import doctest 369 doctest.testmod() 370