Beispiel #1
0
def index():
    """
    example action using the internationalization operator T and flash
    rendered by views/default/index.html or views/generic.html

    if you need a simple wiki simple replace the two lines below with:
    return auth.wiki()
    """
    row=db(content.html).select().last()
    form=FORM('html',TEXTAREA(row.html,_id="textarea_id",_name="content" ,_style="width:700px;height:300px;"),
              INPUT(_type='submit'),
              next=URL('default','index'))
    if form.process().accepted:
        session.flash = form.vars
        content.insert(html= form.vars['content'])
    elif form.errors:
        response.flash = 'form has errors'
    else:
        response.flash = 'please fill the form'
    return dict(form=form,req=form.vars)
    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 __init__(self,
                 table,
                 record=None,
                 deletable=False,
                 linkto=None,
                 upload=None,
                 fields=None,
                 labels=None,
                 col3={},
                 submit_button='Submit',
                 delete_label='Check to delete:',
                 showid=True,
                 readonly=False,
                 comments=True,
                 keepopts=[],
                 ignore_rw=False,
                 record_id=None,
                 formstyle='table3cols',
                 **attributes):
        """
        SQLFORM(db.table,
               record=None,
               fields=['name'],
               labels={'name': 'Your name'},
               linkto=URL(r=request, f='table/db/')
        """

        self.ignore_rw = ignore_rw
        self.formstyle = formstyle
        nbsp = XML(' ')  # Firefox2 does not display fields with blanks
        FORM.__init__(self, *[], **attributes)
        ofields = fields
        keyed = hasattr(table, '_primarykey')

        # if no fields are provided, build it from the provided table
        # will only use writable or readable fields, unless forced to ignore
        if fields == None:
            fields = [
                f.name for f in table
                if (ignore_rw or f.writable or f.readable) and not f.compute
            ]
        self.fields = fields

        # make sure we have an id
        if self.fields[0] != table.fields[0] and \
                isinstance(table,Table) and not keyed:
            self.fields.insert(0, table.fields[0])

        self.table = table

        # try to retrieve the indicated record using its id
        # otherwise ignore it
        if record and isinstance(record, (int, long, str, unicode)):
            if not str(record).isdigit():
                raise HTTP(404, "Object not found")
            record = table._db(table.id == record).select().first()
            if not record:
                raise HTTP(404, "Object not found")
        self.record = record

        self.record_id = record_id
        if keyed:
            if record:
                self.record_id = dict([(k, record[k])
                                       for k in table._primarykey])
            else:
                self.record_id = dict([(k, None) for k in table._primarykey])
        self.field_parent = {}
        xfields = []
        self.fields = fields
        self.custom = Storage()
        self.custom.dspval = Storage()
        self.custom.inpval = Storage()
        self.custom.label = Storage()
        self.custom.comment = Storage()
        self.custom.widget = Storage()
        self.custom.linkto = Storage()

        for fieldname in self.fields:
            if fieldname.find('.') >= 0:
                continue

            field = self.table[fieldname]
            comment = None

            if comments:
                comment = col3.get(fieldname, field.comment)
            if comment == None:
                comment = ''
            self.custom.comment[fieldname] = comment

            if labels != None and fieldname in labels:
                label = labels[fieldname]
                colon = ''
            else:
                label = field.label
                colon = ': '
            self.custom.label[fieldname] = label

            field_id = '%s_%s' % (table._tablename, fieldname)

            label = LABEL(label,
                          colon,
                          _for=field_id,
                          _id=field_id + SQLFORM.ID_LABEL_SUFFIX)

            row_id = field_id + SQLFORM.ID_ROW_SUFFIX
            if field.type == 'id':
                self.custom.dspval.id = nbsp
                self.custom.inpval.id = ''
                widget = ''
                if record:
                    if showid and 'id' in fields and field.readable:
                        v = record['id']
                        widget = SPAN(v, _id=field_id)
                        self.custom.dspval.id = str(v)
                        xfields.append((row_id, label, widget, comment))
                    self.record_id = str(record['id'])
                self.custom.widget.id = widget
                continue

            if readonly and not ignore_rw and not field.readable:
                continue

            if record:
                default = record[fieldname]
            else:
                default = field.default

            cond = readonly or \
                (not ignore_rw and not field.writable and field.readable)

            if default and not cond:
                default = field.formatter(default)
            dspval = default
            inpval = default

            if cond:

                # ## if field.represent is available else
                # ## ignore blob and preview uploaded images
                # ## format everything else

                if field.represent:
                    inp = field.represent(default)
                elif field.type in ['blob']:
                    continue
                elif field.type == 'upload':
                    inp = UploadWidget.represent(field, default, upload)
                else:
                    inp = field.formatter(default)
            elif hasattr(field, 'widget') and field.widget:
                inp = field.widget(field, default)
            elif field.type == 'upload':
                inp = self.widgets.upload.widget(field, default, upload)
            elif field.type == 'boolean':
                inp = self.widgets.boolean.widget(field, default)
                if default:
                    inpval = 'checked'
                else:
                    inpval = ''
            elif OptionsWidget.has_options(field):
                if not field.requires.multiple:
                    inp = self.widgets.options.widget(field, default)
                else:
                    inp = self.widgets.multiple.widget(field, default)
                if fieldname in keepopts:
                    inpval = TAG[''](*inp.components)
            elif str(field.type).startswith('list'):
                inp = self.widgets.list.widget(field, default)
            elif field.type == 'text':
                inp = self.widgets.text.widget(field, default)
            elif field.type == 'password':
                inp = self.widgets.password.widget(field, default)
                if self.record:
                    dspval = PasswordWidget.DEFAULT_PASSWORD_DISPLAY
                else:
                    dspval = ''
            elif field.type == 'blob':
                continue
            else:
                inp = self.widgets.string.widget(field, default)

            xfields.append((row_id, label, inp, comment))
            self.custom.dspval[fieldname] = dspval or nbsp
            self.custom.inpval[fieldname] = inpval or ''
            self.custom.widget[fieldname] = inp

        # if a record is provided and found, as is linkto
        # build a link
        if record and linkto:
            for (rtable, rfield) in table._referenced_by:
                if keyed:
                    rfld = table._db[rtable][rfield]
                    query = urllib.quote(
                        str(rfld == record[rfld.type[10:].split('.')[1]]))
                else:
                    #                 <block>
                    query = urllib.quote(
                        str(table._db[rtable][rfield] == record.id))
                lname = olname = '%s.%s' % (rtable, rfield)
                if ofields and not olname in ofields:
                    continue
                if labels and lname in labels:
                    lname = labels[lname]
                widget = A(lname,
                           _class='reference',
                           _href='%s/%s?query=%s' % (linkto, rtable, query))
                xfields.append(
                    (olname.replace('.', '__') + SQLFORM.ID_ROW_SUFFIX, '',
                     widget, col3.get(olname, '')))
                self.custom.linkto[olname.replace('.', '__')] = widget


