Skip to content

Commit eb51d74

Browse files
authored
Respect computed_field title in Details (#306)
1 parent 61d9b0c commit eb51d74

File tree

2 files changed

+47
-5
lines changed

2 files changed

+47
-5
lines changed

src/python-fastui/fastui/components/display.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,14 @@ class Details(BaseModel, extra='forbid'):
7979

8080
@pydantic.model_validator(mode='after')
8181
def _fill_fields(self) -> _te.Self:
82+
fields = {**self.data.model_fields, **self.data.model_computed_fields}
83+
8284
if self.fields is None:
83-
self.fields = [
84-
DisplayLookup(field=name, title=field.title) for name, field in self.data.model_fields.items()
85-
]
85+
self.fields = [DisplayLookup(field=name, title=field.title) for name, field in fields.items()]
8686
else:
8787
# add pydantic titles to fields that don't have them
8888
for field in (c for c in self.fields if c.title is None):
89-
pydantic_field = self.data.model_fields.get(field.field)
89+
pydantic_field = fields.get(field.field)
9090
if pydantic_field and pydantic_field.title:
9191
field.title = pydantic_field.title
9292
return self

src/python-fastui/tests/test_tables_display.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,11 @@ def test_display_no_fields():
8686
# insert_assert(d.model_dump(by_alias=True, exclude_none=True))
8787
assert d.model_dump(by_alias=True, exclude_none=True) == {
8888
'data': {'id': 1, 'name': 'john', 'representation': '1: john'},
89-
'fields': [{'field': 'id'}, {'title': 'Name', 'field': 'name'}],
89+
'fields': [
90+
{'field': 'id'},
91+
{'title': 'Name', 'field': 'name'},
92+
{'title': 'Representation', 'field': 'representation'},
93+
],
9094
'type': 'Details',
9195
}
9296

@@ -102,3 +106,41 @@ def test_display_fields():
102106
'fields': [{'title': 'ID', 'field': 'id'}, {'title': 'Name', 'field': 'name'}],
103107
'type': 'Details',
104108
}
109+
110+
111+
def test_table_respect_computed_field_title():
112+
class Foo(BaseModel):
113+
id: int
114+
115+
@computed_field(title='Foo Name')
116+
def name(self) -> str:
117+
return f'foo{self.id}'
118+
119+
foos = [Foo(id=1)]
120+
table = components.Table(data=foos)
121+
122+
# insert_assert(table.model_dump(by_alias=True, exclude_none=True))
123+
assert table.model_dump(by_alias=True, exclude_none=True) == {
124+
'data': [{'id': 1, 'name': 'foo1'}],
125+
'columns': [{'field': 'id'}, {'title': 'Foo Name', 'field': 'name'}],
126+
'type': 'Table',
127+
}
128+
129+
130+
def test_details_respect_computed_field_title():
131+
class Foo(BaseModel):
132+
id: int
133+
134+
@computed_field(title='Foo Name')
135+
def name(self) -> str:
136+
return f'foo{self.id}'
137+
138+
foos = Foo(id=1)
139+
details = components.Details(data=foos)
140+
141+
# insert_assert(table.model_dump(by_alias=True, exclude_none=True))
142+
assert details.model_dump(by_alias=True, exclude_none=True) == {
143+
'data': {'id': 1, 'name': 'foo1'},
144+
'fields': [{'field': 'id'}, {'title': 'Foo Name', 'field': 'name'}],
145+
'type': 'Details',
146+
}

0 commit comments

Comments
 (0)