Closed CY-ipercept closed 5 months ago
Hey @CY-ipercept list of BaseModel is already covered by dash-pydantic-form. Are you having issues with it? https://pydf-docs.onrender.com/api/list_field
yep, i've updated the issue @RenaudLN
Also, another question about the pre-filled form feature.
If i have a model with an optional field such as info: Optional[SomeModel] = None
class SomeModel
compulsory_field: str
default_field: Literal["test", "test1", "test2"] = "test"
The item that i passed in does not have any info field filled in, but the form_data suddenly contains a value for default_field when I access the form_data via a dash callback, and throws validation errors for other missing fields in SomeModel like compulsory_field
class Branch(BaseModel):
name: Literal["West", "North", "East", "South"] = "West"
class Department(BaseModel):
name: str
sub_departments: List[str]
class Colleagues(BaseModel):
department: List[Department]
branch: Branch = Branch()
class Employee(BaseModel):
"""Employee model."""
name: str = Field(title="Name", description="Name of the employee", min_length=2)
age: int = Field(title="Age", description="Age of the employee, starting from their birth", ge=18)
mini_bio: str | None = Field(title="Mini bio", description="Short bio of the employee", default=None)
joined: date = Field(title="Joined", description="Date when the employee joined the company")
office: Office = Field(title="Office", description="Office of the employee")
metadata: Metadata | None = Field(title="Employee metadata", default=None)
location: HomeOffice | WorkOffice | None = Field(title="Work location", default=None, discriminator="type")
pets: list[Pet] = Field(title="Pets", description="Employee pets", default_factory=list)
jobs: list[str] = Field(
title="Past jobs", description="List of previous jobs the employee has held", default_factory=list
)
colleagues: Optional[Colleagues] = None
bob = Employee(
name="Bob",
age=30,
joined="2020-01-01",
mini_bio="### Birth\nSomething something\n\n### Education\nCollege",
office="au",
metadata={"languages": ["fr", "en"], "siblings": 2},
pets=[{"name": "Rex", "species": "cat"}],
location={
"type": "home_office",
"has_workstation": True,
},
jobs=["Engineer", "Lawyer"],
colleagues={"department": [{"name": "Engineering", "sub_departments": ["Software", "Hardware"]}]},
)
ModelForm(
# Employee,
bob,
AIO_ID,
FORM_ID,
)
Hope this helps! @RenaudLN
The prefilled form shows
workers:[{name:"Ben", 'associates': [None]}]
Hey @CY-ipercept, 0.2.2 fixes the issue with the pre-filled scalar list, thanks for bringing it up.
I'll have a look at the optional fields issue but this one is a bit trickier. Will let you know.
Update: on the optional field issue, it's not something that can be fixed clientside as it depends on the pydantic validation which can only happen serverside. The best I could do is a utility python function that creates a pydantic model with None if the field is optional and the sub-field fails to validate.
ah thanks @RenaudLN , I actually pulled the repo and made some changes, but was not able to push those changes cos of permission rights. But since you made the change already, I guess there is no need for mine. Thanks for making the changes!
This was the change I made, if you want to see:
def get_subitem(item: BaseModel, parent: str) -> BaseModel:
"""Get the subitem of a model at a given parent.
e.g., get_subitem(person, "au_metadata") = AUMetadata(param1=True, param2=False)
"""
if parent == "":
return item
path = parent.split(SEP)
first_part = path[0]
if isinstance(first_part, str) and first_part.isdigit():
first_part = int(first_part)
if len(path) == 1:
if isinstance(item, BaseModel):
return getattr(item, first_part)
if isinstance(item, dict) and isinstance(first_part, int):
return list(item.values())[first_part]
return item[first_part]
if isinstance(item, list) and isinstance(first_part, int):
return get_subitem(item[first_part], SEP.join(path[1:]))
return get_subitem(getattr(item, first_part), SEP.join(path[1:]))
My fix is similar. If you want to contribute to the project, you'll need to fork the repo, create a branch then create a pull request from there 🙂
@CY-ipercept I added a from_form_data
function to use a default value if it cannot validate a field. Note that it will go up the tree of fields until it finds a default value. An example of how to use it is in the usage.py
Let me know if this works for your case and I'll close this issue.
Edit: available in 0.3.0
Hi @RenaudLN , unfortunately, I encountered an error when trying to add a department
. Below is the screenshot of the error and the model that i used.
class Branch(BaseModel):
name: Literal["West", "North", "East", "South"] = "West"
class Department(BaseModel):
name: str
sub_departments: List[str]
class Colleagues(BaseModel):
department: List[Department]
branch: Branch = Branch()
class Employee(BaseModel):
"""Employee model."""
name: str = Field(title="Name", description="Name of the employee", min_length=2)
age: int = Field(title="Age", description="Age of the employee, starting from their birth", ge=18)
mini_bio: str | None = Field(title="Mini bio", description="Short bio of the employee", default=None)
joined: date = Field(title="Joined", description="Date when the employee joined the company")
office: Office = Field(title="Office", description="Office of the employee")
metadata: Metadata | None = Field(title="Employee metadata", default=None)
location: HomeOffice | WorkOffice | None = Field(title="Work location", default=None, discriminator="type")
pets: list[Pet] = Field(title="Pets", description="Employee pets", default_factory=list)
jobs: list[str] = Field(
title="Past jobs", description="List of previous jobs the employee has held", default_factory=list
)
colleagues: Optional[Colleagues] = None
bob = Employee(
name="Bob",
age=30,
joined="2020-01-01",
mini_bio="### Birth\nSomething something\n\n### Education\nCollege",
office="au",
metadata={"languages": ["fr", "en"], "siblings": 2},
pets=[{"name": "Rex", "species": "cat"}],
location={
"type": "home_office",
"has_workstation": True,
},
jobs=["Engineer", "Lawyer"],
)
Update: The updating of the form data seems a little buggy, as I have 2 strings in my list of sub-departments but the form_data shows 1
@RenaudLN I managed to come up with a fix for the from_form_data
function, will create a PR when it is ready
Hi again, @RenaudLN
Could support for List[BaseModel] be added when creating a prefilled form? I have a model where one of the parameters takes in a list of another model, and this other model contains parameters of floats, str, int, List[str], List[float] and List[int]. Hence, I would like to have these values populate the pre-filled form.
Example model structure
The prefilled form shows
workers:[{name:"Ben", 'associates': [None]}]
even though the json_obj has a list of strings
Thanks!