#                 </block>

# when deletable, add delete? checkbox
        self.custom.deletable = ''
        if record and deletable:
            widget = INPUT(
                _type='checkbox',
                _class='delete',
                _id=self.FIELDKEY_DELETE_RECORD,
                _name=self.FIELDNAME_REQUEST_DELETE,
            )
            xfields.append(
                (self.FIELDKEY_DELETE_RECORD + SQLFORM.ID_ROW_SUFFIX,
                 LABEL(delete_label,
                       _for=self.FIELDKEY_DELETE_RECORD,
                       _id=self.FIELDKEY_DELETE_RECORD +
                       SQLFORM.ID_LABEL_SUFFIX), widget,
                 col3.get(self.FIELDKEY_DELETE_RECORD, '')))
            self.custom.deletable = widget
        # when writable, add submit button
        self.custom.submit = ''
        if not readonly:
            widget = INPUT(_type='submit', _value=submit_button)
            xfields.append(
                ('submit_record' + SQLFORM.ID_ROW_SUFFIX, '', widget,
                 col3.get('submit_button', '')))
            self.custom.submit = widget
        # if a record is provided and found
        # make sure it's id is stored in the form
        if record:
            if not self['hidden']:
                self['hidden'] = {}
            if not keyed:
                self['hidden']['id'] = record['id']

        (begin, end) = self._xml()
        self.custom.begin = XML("<%s %s>" % (self.tag, begin))
        self.custom.end = XML("%s</%s>" % (end, self.tag))
        if formstyle == 'table3cols':
            table = TABLE()
            for id, a, b, c in xfields:
                td_b = self.field_parent[id] = TD(b, _class='w2p_fw')
                table.append(
                    TR(TD(a, _class='w2p_fl'),
                       td_b,
                       TD(c, _class='w2p_fc'),
                       _id=id))
        elif formstyle == 'table2cols':
            table = TABLE()
            for id, a, b, c in xfields:
                td_b = self.field_parent[id] = TD(b,
                                                  _class='w2p_fw',
                                                  _colspan="2")
                table.append(
                    TR(TD(a, _class='w2p_fl'),
                       TD(c, _class='w2p_fc'),
                       _id=id + '1',
                       _class='even'))
                table.append(TR(td_b, _id=id + '2', _class='odd'))
        elif formstyle == 'divs':
            table = TAG['']()
            for id, a, b, c in xfields:
                div_b = self.field_parent[id] = DIV(b, _class='w2p_fw')
                table.append(
                    DIV(DIV(a, _class='w2p_fl'),
                        div_b,
                        DIV(c, _class='w2p_fc'),
                        _id=id))
        elif formstyle == 'ul':
            table = UL()
            for id, a, b, c in xfields:
                div_b = self.field_parent[id] = DIV(b, _class='w2p_fw')
                table.append(
                    LI(DIV(a, _class='w2p_fl'),
                       div_b,
                       DIV(c, _class='w2p_fc'),
                       _id=id))
        elif type(formstyle) == type(lambda: None):
            table = TABLE()
            for id, a, b, c in xfields:
                td_b = self.field_parent[id] = TD(b, _class='w2p_fw')
                newrows = formstyle(id, a, td_b, c)
                if type(newrows).__name__ != "tuple":
                    newrows = [newrows]
                for newrow in newrows:
                    table.append(newrow)
        else:
            raise RuntimeError, 'formsyle not supported'
        self.components = [table]
Beispiel #4
0
    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
