Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug with multi select fields #122

Open
schatimo opened this issue Dec 23, 2023 · 4 comments · May be fixed by #141 or #159
Open

Bug with multi select fields #122

schatimo opened this issue Dec 23, 2023 · 4 comments · May be fixed by #141 or #159
Milestone

Comments

@schatimo
Copy link

There is a bug with multi select fields when only one item is selected leading to an incorrect 422 error.

E.g., when selecting only one item for the "Select Multiple" select element on https://fastui-demo.onrender.com/forms/select, the POST request throws an unexpected 422 error:

{
    "detail": {
        "form": [
            {
                "type": "list_type",
                "loc": [
                    "select_multiple"
                ],
                "msg": "Input should be a valid list"
            }
        ]
    }
}

This might be related to tiangolo/fastapi#8741. A work-around, not elegant though, would be to add the following validation to SelectForm (https://github.com/pydantic/FastUI/blob/main/demo/forms.py):

@field_validator('select_multiple', mode='before')
@classmethod
    def correct_list_fields(cls, value: List[str] | str) -> List[str]:
        if isinstance(value, list):
            return value
        else:
            return [value]

Any thoughts on a neater solution?

@samuelcolvin
Copy link
Member

Ye I've seen that too.

Either we'll need a way to work out which fields expect lists, or you can just add a before validator to that field to convert v to [v].

@parthjoshi90
Copy link

can we do something like this? may I create a separate pull request?

parthjoshi90@0a1b464

@schatimo
Copy link
Author

Thanks, this looks neater to me as it does not require to add the before validation to every pydantic model separately.

@schatimo
Copy link
Author

schatimo commented Feb 22, 2024

We could add something like the following to check whether a field is of type array

@cache
def get_array_fields(model: pydantic.BaseModel) -> dict[str, bool]:
    """Iterate through json schema and identify which fields accept an array-like type."""
    from . import json_schema

    schema = _t.cast(json_schema.JsonSchemaObject, model.model_json_schema())
    defs = schema.get('$defs', {})
    is_array_dict = {}
    for f, prop in schema['properties'].items():
        field_schema, _ = json_schema.deference_json_schema(prop, defs, required=False)
        # Get nested items (this only goes one level deep and does no recursion), can be improved
        if 'properties' in field_schema.keys():
            field_schema, _ = json_schema.deference_json_schema(field_schema['properties'], defs, required=False)
            f = list(field_schema.keys())[0]
        try:
            is_array_dict[f] = True if json_schema.schema_is_array(field_schema) else False
        except Exception:
            is_array_dict[f] = False
    return is_array_dict

and then use this function in the unflatten method in forms.py to replace https://github.com/pydantic/FastUI/blob/4605e6d0158926ae06642ecde2d31e66ef908c1b/src/python-fastui/fastui/forms.py#L197C9-L197C29

if len(values) == 1:

with

if len(values) == 1 and not get_array_fields()[last_key]:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants