web2py / py4web

Other
261 stars 128 forks source link

Grid custom search_form duplicate formname #858

Closed mbelletti closed 7 months ago

mbelletti commented 9 months ago

When we create a custom search_form for a grid, the form will never be validated because _formname became a list with a duplicate formname.

example:

@action("grid", method=["POST", "GET"])    
@action("grid/<path:path>", method=["POST", "GET"])    
@action.uses(
    "grid.html",
    session,
    db,
)
def grid(path=None):

    form_attrs = {
        "submit_value": "Filter",
        "formstyle": FormStyleBulma,        
    }
    form = Form([
        Field('name',
              type="string",
              label='Name'
        )],
        keep_values=True,
        csrf_session=session,
        form_name='search_form',
        **form_attrs,            
    )    

    tc = db.things
    query = (tc.id>0 > 0)

    if form.accepted:
        query &= (tc.name.contains(form.vars.get('name', ''))

    if form.vars:    
        print(form.vars)
        # you will get something like:
        # {'_formname': ['search_form', 'search_form'], 'name': 'xyz'}

    grid_param = dict(
        rows_per_page=50,
        search_form=form,
        formstyle=FormStyleBulma,
        grid_class_style=GridClassStyleBulma,
    )

    orderby = [~tc.name]
    columns = [field for field in tc if field.readable]
    grid = Grid(
        path,
        query,
        columns=columns,
        orderby=orderby,
        show_id=False,
        **grid_param
    )
    return dict(grid=grid)

It seems related to Grid()._make_search_form that in line 1047 add hidden widgets:

        for hidden_widget in self.param.search_form.custom["hidden_widgets"].keys():
                div.append(self.param.search_form.custom["hidden_widgets"][hidden_widget])

but the hidden input with the formname is already inserted from line 1004 from this: div.append(self.param.search_form.custom["begin"])

my idea is to fix in this way:

        for hidden_widget in self.param.search_form.custom["hidden_widgets"].keys():
            if hidden_widget not in ('formname', 'formkey'):
                div.append(self.param.search_form.custom["hidden_widgets"][hidden_widget])