Beispiel #5
0
    def __init__(self,
                 table,
                 record=None,
                 deletable=False,
                 download="",
                 upload=None,
                 fields=None,
                 labels=None,
                 col3={},
                 submit_button='Submit',
                 delete_label='Check to delete:',
                 showid=True,
                 readonly=False,
                 comments=True,
                 keepopts=[],
                 ignore_rw=False,
                 formstyle='divs',
                 record_pk_name='_id',
                 tabs=[],
                 **attributes):
        """
        FORMBUILDER(db.table,
               record=None,
               fields=['name'],
               labels={'name': 'Your name'},
        """
        self.table = table
        if record:
            for itm in record:
                if isinstance(record[itm], (list, tuple)):
                    if not (itm in self.table.fields
                            and self.table[itm].type.startswith("list::")):
                        record[itm] = record[itm][-1]
        self.custom_file = upload
        self.ignore_rw = ignore_rw
        self.formstyle = formstyle
        self.record_pk_name = record_pk_name
        nbsp = XML('&nbsp;')  # Firefox2 does not display fields with blanks
        attributes.update({"_id": "hyform_%s" % self.table._tablename})
        FORM.__init__(self, *[], **attributes)
        ofields = fields

        # if no fields are provided, build it from the provided table
        # will only use writable or readable fields, unless forced to ignore
        if fields == None:
            fields = [
                f.name for f in table
                if (ignore_rw or f.writable or f.readable)
            ]

        self.record = record

        self.field_parent = {}
        xfields = {}
        xfields_keys = []
        self.fields = fields
        self.custom = Storage()
        self.custom.dspval = Storage()
        self.custom.inpval = Storage()
        self.custom.label = Storage()
        self.custom.comment = Storage()
        self.custom.widget = Storage()

        for fieldname in self.fields:
            if fieldname.find('.') >= 0:
                continue

            field = self.table[fieldname]
            comment = None

            if comments:
                comment = col3.get(fieldname, field.comment)
            if comment == None:
                comment = ''
            self.custom.comment[fieldname] = comment

            if labels != None and fieldname in labels:
                label = labels[fieldname]
                colon = ''
            else:
                label = field.label
                colon = ': '
            self.custom.label[fieldname] = label

            field_id = '%s_%s' % (table._tablename, fieldname)

            label = LABEL(label,
                          colon,
                          _for=field_id,
                          _id=field_id + FORMBUILDER.ID_LABEL_SUFFIX)

            row_id = field_id + FORMBUILDER.ID_ROW_SUFFIX

            if readonly and not ignore_rw and not field.readable:
                continue

            if record:
                default = record.get(fieldname, field.default)
            else:
                default = field.default

            cond = readonly or \
                (not ignore_rw and not field.writable and field.readable)

            if default and not cond:
                default = field.formatter(default)
            dspval = default
            inpval = default

            if cond:

                # ## if field.represent is available else
                # ## ignore blob and preview uploaded images
                # ## format everything else

                if field.represent:
                    inp = field.represent(default)
                elif field.type in ['blob']:
                    continue
                elif field.type == 'upload':
                    inp = UploadWidget.represent(field, default, download)
                elif field.type == 'boolean':
                    inp = self.widgets.boolean.widget(field,
                                                      default,
                                                      _disabled=True)
                else:
                    inp = field.formatter(default)
            elif field.type == 'upload':
                if hasattr(field, 'widget') and field.widget:
                    inp = field.widget(field, default, download)
                else:
                    inp = self.widgets.upload.widget(field, default, download)
            elif hasattr(field, 'widget') and field.widget:
                inp = field.widget(field, default)
            elif field.type == 'boolean':
                inp = self.widgets.boolean.widget(field, default)
                if default:
                    inpval = 'checked'
                else:
                    inpval = ''
            elif OptionsWidget.has_options(field):
                if not field.requires.multiple:
                    inp = self.widgets.options.widget(field, default)
                else:
                    inp = self.widgets.multiple.widget(field, default)
                if fieldname in keepopts:
                    inpval = TAG[''](*inp.components)
            elif field.type.startswith('list:'):
                inp = self.widgets.list.widget(field, default)
            elif field.type == 'text':
                inp = self.widgets.text.widget(field, default)
            elif field.type == 'hidden':
                inp = self.widgets.hidden.widget(field, default)
            elif field.type == 'password':
                inp = self.widgets.password.widget(field, default)
                if self.record:
                    dspval = PasswordWidget.DEFAULT_PASSWORD_DISPLAY
                else:
                    dspval = ''
            elif field.type == 'blob':
                continue
            else:
                inp = self.widgets.string.widget(field, default)
            xfields_keys.append(fieldname)
            xfields[fieldname] = (row_id, label, inp, comment)
            self.custom.dspval[fieldname] = dspval or nbsp
            self.custom.inpval[fieldname] = inpval or ''
            self.custom.widget[fieldname] = inp

        # when writable, add submit button
        self.custom.submit = ''
        if not readonly:
            widget = INPUT(_type='submit',
                           _class="submit",
                           _value=submit_button,
                           _id="submit_%s" % self.table._tablename)
            self.custom.submit = widget
        # if a record is provided and found
        # make sure it's id is stored in the form
        if record:
            if not self['hidden']:
                self['hidden'] = {}

        (begin, end) = self._xml()
        self.custom.begin = XML("<%s %s>" % (self.tag, begin))
        self.custom.end = XML("%s</%s>" % (end, self.tag))

        table = TAG['']()
        if formstyle == 'divs':
            # tabs = [
            #          {"tabname":"personal","caption":"个人信息","fields":["login","age"]},
            #          {"tabname":"comp","caption":"公司信息","fields":["login","age"]},
            #          {"tabname":"gf","caption":"朋友信息","fields":["login","age"]},
            #        ]
            if tabs:
                tab_headers = UL()
                tab_bodys = []

                for i, tab in enumerate(tabs):
                    tbody = DIV(_id="body_%s" % (tab.get("tabname", "")))
                    if i == 0:
                        li = LI(tab.get("caption", ""),
                                _class="active",
                                _id="tab_%s" % (tab.get("tabname", "")))
                        tbody['_class'] = "active"
                    else:
                        li = LI(tab.get("caption", ""),
                                _style="display:none;",
                                _id="tab_%s" % (tab.get("tabname", "")))
                        tbody['_style'] = "display:none;"
                    tab_headers.append(li)
                    for f in tab.get("fields", []):
                        if f in xfields_keys:
                            id, a, b, c = xfields[f]
                            div_b = self.field_parent[id] = DIV(
                                b, _class='w2p_fw')
                            tbody.append(
                                DIV(DIV(a, _class='w2p_fl'),
                                    div_b,
                                    DIV(c, _class='w2p_fc'),
                                    _id=id,
                                    _class="fb_row"))
                    tab_bodys.append(tbody)
                tab_headers = DIV(tab_headers,
                                  _id="tab_headers_%s" % self.table._tablename)
                tab_bodys = DIV(tab_bodys,
                                _id="tab_bodys_%s" % self.table._tablename)
                table.append(DIV(tab_headers, tab_bodys))
            else:
                for d in xfields_keys:
                    id, a, b, c = xfields[d]
                    div_b = self.field_parent[id] = DIV(b, _class='w2p_fw')
                    table.append(
                        DIV(DIV(a, _class='w2p_fl'),
                            div_b,
                            DIV(c, _class='w2p_fc'),
                            _id=id,
                            _class="fb_row"))

        self.components = [table, self.custom.submit]
