'Render a widget for the Field/value
@param field: the Field
@param value: the value
@param download_url: the download URL for upload fields
@param attr: the HTML attributes for the widget
@note: upload fields currently not rendered because the
upload widget wouldn\'t render the current value,
hence pointless for merge
@note: custom widgets must allow override of both _id
and _name attributes'

@staticmethod
def widget(field, value, download_url=None, **attr):

    widgets = SQLFORM.widgets
    ftype = str(field.type)
    if ((value is not None) and (ftype not in ('id', 'upload', 'blob'))):
        value = field.formatter(value)
    if (ftype == 'id'):
        inp = None
    elif (ftype == 'upload'):
        inp = None
    elif field.widget:
        if isinstance(field.widget, S3LocationSelectorWidget):
            level = None
            if value:
                try:
                    level = s3db.gis_location[value].level
                except:
                    pass
            widget = S3LocationDropdownWidget(level, value)
            field.requires = IS_EMPTY_OR(IS_ONE_OF(current.db, 'gis_location.id'))
            inp = widget(field, value, **attr)
        else:
            inp = field.widget(field, value, **attr)
    elif (ftype == 'boolean'):
        inp = widgets.boolean.widget(field, value, **attr)
    elif widgets.options.has_options(field):
        if (not field.requires.multiple):
            inp = widgets.options.widget(field, value, **attr)
        else:
            inp = widgets.multiple.widget(field, value, **attr)
    elif (ftype[:5] == 'list:'):
        inp = widgets.list.widget(field, value, **attr)
    elif (ftype == 'text'):
        inp = widgets.text.widget(field, value, **attr)
    elif (ftype == 'password'):
        inp = widgets.password.widget(field, value, **attr)
    elif (ftype == 'blob'):
        inp = None
    else:
        ftype = (((ftype in widgets) and ftype) or 'string')
        inp = widgets[ftype].widget(field, value, **attr)
    return inp
