dash-pydantic-form 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dash_pydantic_form-0.1.1/.gitignore +166 -0
- dash_pydantic_form-0.1.1/.pre-commit-config.yaml +15 -0
- dash_pydantic_form-0.1.1/.vscode/launch.json +28 -0
- dash_pydantic_form-0.1.1/CHANGELOG.md +10 -0
- dash_pydantic_form-0.1.1/PKG-INFO +268 -0
- dash_pydantic_form-0.1.1/README.md +248 -0
- dash_pydantic_form-0.1.1/dash_pydantic_form/__init__.py +24 -0
- dash_pydantic_form-0.1.1/dash_pydantic_form/fields/__init__.py +52 -0
- dash_pydantic_form-0.1.1/dash_pydantic_form/fields/all_fields.py +47 -0
- dash_pydantic_form-0.1.1/dash_pydantic_form/fields/base_fields.py +563 -0
- dash_pydantic_form-0.1.1/dash_pydantic_form/fields/editabletable_field.py +430 -0
- dash_pydantic_form-0.1.1/dash_pydantic_form/fields/model_fields.py +743 -0
- dash_pydantic_form-0.1.1/dash_pydantic_form/form_section.py +36 -0
- dash_pydantic_form-0.1.1/dash_pydantic_form/ids.py +31 -0
- dash_pydantic_form-0.1.1/dash_pydantic_form/model_form.py +329 -0
- dash_pydantic_form-0.1.1/dash_pydantic_form/pydantic_form_scripts.js +254 -0
- dash_pydantic_form-0.1.1/dash_pydantic_form/pydantic_form_styles.css +60 -0
- dash_pydantic_form-0.1.1/dash_pydantic_form/utils.py +138 -0
- dash_pydantic_form-0.1.1/dash_pydantic_form.egg-info/PKG-INFO +268 -0
- dash_pydantic_form-0.1.1/dash_pydantic_form.egg-info/SOURCES.txt +32 -0
- dash_pydantic_form-0.1.1/dash_pydantic_form.egg-info/dependency_links.txt +1 -0
- dash_pydantic_form-0.1.1/dash_pydantic_form.egg-info/requires.txt +11 -0
- dash_pydantic_form-0.1.1/dash_pydantic_form.egg-info/top_level.txt +4 -0
- dash_pydantic_form-0.1.1/docs/_config.yml +4 -0
- dash_pydantic_form-0.1.1/docs/index.md +1 -0
- dash_pydantic_form-0.1.1/images/conditionnally-visible-field.gif +0 -0
- dash_pydantic_form-0.1.1/images/editable-table.png +0 -0
- dash_pydantic_form-0.1.1/images/form-sections.png +0 -0
- dash_pydantic_form-0.1.1/images/model-list.png +0 -0
- dash_pydantic_form-0.1.1/images/nested-model.png +0 -0
- dash_pydantic_form-0.1.1/images/simple-form.png +0 -0
- dash_pydantic_form-0.1.1/pyproject.toml +53 -0
- dash_pydantic_form-0.1.1/setup.cfg +4 -0
- dash_pydantic_form-0.1.1/usage.py +178 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Terraform - .terraform* matches the local .lock.hcl files and modules that we do not want to export to git
|
|
10
|
+
.terraform*
|
|
11
|
+
|
|
12
|
+
# Distribution / packaging
|
|
13
|
+
.Python
|
|
14
|
+
build/
|
|
15
|
+
develop-eggs/
|
|
16
|
+
dist/
|
|
17
|
+
downloads/
|
|
18
|
+
eggs/
|
|
19
|
+
.eggs/
|
|
20
|
+
lib/
|
|
21
|
+
lib64/
|
|
22
|
+
parts/
|
|
23
|
+
sdist/
|
|
24
|
+
var/
|
|
25
|
+
wheels/
|
|
26
|
+
share/python-wheels/
|
|
27
|
+
*.egg-info/
|
|
28
|
+
.installed.cfg
|
|
29
|
+
*.egg
|
|
30
|
+
MANIFEST
|
|
31
|
+
|
|
32
|
+
# PyInstaller
|
|
33
|
+
# Usually these files are written by a python script from a template
|
|
34
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
35
|
+
*.manifest
|
|
36
|
+
*.spec
|
|
37
|
+
|
|
38
|
+
# Installer logs
|
|
39
|
+
pip-log.txt
|
|
40
|
+
pip-delete-this-directory.txt
|
|
41
|
+
|
|
42
|
+
# Unit test / coverage reports
|
|
43
|
+
htmlcov/
|
|
44
|
+
.tox/
|
|
45
|
+
.nox/
|
|
46
|
+
.coverage
|
|
47
|
+
.coverage.*
|
|
48
|
+
.cache
|
|
49
|
+
nosetests.xml
|
|
50
|
+
coverage.xml
|
|
51
|
+
*.cover
|
|
52
|
+
*.py,cover
|
|
53
|
+
.hypothesis/
|
|
54
|
+
.pytest_cache/
|
|
55
|
+
cover/
|
|
56
|
+
|
|
57
|
+
# Translations
|
|
58
|
+
*.mo
|
|
59
|
+
*.pot
|
|
60
|
+
|
|
61
|
+
# Django stuff:
|
|
62
|
+
*.log
|
|
63
|
+
local_settings.py
|
|
64
|
+
db.sqlite3
|
|
65
|
+
db.sqlite3-journal
|
|
66
|
+
|
|
67
|
+
# Flask stuff:
|
|
68
|
+
instance/
|
|
69
|
+
.webassets-cache
|
|
70
|
+
|
|
71
|
+
# Scrapy stuff:
|
|
72
|
+
.scrapy
|
|
73
|
+
|
|
74
|
+
# Sphinx documentation
|
|
75
|
+
docs/_build/
|
|
76
|
+
|
|
77
|
+
# PyBuilder
|
|
78
|
+
.pybuilder/
|
|
79
|
+
target/
|
|
80
|
+
|
|
81
|
+
# Jupyter Notebook
|
|
82
|
+
*.ipynb
|
|
83
|
+
.ipynb_checkpoints
|
|
84
|
+
|
|
85
|
+
# IPython
|
|
86
|
+
profile_default/
|
|
87
|
+
ipython_config.py
|
|
88
|
+
|
|
89
|
+
# pyenv
|
|
90
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
91
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
92
|
+
# .python-version
|
|
93
|
+
|
|
94
|
+
# pipenv
|
|
95
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
96
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
97
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
98
|
+
# install all needed dependencies.
|
|
99
|
+
#Pipfile.lock
|
|
100
|
+
|
|
101
|
+
# poetry
|
|
102
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
103
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
104
|
+
# commonly ignored for libraries.
|
|
105
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
106
|
+
#poetry.lock
|
|
107
|
+
|
|
108
|
+
# pdm
|
|
109
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
110
|
+
#pdm.lock
|
|
111
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
112
|
+
# in version control.
|
|
113
|
+
# https://pdm.fming.dev/#use-with-ide
|
|
114
|
+
.pdm.toml
|
|
115
|
+
|
|
116
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
117
|
+
__pypackages__/
|
|
118
|
+
|
|
119
|
+
# Celery stuff
|
|
120
|
+
celerybeat-schedule
|
|
121
|
+
celerybeat.pid
|
|
122
|
+
|
|
123
|
+
# SageMath parsed files
|
|
124
|
+
*.sage.py
|
|
125
|
+
|
|
126
|
+
# Environments
|
|
127
|
+
.env
|
|
128
|
+
.venv
|
|
129
|
+
env/
|
|
130
|
+
venv/
|
|
131
|
+
ENV/
|
|
132
|
+
env.bak/
|
|
133
|
+
venv.bak/
|
|
134
|
+
|
|
135
|
+
# Spyder project settings
|
|
136
|
+
.spyderproject
|
|
137
|
+
.spyproject
|
|
138
|
+
|
|
139
|
+
# Rope project settings
|
|
140
|
+
.ropeproject
|
|
141
|
+
|
|
142
|
+
# mkdocs documentation
|
|
143
|
+
/site
|
|
144
|
+
|
|
145
|
+
# mypy
|
|
146
|
+
.mypy_cache/
|
|
147
|
+
.dmypy.json
|
|
148
|
+
dmypy.json
|
|
149
|
+
|
|
150
|
+
# Pyre type checker
|
|
151
|
+
.pyre/
|
|
152
|
+
|
|
153
|
+
# pytype static type analyzer
|
|
154
|
+
.pytype/
|
|
155
|
+
|
|
156
|
+
# Cython debug symbols
|
|
157
|
+
cython_debug/
|
|
158
|
+
|
|
159
|
+
# PyCharm
|
|
160
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
161
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
162
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
163
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
164
|
+
#.idea/
|
|
165
|
+
|
|
166
|
+
.vscode/settings.json
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# See https://pre-commit.com for more information
|
|
2
|
+
# See https://pre-commit.com/hooks.html for more hooks
|
|
3
|
+
repos:
|
|
4
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
5
|
+
rev: v0.4.1
|
|
6
|
+
hooks:
|
|
7
|
+
- id: ruff
|
|
8
|
+
args: [ --fix ]
|
|
9
|
+
- id: ruff-format
|
|
10
|
+
|
|
11
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
12
|
+
rev: v4.5.0
|
|
13
|
+
hooks:
|
|
14
|
+
- id: trailing-whitespace
|
|
15
|
+
- id: end-of-file-fixer
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Use IntelliSense to learn about possible attributes.
|
|
3
|
+
// Hover to view descriptions of existing attributes.
|
|
4
|
+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
5
|
+
"version": "0.2.0",
|
|
6
|
+
"configurations": [
|
|
7
|
+
{
|
|
8
|
+
"name": "Python Debugger: Flask",
|
|
9
|
+
"type": "debugpy",
|
|
10
|
+
"request": "launch",
|
|
11
|
+
"module": "flask",
|
|
12
|
+
"env": {
|
|
13
|
+
"FLASK_APP": "usage.py:server",
|
|
14
|
+
"FLASK_DEBUG": "1",
|
|
15
|
+
"REACT_VERSION": "18.2.0",
|
|
16
|
+
"DEBUG": "1",
|
|
17
|
+
},
|
|
18
|
+
"args": [
|
|
19
|
+
"run",
|
|
20
|
+
"--no-debugger",
|
|
21
|
+
"--no-reload"
|
|
22
|
+
],
|
|
23
|
+
"jinja": true,
|
|
24
|
+
"autoStartBrowser": false,
|
|
25
|
+
"justMyCode": false
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
All notable changes to this project will be documented in this file.
|
|
3
|
+
|
|
4
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
5
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2022-10-27
|
|
9
|
+
### Added
|
|
10
|
+
- Working initial version
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: dash-pydantic-form
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Create Dash forms from pydantic objects
|
|
5
|
+
Author-email: Renaud Lainé <renaud.laine@enea-consulting.com>
|
|
6
|
+
License: Copyright ENEA Australia Pty Ltd - All Rights Reserved. Proprietary and confidential
|
|
7
|
+
Project-URL: Source, https://github.com/RenaudLN/dash-pydantic-form
|
|
8
|
+
Requires-Python: <3.11,>=3.10
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
Requires-Dist: dash
|
|
11
|
+
Requires-Dist: dash_mantine_components>=0.14
|
|
12
|
+
Requires-Dist: dash_iconify
|
|
13
|
+
Requires-Dist: dash_ag_grid
|
|
14
|
+
Requires-Dist: pandas
|
|
15
|
+
Requires-Dist: pydantic==2.*
|
|
16
|
+
Requires-Dist: flatdict
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
19
|
+
Requires-Dist: pytest; extra == "dev"
|
|
20
|
+
|
|
21
|
+
# Dash pydantic form
|
|
22
|
+
|
|
23
|
+
This package allows users to quickly create forms with Plotly Dash based on pydantic models.
|
|
24
|
+
|
|
25
|
+
## Getting started
|
|
26
|
+
|
|
27
|
+
Create a pydantic model you would like to display a form for.
|
|
28
|
+
|
|
29
|
+
*Note: This package uses pydantic 2.*
|
|
30
|
+
|
|
31
|
+
```py
|
|
32
|
+
from datetime import date
|
|
33
|
+
from typing import Literal
|
|
34
|
+
from pydantic import BaseModel, Field
|
|
35
|
+
|
|
36
|
+
class Employee(BaseModel):
|
|
37
|
+
first_name: str = Field(title="First name")
|
|
38
|
+
last_name: str = Field(title="Last name")
|
|
39
|
+
office: Literal["au", "uk", "us", "fr"] = Field(title="Office")
|
|
40
|
+
joined: date = Field(title="Employment date")
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Then you can get an auto-generated form with `ModelForm`, leveraging [dash-mantine-components](https://dash-mantine-components.com) for form inputs.
|
|
44
|
+
|
|
45
|
+
```py
|
|
46
|
+
from dash_pydantic_form import ModelForm
|
|
47
|
+
|
|
48
|
+
# somewhere in your layout:
|
|
49
|
+
form = ModelForm(
|
|
50
|
+
Employee,
|
|
51
|
+
aio_id="employees",
|
|
52
|
+
form_id="new_employee",
|
|
53
|
+
)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+

|
|
57
|
+
|
|
58
|
+
You can then retrieve the contents of the whole form at once in a callback as follows
|
|
59
|
+
|
|
60
|
+
```py
|
|
61
|
+
from dash import Input, Output, callback
|
|
62
|
+
|
|
63
|
+
@callback(
|
|
64
|
+
Output("some-output-id", "some-output-attribute"),
|
|
65
|
+
Input(ModelForm.ids.main("employees", "new_employee"), "data"),
|
|
66
|
+
)
|
|
67
|
+
def use_form_data(form_data: dict):
|
|
68
|
+
try:
|
|
69
|
+
print(Employee(**form_data))
|
|
70
|
+
except ValidationError as exc:
|
|
71
|
+
print("Could not validate form data:")
|
|
72
|
+
print(exc.errors())
|
|
73
|
+
return # ...
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Customising inputs
|
|
77
|
+
|
|
78
|
+
The `ModelForm` will automaticlly pick which input type to use based on the type annotation for the model field. However, you can customise how each field input is rendered, and or pass additional props to the DMC component.
|
|
79
|
+
|
|
80
|
+
```py
|
|
81
|
+
from dash_pydantic_form import ModelfForm, fields
|
|
82
|
+
|
|
83
|
+
form = ModelForm(
|
|
84
|
+
Employee,
|
|
85
|
+
aio_id="employees",
|
|
86
|
+
form_id="new_employee",
|
|
87
|
+
fields_repr={
|
|
88
|
+
# Change the default from a Select to Radio items
|
|
89
|
+
# NOTE: `description` can be set on pydantic fields as well
|
|
90
|
+
"office": fields.RadioItems(description="Wich country office?"),
|
|
91
|
+
# Pass additional props to the default input field
|
|
92
|
+
"joined": {"input_kwargs": {"maxDate": "2024-01-01"}},
|
|
93
|
+
},
|
|
94
|
+
)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### List of current field inputs:
|
|
98
|
+
|
|
99
|
+
Based on DMC:
|
|
100
|
+
* Checkbox
|
|
101
|
+
* Checklist
|
|
102
|
+
* Color
|
|
103
|
+
* Date
|
|
104
|
+
* Json
|
|
105
|
+
* MultiSelect
|
|
106
|
+
* Number
|
|
107
|
+
* Password
|
|
108
|
+
* RadioItems
|
|
109
|
+
* Range
|
|
110
|
+
* SegmentedControl
|
|
111
|
+
* Select
|
|
112
|
+
* Slider
|
|
113
|
+
* Switch
|
|
114
|
+
* Textarea
|
|
115
|
+
* Text
|
|
116
|
+
* Time
|
|
117
|
+
|
|
118
|
+
Custom:
|
|
119
|
+
* EditableTable
|
|
120
|
+
* Model
|
|
121
|
+
* ModelList
|
|
122
|
+
|
|
123
|
+
## Creating sections
|
|
124
|
+
|
|
125
|
+
There are 2 main avenues to create form sections:
|
|
126
|
+
|
|
127
|
+
### 1. Create a submodel in one of the model fields
|
|
128
|
+
|
|
129
|
+
```py
|
|
130
|
+
class HRData(BaseModel):
|
|
131
|
+
office: Literal["au", "uk", "us", "fr"] = Field(title="Office")
|
|
132
|
+
joined: date = Field(title="Employment date")
|
|
133
|
+
|
|
134
|
+
class EmployeeNested(BaseModel):
|
|
135
|
+
first_name: str = Field(title="First name")
|
|
136
|
+
last_name: str = Field(title="Last name")
|
|
137
|
+
hr_data: HRData = Field(title="HR data")
|
|
138
|
+
```
|
|
139
|
+
ModelForm will then recognise HRData as a pydantic model and use the `fields.Model` to render it, de facto creating a section.
|
|
140
|
+
|
|
141
|
+

|
|
142
|
+
|
|
143
|
+
### 2. Pass sections information to ModelForm
|
|
144
|
+
|
|
145
|
+
```py
|
|
146
|
+
from dash_pydantic_form import FormSection, ModelForm, Sections
|
|
147
|
+
|
|
148
|
+
form = ModelForm(
|
|
149
|
+
Employee,
|
|
150
|
+
aio_id="employees",
|
|
151
|
+
form_id="new_employee",
|
|
152
|
+
sections=Sections(
|
|
153
|
+
sections=[
|
|
154
|
+
FormSection(name="General", fields=["first_name", "last_name"], default_open=True),
|
|
155
|
+
FormSection(name="HR data", fields=["office", "joined"], default_open=False),
|
|
156
|
+
],
|
|
157
|
+
# 3 render values are available: accordion, tabs and steps
|
|
158
|
+
render="tabs",
|
|
159
|
+
),
|
|
160
|
+
)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+

|
|
164
|
+
|
|
165
|
+
## List of nested models
|
|
166
|
+
|
|
167
|
+
Dash pydantic form also handles lists of nested models with the possibility to add/remove items from the list and edit each one.
|
|
168
|
+
|
|
169
|
+
Let's say we now want to record the employee's pets
|
|
170
|
+
|
|
171
|
+
### 1. ModelList
|
|
172
|
+
|
|
173
|
+
This creates a list of sub-forms each of which can take similar arguments as a ModelForm (fields_repr, sections).
|
|
174
|
+
|
|
175
|
+
```py
|
|
176
|
+
class Pet(BaseModel):
|
|
177
|
+
name: str = Field(title="Name")
|
|
178
|
+
species: Literal["cat", "dog"] = Field(title="Species")
|
|
179
|
+
age: int = Field(title="Age")
|
|
180
|
+
|
|
181
|
+
class Employee(BaseModel):
|
|
182
|
+
first_name: str = Field(title="First name")
|
|
183
|
+
last_name: str = Field(title="Last name")
|
|
184
|
+
pets: list[Pet] = Field(title="Pets", default_factory=list)
|
|
185
|
+
|
|
186
|
+
form = ModelForm(
|
|
187
|
+
Employee,
|
|
188
|
+
aio_id="employees",
|
|
189
|
+
form_id="new_employee",
|
|
190
|
+
fields_repr={
|
|
191
|
+
"pets": fields.ModelList(
|
|
192
|
+
fields_repr={
|
|
193
|
+
"species": {"options_labels": {"cat": "Cat", "dog": "Dog"}}
|
|
194
|
+
},
|
|
195
|
+
# 3 render_type options: accordion, list or modal
|
|
196
|
+
render_type="accordion",
|
|
197
|
+
)
|
|
198
|
+
},
|
|
199
|
+
)
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+

|
|
203
|
+
|
|
204
|
+
### 2. EditableTable
|
|
205
|
+
|
|
206
|
+
You can also represent the list of sub-models as an ag-grid table with `fields.EditableTable`.
|
|
207
|
+
|
|
208
|
+
```py
|
|
209
|
+
form = ModelForm(
|
|
210
|
+
Employee,
|
|
211
|
+
aio_id="employees",
|
|
212
|
+
form_id="new_employee",
|
|
213
|
+
fields_repr={
|
|
214
|
+
"pets": fields.EditableTable(
|
|
215
|
+
fields_repr={
|
|
216
|
+
"species": {"options_labels": {"cat": "Cat", "dog": "Dog"}}
|
|
217
|
+
},
|
|
218
|
+
)
|
|
219
|
+
},
|
|
220
|
+
)
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+

|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
## Make fields conditionnally visible
|
|
227
|
+
|
|
228
|
+
You can make field visibility depend on the value of other fields in the form. To do so, simply pass a `visible` argument to the field.
|
|
229
|
+
|
|
230
|
+
```py
|
|
231
|
+
class Employee(BaseModel):
|
|
232
|
+
first_name: str
|
|
233
|
+
last_name: str
|
|
234
|
+
only_bob: str | None = Field(
|
|
235
|
+
title="Only for Bobs",
|
|
236
|
+
description="What's your favourite thing about being a Bob?",
|
|
237
|
+
default=None,
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
form = ModelForm(
|
|
241
|
+
Employee,
|
|
242
|
+
aio_id="employees",
|
|
243
|
+
form_id="new_employee",
|
|
244
|
+
fields_repr={
|
|
245
|
+
"only_bob": fields.Textarea(
|
|
246
|
+
visible=("first_name", "==", "Bob"),
|
|
247
|
+
)
|
|
248
|
+
},
|
|
249
|
+
)
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+

|
|
253
|
+
|
|
254
|
+
`visible` accepts a boolean, a 3-tuple or list of 3-tuples with format: (field, operator, value). The available operators are:
|
|
255
|
+
* "=="
|
|
256
|
+
* "!="
|
|
257
|
+
* "in"
|
|
258
|
+
* "not in"
|
|
259
|
+
* "array_contains"
|
|
260
|
+
* "array_contains_any"
|
|
261
|
+
|
|
262
|
+
NOTE: The field in the 3-tuples is a ":" separated path relative to the current field's level of nesting. If you need to reference a field from a parent or the root use the special values `_parent_` or `_root_`.
|
|
263
|
+
|
|
264
|
+
E.g., `visible=("_root_:first_name", "==", "Bob")`
|
|
265
|
+
|
|
266
|
+
## Creating custom fields
|
|
267
|
+
|
|
268
|
+
*To be written*
|