Beispiel #6
0
    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
Beispiel #7
0
    def __init__(
        self,
        table,
        record = None,
        deletable = False,
        download = "",
        upload = None,
        fields = None,
        labels = None,
        col3 = {},
        submit_button = 'Submit',
        delete_label = 'Check to delete:',
        showid = True,
        readonly = False,
        comments = True,
        keepopts = [],
        ignore_rw = False,
        formstyle = 'divs',
        record_pk_name = '_id',
        tabs = [],
        **attributes
        ):
        """
        FORMBUILDER(db.table,
               record=None,
               fields=['name'],
               labels={'name': 'Your name'},
        """
        self.table = table
        if record:
            for itm in record:
                if isinstance(record[itm],(list,tuple)):
                    if not (itm in self.table.fields and self.table[itm].type.startswith("list::")):
                        record[itm] = record[itm][-1]
        self.custom_file = upload
        self.ignore_rw = ignore_rw
        self.formstyle = formstyle
        self.record_pk_name = record_pk_name
        nbsp = XML('&nbsp;') # Firefox2 does not display fields with blanks
        attributes.update({"_id":"hyform_%s"%self.table._tablename})
        FORM.__init__(self, *[], **attributes)
        ofields = fields

        # if no fields are provided, build it from the provided table
        # will only use writable or readable fields, unless forced to ignore
        if fields == None:
            fields = [f.name for f in table if (ignore_rw or f.writable or f.readable)]

        self.record = record

        self.field_parent = {}
        xfields = {}
        xfields_keys = []
        self.fields = fields
        self.custom = Storage()
        self.custom.dspval = Storage()
        self.custom.inpval = Storage()
        self.custom.label = Storage()
        self.custom.comment = Storage()
        self.custom.widget = Storage()

        for fieldname in self.fields:
            if fieldname.find('.') >= 0:
                continue

            field = self.table[fieldname]
            comment = None

            if comments:
                comment = col3.get(fieldname, field.comment)
            if comment == None:
                comment = ''
            self.custom.comment[fieldname] = comment

            if labels != None and fieldname in labels:
                label = labels[fieldname]
                colon = ''
            else:
                label = field.label
                colon = ': '
            self.custom.label[fieldname] = label

            field_id = '%s_%s' % (table._tablename, fieldname)

            label = LABEL(label, colon, _for=field_id,
                          _id=field_id+FORMBUILDER.ID_LABEL_SUFFIX)

            row_id = field_id + FORMBUILDER.ID_ROW_SUFFIX

            if readonly and not ignore_rw and not field.readable:
                continue

            if record:
                default = record.get(fieldname, field.default)
            else:
                default = field.default

            cond = readonly or \
                (not ignore_rw and not field.writable and field.readable)

            if default and not cond:
                default = field.formatter(default)
            dspval = default
            inpval = default

            if cond:

                # ## if field.represent is available else
                # ## ignore blob and preview uploaded images
                # ## format everything else

                if field.represent:
                    inp = field.represent(default)
                elif field.type in ['blob']:
                    continue
                elif field.type == 'upload':
                    inp = UploadWidget.represent(field, default, download)
                elif field.type == 'boolean':
                    inp = self.widgets.boolean.widget(field, default, _disabled=True)
                else:
                    inp = field.formatter(default)
            elif field.type == 'upload':
                if hasattr(field, 'widget') and field.widget:
                    inp = field.widget(field, default, download)
                else:
                    inp = self.widgets.upload.widget(field, default, download)
            elif hasattr(field, 'widget') and field.widget:
                inp = field.widget(field, default)
            elif field.type == 'boolean':
                inp = self.widgets.boolean.widget(field, default)
                if default:
                    inpval = 'checked'
                else:
                    inpval = ''
            elif OptionsWidget.has_options(field):
                if not field.requires.multiple:
                    inp = self.widgets.options.widget(field, default)
                else:
                    inp = self.widgets.multiple.widget(field, default)
                if fieldname in keepopts:
                    inpval = TAG[''](*inp.components)
            elif field.type.startswith('list:'):
                inp = self.widgets.list.widget(field,default)
            elif field.type == 'text':
                inp = self.widgets.text.widget(field, default)
            elif field.type == 'hidden':
                inp = self.widgets.hidden.widget(field, default)
            elif field.type == 'password':
                inp = self.widgets.password.widget(field, default)
                if self.record:
                    dspval = PasswordWidget.DEFAULT_PASSWORD_DISPLAY
                else:
                    dspval = ''
            elif field.type == 'blob':
                continue
            else:
                inp = self.widgets.string.widget(field, default)
            xfields_keys.append(fieldname)
            xfields[fieldname] = (row_id,label,inp,comment)
            self.custom.dspval[fieldname] = dspval or nbsp
            self.custom.inpval[fieldname] = inpval or ''
            self.custom.widget[fieldname] = inp


        # when writable, add submit button
        self.custom.submit = ''
        if not readonly:
            widget = INPUT(_type='submit',_class="submit",
                           _value=submit_button,
                           _id = "submit_%s"%self.table._tablename )
            self.custom.submit = widget
        # if a record is provided and found
        # make sure it's id is stored in the form
        if record:
            if not self['hidden']:
                self['hidden'] = {}

        (begin, end) = self._xml()
        self.custom.begin = XML("<%s %s>" % (self.tag, begin))
        self.custom.end = XML("%s</%s>" % (end, self.tag))

        table = TAG['']()
        if formstyle == 'divs':
            # tabs = [
            #          {"tabname":"personal","caption":"个人信息","fields":["login","age"]},
            #          {"tabname":"comp","caption":"公司信息","fields":["login","age"]},
            #          {"tabname":"gf","caption":"朋友信息","fields":["login","age"]},
            #        ]
            if tabs:
                tab_headers = UL()
                tab_bodys = []
                
                for i, tab in enumerate(tabs):
                    tbody = DIV(_id="body_%s"%(tab.get("tabname","")))
                    if i == 0:
                        li = LI(tab.get("caption",""),_class="active", _id="tab_%s"%(tab.get("tabname","")))
                        tbody['_class'] = "active"
                    else:
                        li = LI(tab.get("caption",""),_style="display:none;",_id="tab_%s"%(tab.get("tabname","")))
                        tbody['_style'] = "display:none;"
                    tab_headers.append(li)
                    for f in tab.get("fields",[]):
                        if f in xfields_keys:
                            id,a,b,c = xfields[f]
                            div_b = self.field_parent[id] = DIV(b,_class='w2p_fw')
                            tbody.append(DIV(DIV(a,_class='w2p_fl'),div_b,DIV(c,_class='w2p_fc'),_id=id, _class="fb_row"))
                    tab_bodys.append(tbody)                  
                tab_headers = DIV(tab_headers, _id="tab_headers_%s"%self.table._tablename)
                tab_bodys = DIV(tab_bodys, _id="tab_bodys_%s"%self.table._tablename)
                table.append(DIV(tab_headers, tab_bodys))
            else:
                for d in xfields_keys:
                    id,a,b,c = xfields[d]
                    div_b = self.field_parent[id] = DIV(b,_class='w2p_fw')
                    table.append(DIV(DIV(a,_class='w2p_fl'),
                                 div_b,
                                 DIV(c,_class='w2p_fc'),_id=id,_class="fb_row"))

        self.components = [table, self.custom.submit]
