def accepts( self, request_vars, session=None, formname='%(tablename)s_%(record_id)s', keepvalues=False, onvalidation=None, dbio=True, hideerror=False, ): """ same as FORM.accepts but also does insert, update or delete in SQLDB. """ keyed = hasattr(self.table, '_primarykey') if self.record: if keyed: formname_id = '.'.join([ str(self.record[k]) for k in self.table._primarykey if hasattr(self.record, k) ]) record_id = dict([(k, request_vars[k]) for k in self.table._primarykey]) else: (formname_id, record_id) = \ (self.record.id, request_vars.get('id', None)) keepvalues = True else: if keyed: formname_id = 'create' record_id = dict([(k, None) for k in self.table._primarykey]) else: (formname_id, record_id) = ('create', None) if not keyed and isinstance(record_id, (list, tuple)): record_id = record_id[0] if formname: formname = formname % dict(tablename=self.table._tablename, record_id=formname_id) # ## THIS IS FOR UNIQUE RECORDS, read IS_NOT_IN_DB for fieldname in self.fields: field = self.table[fieldname] requires = field.requires or [] if not isinstance(requires, (list, tuple)): requires = [requires] [ item.set_self_id(self.record_id) for item in requires if hasattr(item, 'set_self_id') and self.record_id ] # ## END fields = {} for key in self.vars: fields[key] = self.vars[key] ret = FORM.accepts( self, request_vars, session, formname, keepvalues, onvalidation, hideerror=hideerror, ) if not ret and self.record and self.errors: ### if there are errors in update mode # and some errors refers to an already uploaded file # delete error if # - user not trying to upload a new file # - there is existing file and user is not trying to delete it # this is because removing the file may not pass validation for key in self.errors.keys(): if self.table[key].type == 'upload' \ and request_vars.get(key,None) in (None,'') \ and self.record[key] \ and not key+UploadWidget.ID_DELETE_SUFFIX in request_vars: del self.errors[key] if not self.errors: ret = True requested_delete = \ request_vars.get(self.FIELDNAME_REQUEST_DELETE, False) self.custom.end = TAG[''](self.hidden_fields(), self.custom.end) auch = record_id and self.errors and requested_delete # auch is true when user tries to delete a record # that does not pass validation, yet it should be deleted if not ret and not auch: for fieldname in self.fields: field = self.table[fieldname] if fieldname in self.vars: value = self.vars[fieldname] elif self.record: value = self.record[fieldname] else: value = self.table[fieldname].default #was value = request_vars[fieldname] if hasattr(field, 'widget') and field.widget\ and fieldname in request_vars: row_id = '%s_%s%s' % (self.table, fieldname, SQLFORM.ID_ROW_SUFFIX) widget = field.widget(field, value) self.field_parent[row_id].components = [widget] self.field_parent[row_id]._traverse(False, hideerror) self.custom.widget[fieldname] = widget return ret if record_id and str(record_id) != str(self.record_id): raise SyntaxError, 'user is tampering with form\'s record_id: ' \ '%s != %s' % (record_id, self.record_id) if requested_delete and self.custom.deletable: if dbio: if keyed: qry = reduce(lambda x, y: x & y, [ self.table[k] == record_id[k] for k in self.table._primarykey ]) if self.table._db(qry).delete(): self.vars.update(record_id) else: self.table._db(self.table.id == self.record.id).delete() self.vars.id = self.record.id self.errors.clear() for component in self.elements('input, select, textarea'): component['_disabled'] = True return True for fieldname in self.fields: if not fieldname in self.table: continue if not self.ignore_rw and not self.table[fieldname].writable: continue field = self.table[fieldname] if field.type == 'id': continue if field.type == 'boolean': if self.vars.get(fieldname, False): self.vars[fieldname] = fields[fieldname] = True else: self.vars[fieldname] = fields[fieldname] = False elif field.type == 'password' and self.record\ and request_vars.get(fieldname, None) == \ PasswordWidget.DEFAULT_PASSWORD_DISPLAY: continue # do not update if password was not changed elif field.type == 'upload': f = self.vars[fieldname] fd = fieldname + '__delete' if f == '' or f == None: if self.vars.get(fd, False) or not self.record: fields[fieldname] = '' else: fields[fieldname] = self.record[fieldname] self.vars[fieldname] = fields[fieldname] continue elif hasattr(f, 'file'): (source_file, original_filename) = (f.file, f.filename) elif isinstance(f, (str, unicode)): ### do not know why this happens, it should not (source_file, original_filename) = \ (cStringIO.StringIO(f), 'file.txt') newfilename = field.store(source_file, original_filename) # this line is for backward compatibility only self.vars['%s_newfilename' % fieldname] = newfilename fields[fieldname] = newfilename if isinstance(field.uploadfield, str): fields[field.uploadfield] = source_file.read() # proposed by Hamdy (accept?) do we need fields at this point? self.vars[fieldname] = fields[fieldname] continue elif fieldname in self.vars: fields[fieldname] = self.vars[fieldname] elif field.default == None and field.type != 'blob': self.errors[fieldname] = 'no data' return False if field.type == 'integer': if fields[fieldname] != None: fields[fieldname] = int(fields[fieldname]) elif str(field.type).startswith('reference'): if fields[fieldname] != None and isinstance( self.table, Table) and not keyed: fields[fieldname] = int(fields[fieldname]) elif field.type == 'double': if fields[fieldname] != None: fields[fieldname] = float(fields[fieldname]) for fieldname in self.vars: if fieldname != 'id' and fieldname in self.table.fields\ and not fieldname in fields and not fieldname\ in request_vars: fields[fieldname] = self.vars[fieldname] if dbio: if keyed: if reduce(lambda x, y: x and y, record_id.values()): # if record_id if fields: qry = reduce(lambda x, y: x & y, [ self.table[k] == self.record[k] for k in self.table._primarykey ]) self.table._db(qry).update(**fields) else: pk = self.table.insert(**fields) if pk: self.vars.update(pk) else: ret = False else: if record_id: self.vars.id = self.record.id if fields: self.table._db(self.table.id == self.record.id).update( **fields) else: self.vars.id = self.table.insert(**fields) return ret
def accepts( self, request_vars, formname='%(tablename)s_%(record_id)s', keepvalues=False, onvalidation=None, hideerror=False, ): """ similar FORM.accepts but also does insert, update or delete in SQLDB. but if detect_record_change == True than: form.record_changed = False (record is properly validated/submitted) form.record_changed = True (record cannot be submitted because changed) elseif detect_record_change == False than: form.record_changed = None """ # implement logic to detect whether record exist but has been modified # server side _vars_ = {} request_vars = copy.deepcopy(request_vars) for itm in request_vars: if isinstance(request_vars[itm],(list,tuple)): if not (str(itm) in self.table.fields and str(self.table[itm].type).startswith("list::")): request_vars[itm] = request_vars[itm][-1] if self.record: (formname_id, record_id) = ( self.record.get(self.record_pk_name, None), request_vars.get(self.record_pk_name, None)) keepvalues = True else: (formname_id, record_id) = ('create', None) if formname: formname = formname % dict(tablename = self.table._tablename, record_id = formname_id) for fieldname in self.fields: field = self.table[fieldname] requires = field.requires or [] if not isinstance(requires, (list, tuple)): requires = [requires] # ## END fields = {} for key in self.vars: fields[key] = self.vars[key] ret = FORM.accepts( self, request_vars, formname, keepvalues, onvalidation, hideerror=hideerror, ) if not ret and self.record and self.errors: ### if there are errors in update mode # and some errors refers to an already uploaded file # delete error if # - user not trying to upload a new file # - there is existing file and user is not trying to delete it # this is because removing the file may not pass validation for key in self.errors.keys(): if self.table[key].type == 'upload' \ and request_vars.get(key,None) in (None,'') \ and self.record[key] \ and not key+UploadWidget.ID_DELETE_SUFFIX in request_vars: del self.errors[key] if not self.errors: ret = True requested_delete = \ request_vars.get(self.FIELDNAME_REQUEST_DELETE, False) self.custom.end = TAG[''](self.hidden_fields(), self.custom.end) auch = record_id and self.errors and requested_delete # auch is true when user tries to delete a record # that does not pass validation, yet it should be deleted if not ret and not auch: for fieldname in self.fields: field = self.table[fieldname] ### this is a workaround! widgets should always have default not None! if not field.widget and field.type.startswith('list:') and \ not OptionsWidget.has_options(field): field.widget = self.widgets.list.widget if hasattr(field, 'widget') and field.widget and fieldname in request_vars: if fieldname in self.vars: value = self.vars[fieldname] elif self.record: value = self.record[fieldname] else: value = self.table[fieldname].default row_id = '%s_%s%s' % (self.table,fieldname,FORMBUILDER.ID_ROW_SUFFIX) widget = field.widget(field, value) self.field_parent[row_id].components = [ widget ] if not field.type.startswith('list:'): self.field_parent[row_id]._traverse(False,hideerror) self.custom.widget[ fieldname ] = widget return ret self.record_id = record_id if requested_delete and self.custom.deletable: self.errors.clear() for component in self.elements('input, select, textarea'): component['_disabled'] = True return True for fieldname in self.fields: if not fieldname in self.table: continue if not self.ignore_rw and not self.table[fieldname].writable: ### this happens because FROM has no knowledge of writable ### and thinks that a missing boolean field is a None if self.table[fieldname].type == 'boolean' and self.vars[fieldname]==None: del self.vars[fieldname] continue field = self.table[fieldname] if field.type == 'id': continue if field.type == 'boolean': if self.vars.get(fieldname, False): self.vars[fieldname] = fields[fieldname] = True else: self.vars[fieldname] = fields[fieldname] = False elif field.type == 'password' and self.record\ and request_vars.get(fieldname, None) == \ PasswordWidget.DEFAULT_PASSWORD_DISPLAY: continue # do not update if password was not changed elif field.type == 'upload': if self.vars.get("%s__delete"%fieldname,False): self.vars[fieldname] = "" del self.vars["%s__delete"%fieldname] continue if self.custom_file: self.vars[fieldname] = self.custom_file(field, request_vars) else: self.vars[fieldname] = field.store(request_vars.get(fieldname,""),request_vars.get("%s.original"%fieldname,"")) continue elif fieldname in self.vars: fields[fieldname] = self.vars[fieldname] elif field.default == None and field.type!='blob': self.errors[fieldname] = 'no data' return False value = fields.get(fieldname,None) if field.type == 'list:string': if not isinstance(value,(tuple,list)): fields[fieldname] = value and [value] or [] elif field.type.startswith('list:'): if not isinstance(value,list): fields[fieldname] = [safe_int(x) for x in (value and [value] or [])] elif field.type == 'integer': if value != None: fields[fieldname] = safe_int(value) elif field.type == 'double': if value != None: fields[fieldname] = safe_float(value) for fieldname in self.vars: if fieldname != 'id' and fieldname in self.table.fields\ and not fieldname in fields and not fieldname\ in request_vars: fields[fieldname] = self.vars[fieldname] return ret
def accepts( self, request_vars, formname='%(tablename)s_%(record_id)s', keepvalues=False, onvalidation=None, hideerror=False, ): """ similar FORM.accepts but also does insert, update or delete in SQLDB. but if detect_record_change == True than: form.record_changed = False (record is properly validated/submitted) form.record_changed = True (record cannot be submitted because changed) elseif detect_record_change == False than: form.record_changed = None """ # implement logic to detect whether record exist but has been modified # server side _vars_ = {} request_vars = copy.deepcopy(request_vars) for itm in request_vars: if isinstance(request_vars[itm], (list, tuple)): if not (str(itm) in self.table.fields and str(self.table[itm].type).startswith("list::")): request_vars[itm] = request_vars[itm][-1] if self.record: (formname_id, record_id) = (self.record.get(self.record_pk_name, None), request_vars.get(self.record_pk_name, None)) keepvalues = True else: (formname_id, record_id) = ('create', None) if formname: formname = formname % dict(tablename=self.table._tablename, record_id=formname_id) for fieldname in self.fields: field = self.table[fieldname] requires = field.requires or [] if not isinstance(requires, (list, tuple)): requires = [requires] # ## END fields = {} for key in self.vars: fields[key] = self.vars[key] ret = FORM.accepts( self, request_vars, formname, keepvalues, onvalidation, hideerror=hideerror, ) if not ret and self.record and self.errors: ### if there are errors in update mode # and some errors refers to an already uploaded file # delete error if # - user not trying to upload a new file # - there is existing file and user is not trying to delete it # this is because removing the file may not pass validation for key in self.errors.keys(): if self.table[key].type == 'upload' \ and request_vars.get(key,None) in (None,'') \ and self.record[key] \ and not key+UploadWidget.ID_DELETE_SUFFIX in request_vars: del self.errors[key] if not self.errors: ret = True requested_delete = \ request_vars.get(self.FIELDNAME_REQUEST_DELETE, False) self.custom.end = TAG[''](self.hidden_fields(), self.custom.end) auch = record_id and self.errors and requested_delete # auch is true when user tries to delete a record # that does not pass validation, yet it should be deleted if not ret and not auch: for fieldname in self.fields: field = self.table[fieldname] ### this is a workaround! widgets should always have default not None! if not field.widget and field.type.startswith('list:') and \ not OptionsWidget.has_options(field): field.widget = self.widgets.list.widget if hasattr(field, 'widget' ) and field.widget and fieldname in request_vars: if fieldname in self.vars: value = self.vars[fieldname] elif self.record: value = self.record[fieldname] else: value = self.table[fieldname].default row_id = '%s_%s%s' % (self.table, fieldname, FORMBUILDER.ID_ROW_SUFFIX) widget = field.widget(field, value) self.field_parent[row_id].components = [widget] if not field.type.startswith('list:'): self.field_parent[row_id]._traverse(False, hideerror) self.custom.widget[fieldname] = widget return ret self.record_id = record_id if requested_delete and self.custom.deletable: self.errors.clear() for component in self.elements('input, select, textarea'): component['_disabled'] = True return True for fieldname in self.fields: if not fieldname in self.table: continue if not self.ignore_rw and not self.table[fieldname].writable: ### this happens because FROM has no knowledge of writable ### and thinks that a missing boolean field is a None if self.table[fieldname].type == 'boolean' and self.vars[ fieldname] == None: del self.vars[fieldname] continue field = self.table[fieldname] if field.type == 'id': continue if field.type == 'boolean': if self.vars.get(fieldname, False): self.vars[fieldname] = fields[fieldname] = True else: self.vars[fieldname] = fields[fieldname] = False elif field.type == 'password' and self.record\ and request_vars.get(fieldname, None) == \ PasswordWidget.DEFAULT_PASSWORD_DISPLAY: continue # do not update if password was not changed elif field.type == 'upload': if self.vars.get("%s__delete" % fieldname, False): self.vars[fieldname] = "" del self.vars["%s__delete" % fieldname] continue if self.custom_file: self.vars[fieldname] = self.custom_file( field, request_vars) else: self.vars[fieldname] = field.store( request_vars.get(fieldname, ""), request_vars.get("%s.original" % fieldname, "")) continue elif fieldname in self.vars: fields[fieldname] = self.vars[fieldname] elif field.default == None and field.type != 'blob': self.errors[fieldname] = 'no data' return False value = fields.get(fieldname, None) if field.type == 'list:string': if not isinstance(value, (tuple, list)): fields[fieldname] = value and [value] or [] elif field.type.startswith('list:'): if not isinstance(value, list): fields[fieldname] = [ safe_int(x) for x in (value and [value] or []) ] elif field.type == 'integer': if value != None: fields[fieldname] = safe_int(value) elif field.type == 'double': if value != None: fields[fieldname] = safe_float(value) for fieldname in self.vars: if fieldname != 'id' and fieldname in self.table.fields\ and not fieldname in fields and not fieldname\ in request_vars: fields[fieldname] = self.vars[fieldname] return ret
def accepts( self, request_vars, session=None, formname='%(tablename)s_%(record_id)s', keepvalues=False, onvalidation=None, dbio=True, hideerror=False, detect_record_change=False, ): """ similar FORM.accepts but also does insert, update or delete in SQLDB. but if detect_record_change == True than: form.record_changed = False (record is properly validated/submitted) form.record_changed = True (record cannot be submitted because changed) elseif detect_record_change == False than: form.record_changed = None """ if request_vars.__class__.__name__ == 'Request': request_vars = request_vars.post_vars keyed = hasattr(self.table,'_primarykey') # implement logic to detect whether record exist but has been modified # server side self.record_changed = None if detect_record_change: if self.record: self.record_changed = False serialized = '|'.join(str(self.record[k]) for k in self.table.fields()) self.record_hash = md5_hash(serialized) # logic to deal with record_id for keyed tables if self.record: if keyed: formname_id = '.'.join(str(self.record[k]) for k in self.table._primarykey if hasattr(self.record,k)) record_id = dict((k,request_vars[k]) for k in self.table._primarykey) else: (formname_id, record_id) = (self.record.id, request_vars.get('id', None)) keepvalues = True else: if keyed: formname_id = 'create' record_id = dict([(k,None) for k in self.table._primarykey]) else: (formname_id, record_id) = ('create', None) if not keyed and isinstance(record_id, (list, tuple)): record_id = record_id[0] if formname: formname = formname % dict(tablename = self.table._tablename, record_id = formname_id) # ## THIS IS FOR UNIQUE RECORDS, read IS_NOT_IN_DB for fieldname in self.fields: field = self.table[fieldname] requires = field.requires or [] if not isinstance(requires, (list, tuple)): requires = [requires] [item.set_self_id(self.record_id) for item in requires if hasattr(item, 'set_self_id') and self.record_id] # ## END fields = {} for key in self.vars: fields[key] = self.vars[key] ret = FORM.accepts( self, request_vars, session, formname, keepvalues, onvalidation, hideerror=hideerror, ) if not ret and self.record and self.errors: ### if there are errors in update mode # and some errors refers to an already uploaded file # delete error if # - user not trying to upload a new file # - there is existing file and user is not trying to delete it # this is because removing the file may not pass validation for key in self.errors.keys(): if self.table[key].type == 'upload' \ and request_vars.get(key,None) in (None,'') \ and self.record[key] \ and not key+UploadWidget.ID_DELETE_SUFFIX in request_vars: del self.errors[key] if not self.errors: ret = True requested_delete = \ request_vars.get(self.FIELDNAME_REQUEST_DELETE, False) self.custom.end = TAG[''](self.hidden_fields(), self.custom.end) auch = record_id and self.errors and requested_delete # auch is true when user tries to delete a record # that does not pass validation, yet it should be deleted if not ret and not auch: for fieldname in self.fields: field = self.table[fieldname] ### this is a workaround! widgets should always have default not None! if not field.widget and field.type.startswith('list:') and \ not OptionsWidget.has_options(field): field.widget = self.widgets.list.widget if hasattr(field, 'widget') and field.widget and fieldname in request_vars: if fieldname in self.vars: value = self.vars[fieldname] elif self.record: value = self.record[fieldname] else: value = self.table[fieldname].default row_id = '%s_%s%s' % (self.table,fieldname,SQLFORM.ID_ROW_SUFFIX) widget = field.widget(field, value) self.field_parent[row_id].components = [ widget ] if not field.type.startswith('list:'): self.field_parent[row_id]._traverse(False,hideerror) self.custom.widget[ fieldname ] = widget return ret if record_id and str(record_id) != str(self.record_id): raise SyntaxError, 'user is tampering with form\'s record_id: ' \ '%s != %s' % (record_id, self.record_id) if requested_delete and self.custom.deletable: if dbio: if keyed: qry = reduce(lambda x,y: x & y, [self.table[k]==record_id[k] for k in self.table._primarykey]) if self.table._db(qry).delete(): self.vars.update(record_id) else: self.table._db(self.table.id == self.record.id).delete() self.vars.id = self.record.id self.errors.clear() for component in self.elements('input, select, textarea'): component['_disabled'] = True return True for fieldname in self.fields: if not fieldname in self.table: continue if not self.ignore_rw and not self.table[fieldname].writable: continue field = self.table[fieldname] if field.type == 'id': continue if field.type == 'boolean': if self.vars.get(fieldname, False): self.vars[fieldname] = fields[fieldname] = True else: self.vars[fieldname] = fields[fieldname] = False elif field.type == 'password' and self.record\ and request_vars.get(fieldname, None) == \ PasswordWidget.DEFAULT_PASSWORD_DISPLAY: continue # do not update if password was not changed elif field.type == 'upload': f = self.vars[fieldname] fd = fieldname + '__delete' if f == '' or f == None: if self.vars.get(fd, False) or not self.record: fields[fieldname] = '' else: fields[fieldname] = self.record[fieldname] self.vars[fieldname] = fields[fieldname] continue elif hasattr(f,'file'): (source_file, original_filename) = (f.file, f.filename) elif isinstance(f, (str, unicode)): ### do not know why this happens, it should not (source_file, original_filename) = \ (cStringIO.StringIO(f), 'file.txt') newfilename = field.store(source_file, original_filename) # this line is for backward compatibility only self.vars['%s_newfilename' % fieldname] = newfilename fields[fieldname] = newfilename if isinstance(field.uploadfield,str): fields[field.uploadfield] = source_file.read() # proposed by Hamdy (accept?) do we need fields at this point? self.vars[fieldname] = fields[fieldname] continue elif fieldname in self.vars: fields[fieldname] = self.vars[fieldname] elif field.default == None and field.type!='blob': self.errors[fieldname] = 'no data' return False value = fields.get(fieldname,None) if field.type == 'list:string': if not isinstance(value,(tuple,list)): fields[fieldname] = value and [value] or [] elif field.type.startswith('list:'): if not isinstance(value,list): fields[fieldname] = [safe_int(x) for x in (value and [value] or [])] elif field.type == 'integer': if value != None: fields[fieldname] = safe_int(value) elif field.type.startswith('reference'): if value != None and isinstance(self.table,Table) and not keyed: fields[fieldname] = safe_int(value) elif field.type == 'double': if value != None: fields[fieldname] = safe_float(value) for fieldname in self.vars: if fieldname != 'id' and fieldname in self.table.fields\ and not fieldname in fields and not fieldname\ in request_vars: fields[fieldname] = self.vars[fieldname] if dbio: if keyed: if reduce(lambda x,y: x and y, record_id.values()): # if record_id if fields: qry = reduce(lambda x,y: x & y, [self.table[k]==self.record[k] for k in self.table._primarykey]) self.table._db(qry).update(**fields) else: pk = self.table.insert(**fields) if pk: self.vars.update(pk) else: ret = False else: if record_id: self.vars.id = self.record.id if fields: self.table._db(self.table.id == self.record.id).update(**fields) else: self.vars.id = self.table.insert(**fields) return ret