Skip to content

Commit 07cb101

Browse files
authored
fix: strict field order matching list_display (#58)
1 parent 8a2c566 commit 07cb101

3 files changed

Lines changed: 55 additions & 3 deletions

File tree

fastadmin/models/helpers.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,13 @@ def generate_models_schema(
162162
),
163163
)
164164

165-
for column_index, field_name in enumerate(orm_model_fields_for_serialize):
165+
for field_name in orm_model_fields_for_serialize:
166166
display_field_function = getattr(admin_model_obj, field_name, None)
167167
if not display_field_function or not hasattr(display_field_function, "is_display"):
168168
continue
169+
if field_name not in column_fields:
170+
continue
171+
column_index = column_fields.index(field_name)
169172

170173
fields_schema.append(
171174
ModelFieldSchema(

tests/conftest.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
1414
from tortoise import Tortoise
1515

16+
from fastadmin import DjangoModelAdmin, PonyORMModelAdmin, SqlAlchemyModelAdmin, TortoiseModelAdmin
1617
from fastadmin.models.base import admin_models as admin_models_objs
1718
from fastadmin.models.helpers import get_admin_model
1819
from fastadmin.settings import settings
@@ -589,6 +590,20 @@ async def event(session_with_type, tortoiseorm_event, django_event, sqlalchemy_e
589590
yield obj
590591

591592

593+
@pytest.fixture()
594+
async def base_model_admin(session_with_type):
595+
_, session_type = session_with_type
596+
match session_type:
597+
case "tortoiseorm":
598+
yield TortoiseModelAdmin
599+
case "djangoorm":
600+
yield DjangoModelAdmin
601+
case "sqlalchemy":
602+
yield SqlAlchemyModelAdmin
603+
case "ponyorm":
604+
yield PonyORMModelAdmin
605+
606+
592607
@pytest.fixture()
593608
async def admin_models():
594609
prev_admin_models = {k: copy(v) for k, v in admin_models_objs.items()}

tests/models/test_helpers.py

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1-
from fastadmin import ModelAdmin
2-
from fastadmin.models.helpers import get_admin_model, register_admin_model_class, unregister_admin_model_class
1+
from fastadmin import ModelAdmin, display
2+
from fastadmin.models.helpers import (
3+
generate_models_schema,
4+
get_admin_model,
5+
get_admin_models,
6+
register_admin_model_class,
7+
unregister_admin_model_class,
8+
)
39

410

511
async def test_uregister_admin_model_class():
@@ -15,3 +21,31 @@ class OrmModelClass:
1521
unregister_admin_model_class([OrmModelClass])
1622
assert not get_admin_model(OrmModelClass.__name__)
1723
assert not get_admin_model(OrmModelClass)
24+
25+
26+
async def test_admin_model_list_configuration_ordering(tournament, base_model_admin):
27+
Tournament = tournament.__class__
28+
29+
class TournamentModelAdmin(base_model_admin):
30+
list_display = ("pseudo_name", "name", "another_calculated_field")
31+
32+
@display
33+
def pseudo_name(self, obj: Tournament) -> str:
34+
return "Pseudo name"
35+
36+
@display
37+
def another_calculated_field(self, obj: Tournament) -> int:
38+
return 0
39+
40+
model_schema = generate_models_schema({Tournament: TournamentModelAdmin(Tournament)})
41+
42+
assert model_schema
43+
assert len(model_schema) == 1
44+
45+
list_display = [
46+
(field.list_configuration.index, field.name) for field in model_schema[0].fields if field.list_configuration
47+
]
48+
list_display.sort()
49+
list_display = tuple(name for index, name in list_display)
50+
51+
assert list_display == TournamentModelAdmin.list_display

0 commit comments

Comments
 (0)