Beispiel #8
0
    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
Beispiel #9
0
    def __init__(
        self,
        table,
        record = None,
        deletable = False,
        linkto = None,
        upload = None,
        fields = None,
        labels = None,
        col3 = {},
        submit_button = 'Submit',
        delete_label = 'Check to delete:',
        showid = True,
        readonly = False,
        comments = True,
        keepopts = [],
        ignore_rw = False,
        record_id = None,
        formstyle = 'table3cols',
        **attributes
        ):
        """
        SQLFORM(db.table,
               record=None,
               fields=['name'],
               labels={'name': 'Your name'},
               linkto=URL(r=request, f='table/db/')
        """

        self.ignore_rw = ignore_rw
        self.formstyle = formstyle
        nbsp = XML('&nbsp;') # Firefox2 does not display fields with blanks
        FORM.__init__(self, *[], **attributes)
        ofields = fields
        keyed = hasattr(table,'_primarykey')

        # if no fields are provided, build it from the provided table
        # will only use writable or readable fields, unless forced to ignore
        if fields == None:
            fields = [f.name for f in table if (ignore_rw or f.writable or f.readable) and not f.compute]
        self.fields = fields

        # make sure we have an id
        if self.fields[0] != table.fields[0] and \
                isinstance(table,Table) and not keyed:
            self.fields.insert(0, table.fields[0])

        self.table = table

        # try to retrieve the indicated record using its id
        # otherwise ignore it
        if record and isinstance(record, (int, long, str, unicode)):
            if not str(record).isdigit():
                raise HTTP(404, "Object not found")
            record = table._db(table.id == record).select().first()
            if not record:
                raise HTTP(404, "Object not found")
        self.record = record

        self.record_id = record_id
        if keyed:
            if record:
                self.record_id = dict([(k,record[k]) for k in table._primarykey])
            else:
                self.record_id = dict([(k,None) for k in table._primarykey])
        self.field_parent = {}
        xfields = []
        self.fields = fields
        self.custom = Storage()
        self.custom.dspval = Storage()
        self.custom.inpval = Storage()
        self.custom.label = Storage()
        self.custom.comment = Storage()
        self.custom.widget = Storage()
        self.custom.linkto = Storage()

        for fieldname in self.fields:
            if fieldname.find('.') >= 0:
                continue

            field = self.table[fieldname]
            comment = None

            if comments:
                comment = col3.get(fieldname, field.comment)
            if comment == None:
                comment = ''
            self.custom.comment[fieldname] = comment

            if labels != None and fieldname in labels:
                label = labels[fieldname]
                colon = ''
            else:
                label = field.label
                colon = ': '
            self.custom.label[fieldname] = label

            field_id = '%s_%s' % (table._tablename, fieldname)

            label = LABEL(label, colon, _for=field_id,
                          _id=field_id+SQLFORM.ID_LABEL_SUFFIX)

            row_id = field_id+SQLFORM.ID_ROW_SUFFIX
            if field.type == 'id':
                self.custom.dspval.id = nbsp
                self.custom.inpval.id = ''
                widget = ''
                if record:
                    if showid and 'id' in fields and field.readable:
                        v = record['id']
                        widget = SPAN(v, _id=field_id)
                        self.custom.dspval.id = str(v)
                        xfields.append((row_id,label, widget,comment))
                    self.record_id = str(record['id'])
                self.custom.widget.id = widget
                continue

            if readonly and not ignore_rw and not field.readable:
                continue

            if record:
                default = record[fieldname]
            else:
                default = field.default

            cond = readonly or \
                (not ignore_rw and not field.writable and field.readable)

            if default and not cond:
                default = field.formatter(default)
            dspval = default
            inpval = default

            if cond:

                # ## if field.represent is available else
                # ## ignore blob and preview uploaded images
                # ## format everything else

                if field.represent:
                    inp = field.represent(default)                    
                elif field.type in ['blob']:
                    continue
                elif field.type == 'upload':
                    inp = UploadWidget.represent(field, default, upload)
                else:
                    inp = field.formatter(default)
            elif hasattr(field, 'widget') and field.widget:
                inp = field.widget(field, default)
            elif field.type == 'upload':
                inp = self.widgets.upload.widget(field, default, upload)
            elif field.type == 'boolean':
                inp = self.widgets.boolean.widget(field, default)
                if default:
                    inpval = 'checked'
                else:
                    inpval = ''
            elif OptionsWidget.has_options(field):
                if not field.requires.multiple:
                    inp = self.widgets.options.widget(field, default)
                else:
                    inp = self.widgets.multiple.widget(field, default)
                if fieldname in keepopts:
                    inpval = TAG[''](*inp.components)
            elif field.type.startswith('list:'):
                inp = self.widgets.list.widget(field,default)
            elif field.type == 'text':
                inp = self.widgets.text.widget(field, default)
            elif field.type == 'password':
                inp = self.widgets.password.widget(field, default)
                if self.record:
                    dspval = PasswordWidget.DEFAULT_PASSWORD_DISPLAY
                else:
                    dspval = ''
            elif field.type == 'blob':
                continue
            else:
                inp = self.widgets.string.widget(field, default)

            xfields.append((row_id,label,inp,comment))
            self.custom.dspval[fieldname] = dspval or nbsp
            self.custom.inpval[fieldname] = inpval or ''
            self.custom.widget[fieldname] = inp

        # if a record is provided and found, as is linkto
        # build a link
        if record and linkto:
            for (rtable, rfield) in table._referenced_by:
                if keyed:
                    rfld = table._db[rtable][rfield]
                    query = urllib.quote(str(rfld == record[rfld.type[10:].split('.')[1]]))
                else:
#                 <block>
                    query = urllib.quote(str(table._db[rtable][rfield]
                             == record.id))
                lname = olname = '%s.%s' % (rtable, rfield)
                if ofields and not olname in ofields:
                    continue
                if labels and lname in labels:
                    lname = labels[lname]
                widget = A(lname,
                           _class='reference',
                           _href='%s/%s?query=%s' % (linkto, rtable, query))
                xfields.append((olname.replace('.', '__')+SQLFORM.ID_ROW_SUFFIX,
                                '',widget,col3.get(olname,'')))
                self.custom.linkto[olname.replace('.', '__')] = widget
#                 </block>

        # when deletable, add delete? checkbox
        self.custom.deletable = ''
        if record and deletable:
            widget = INPUT(_type='checkbox',
                            _class='delete',
                            _id=self.FIELDKEY_DELETE_RECORD,
                            _name=self.FIELDNAME_REQUEST_DELETE,
                            )
            xfields.append((self.FIELDKEY_DELETE_RECORD+SQLFORM.ID_ROW_SUFFIX,
                            LABEL(
                                delete_label,
                                _for=self.FIELDKEY_DELETE_RECORD,
                                _id=self.FIELDKEY_DELETE_RECORD+SQLFORM.ID_LABEL_SUFFIX),
                            widget,
                            col3.get(self.FIELDKEY_DELETE_RECORD, '')))
            self.custom.deletable = widget
        # when writable, add submit button
        self.custom.submit = ''
        if not readonly:
            widget = INPUT(_type='submit',
                           _value=submit_button)
            xfields.append(('submit_record'+SQLFORM.ID_ROW_SUFFIX,
                            '', widget,col3.get('submit_button', '')))
            self.custom.submit = widget
        # if a record is provided and found
        # make sure it's id is stored in the form
        if record:
            if not self['hidden']:
                self['hidden'] = {}
            if not keyed:
                self['hidden']['id'] = record['id']

        (begin, end) = self._xml()
        self.custom.begin = XML("<%s %s>" % (self.tag, begin))
        self.custom.end = XML("%s</%s>" % (end, self.tag))
        if formstyle == 'table3cols':
            table = TABLE()
            for id,a,b,c in xfields:
                td_b = self.field_parent[id] = TD(b,_class='w2p_fw')
                table.append(TR(TD(a,_class='w2p_fl'),
                                td_b,
                                TD(c,_class='w2p_fc'),_id=id))
        elif formstyle == 'table2cols':
            table = TABLE()
            for id,a,b,c in xfields:
                td_b = self.field_parent[id] = TD(b,_class='w2p_fw',_colspan="2")
                table.append(TR(TD(a,_class='w2p_fl'),
                                TD(c,_class='w2p_fc'),_id=id+'1',_class='even'))
                table.append(TR(td_b,_id=id+'2',_class='odd'))
        elif formstyle == 'divs':
            table = TAG['']()
            for id,a,b,c in xfields:
                div_b = self.field_parent[id] = DIV(b,_class='w2p_fw')
                table.append(DIV(DIV(a,_class='w2p_fl'),
                                 div_b,
                                 DIV(c,_class='w2p_fc'),_id=id))
        elif formstyle == 'ul':
            table = UL()
            for id,a,b,c in xfields:
                div_b = self.field_parent[id] = DIV(b,_class='w2p_fw')
                table.append(LI(DIV(a,_class='w2p_fl'),
                                 div_b,
                                 DIV(c,_class='w2p_fc'),_id=id))
        elif type(formstyle) == type(lambda:None):
            table = TABLE()
            for id,a,b,c in xfields:
                td_b = self.field_parent[id] = TD(b,_class='w2p_fw')
                newrows = formstyle(id,a,td_b,c)
                if type(newrows).__name__ != "tuple":
                    newrows = [newrows]
                for newrow in newrows:
                    table.append(newrow)
        else:
            raise RuntimeError, 'formsyle not supported'
        self.components = [table]
Beispiel #10
0
    def __init__(
        self,
        table,
        record = None,
        deletable = False,
        linkto = None,
        upload = None,
        fields = None,
        labels = None,
        col3 = {},
        submit_button = 'Submit',
        delete_label = 'Check to delete',
        showid = True,
        readonly = False,
        comments = True,
        keepopts = [],
        ignore_rw = False,
        record_id = None,
        formstyle = 'table3cols',
        buttons = ['submit'],
        separator = ': ',
        **attributes
        ):
        """
        SQLFORM(db.table,
               record=None,
               fields=['name'],
               labels={'name': 'Your name'},
               linkto=URL(f='table/db/')
        """

        self.ignore_rw = ignore_rw
        self.formstyle = formstyle
        nbsp = XML('&nbsp;') # Firefox2 does not display fields with blanks
        FORM.__init__(self, *[], **attributes)
        ofields = fields
        keyed = hasattr(table,'_primarykey')

        # Widgets override
        self.widgets['string'] = StringWidget
        self.widgets['text'] = TextWidget

        # if no fields are provided, build it from the provided table
        # will only use writable or readable fields, unless forced to ignore
        if fields is None:
            fields = [f.name for f in table if (ignore_rw or f.writable or f.readable) and not f.compute]
        self.fields = fields

        # make sure we have an id
        if self.fields[0] != table.fields[0] and \
                isinstance(table,Table) and not keyed:
            self.fields.insert(0, table.fields[0])

        self.table = table

        # try to retrieve the indicated record using its id
        # otherwise ignore it
        if record and isinstance(record, (int, long, str, unicode)):
            if not str(record).isdigit():
                raise HTTP(404, "Object not found")
            record = table._db(table._id == record).select().first()
            if not record:
                raise HTTP(404, "Object not found")
        self.record = record

        self.record_id = record_id
        if keyed:
            self.record_id = dict([(k,record and str(record[k]) or None) \
                                       for k in table._primarykey])
        self.field_parent = {}
        xfields = []
        self.fields = fields
        self.custom = Storage()
        self.custom.dspval = Storage()
        self.custom.inpval = Storage()
        self.custom.label = Storage()
        self.custom.comment = Storage()
        self.custom.widget = Storage()
        self.custom.linkto = Storage()

        # default id field name
        self.id_field_name = table._id.name

        sep = separator or ''

        for fieldname in self.fields:
            if fieldname.find('.') >= 0:
                continue

            field = self.table[fieldname]
            comment = None

            if comments:
                comment = col3.get(fieldname, field.comment)
            if comment is None:
                comment = ''
            self.custom.comment[fieldname] = comment

            if not labels is None and fieldname in labels:
                label = labels[fieldname]
            else:
                label = field.label
            self.custom.label[fieldname] = label

            field_id = '%s_%s' % (table._tablename, fieldname)

            #label_is_required = SPAN(field.comment or '',_class="is_required") if field.notnull == True else ''

            label = LABEL(label, label and sep, _for=field_id,
                          _id=field_id+SQLFORM.ID_LABEL_SUFFIX)

            row_id = field_id+SQLFORM.ID_ROW_SUFFIX
            if field.type == 'id':
                self.custom.dspval.id = nbsp
                self.custom.inpval.id = ''
                widget = ''

                # store the id field name (for legacy databases)
                self.id_field_name = field.name

                if record:
                    if showid and field.name in record and field.readable:
                        v = record[field.name]
                        widget = SPAN(v, _id=field_id)
                        self.custom.dspval.id = str(v)
                        xfields.append((row_id,label, widget,comment))
                    self.record_id = str(record[field.name])
                self.custom.widget.id = widget
                continue

            self.readonly = readonly

            if readonly and not ignore_rw and not field.readable:
                continue

            if record:
                default = record[fieldname]
            else:
                default = field.default
                if isinstance(default,CALLABLETYPES):
                    default=default()

            cond = readonly or \
                (not ignore_rw and not field.writable and field.readable)

            if default and not cond:
                default = field.formatter(default)
            dspval = default
            inpval = default

            if cond:

                # ## if field.represent is available else
                # ## ignore blob and preview uploaded images
                # ## format everything else
                if field.represent:
                    inp = represent(field,default,record)
                elif field.type in ['blob']:
                    continue
                elif field.type == 'upload':
                    inp = UploadWidget.represent(field, default, upload)
                elif field.type == 'boolean':
                    inp = self.widgets.boolean.widget(field, default, _disabled=True)
                else:
                    inp = field.formatter(default)
            elif field.type == 'upload':
                if hasattr(field, 'widget') and field.widget:
                    inp = field.widget(field, default, upload)
                else:
                    inp = self.widgets.upload.widget(field, default, upload)
            elif hasattr(field, 'widget') and field.widget:
                inp = field.widget(field, default, record=record)
            elif field.type == 'boolean':
                inp = self.widgets.boolean.widget(field, default)
                if default:
                    inpval = 'checked'
                else:
                    inpval = ''
            elif OptionsWidget.has_options(field):
                if not field.requires.multiple:
                    inp = self.widgets.options.widget(field, default)
                else:
                    inp = self.widgets.multiple.widget(field, default)
                if fieldname in keepopts:
                    inpval = TAG[''](*inp.components)
            elif field.type.startswith('list:'):
                inp = self.widgets.list.widget(field,default)
            elif field.type == 'text':
                inp = self.widgets.text.widget(field, default)
            elif field.type == 'password':
                inp = self.widgets.password.widget(field, default)
                if self.record:
                    dspval = PasswordWidget.DEFAULT_PASSWORD_DISPLAY
                else:
                    dspval = ''
            elif field.type == 'blob':
                continue
            else:
                field_type = widget_class.match(str(field.type)).group()
                field_type = field_type in self.widgets and field_type or 'string'
                inp = self.widgets[field_type].widget(field, default, record=record)

            xfields.append((row_id,label,inp,comment))
            self.custom.dspval[fieldname] = dspval or nbsp
            self.custom.inpval[fieldname] = inpval or ''
            self.custom.widget[fieldname] = inp

        # if a record is provided and found, as is linkto
        # build a link
        if record and linkto:
            db = linkto.split('/')[-1]
            for (rtable, rfield) in table._referenced_by:
                if keyed:
                    rfld = table._db[rtable][rfield]
                    query = urllib.quote('%s.%s==%s' % (db,rfld,record[rfld.type[10:].split('.')[1]]))
                else:
                    query = urllib.quote('%s.%s==%s' % (db,table._db[rtable][rfield],record[self.id_field_name]))
                lname = olname = '%s.%s' % (rtable, rfield)
                if ofields and not olname in ofields:
                    continue
                if labels and lname in labels:
                    lname = labels[lname]
                widget = A(lname,
                           _class='reference',
                           _href='%s/%s?query=%s' % (linkto, rtable, query))
                xfields.append((olname.replace('.', '__')+SQLFORM.ID_ROW_SUFFIX,
                                '',widget,col3.get(olname,'')))
                self.custom.linkto[olname.replace('.', '__')] = widget
#                 </block>

        # when deletable, add delete? checkbox
        self.custom.deletable = ''
        if record and deletable:
            widget = INPUT(_type='checkbox',
                            _class='delete',
                            _id=self.FIELDKEY_DELETE_RECORD,
                            _name=self.FIELDNAME_REQUEST_DELETE,
                            )
            xfields.append((self.FIELDKEY_DELETE_RECORD+SQLFORM.ID_ROW_SUFFIX,
                            LABEL(
                                delete_label,separator,
                                _for=self.FIELDKEY_DELETE_RECORD,
                                _id=self.FIELDKEY_DELETE_RECORD+SQLFORM.ID_LABEL_SUFFIX),
                            widget,
                            col3.get(self.FIELDKEY_DELETE_RECORD, '')))
            self.custom.deletable = widget

        # when writable, add submit button
        self.custom.submit = ''
        if not readonly:
            if 'submit' in buttons:
                widget = self.custom.submit = INPUT(_type='submit',
                               _value=submit_button)
            elif buttons:
                widget = self.custom.submit = DIV(*buttons)
            if self.custom.submit:
                xfields.append(('submit_record' + SQLFORM.ID_ROW_SUFFIX,
                                '', widget, col3.get('submit_button', '')))

        # if a record is provided and found
        # make sure it's id is stored in the form
        if record:
            if not self['hidden']:
                self['hidden'] = {}
            if not keyed:
                self['hidden']['id'] = record[table._id.name]

        (begin, end) = self._xml()
        self.custom.begin = XML("<%s %s>" % (self.tag, begin))
        self.custom.end = XML("%s</%s>" % (end, self.tag))
        table = self.createform(xfields)
        self.components = [table]