master
.The usage case is to provide two different views with list_query
and slightly different templates.
Having two views on the same model requires to provide a different name
and identity
to the second view to avoid a crash.
However, both links in the menu point to the same ModelView
, so only one of the two views is usable.
Side note: if a name
is omitted in the second view, we get a TypeError
in Menu.add
(called from BaseAdmin._build_menu
), which could probably be caught in advance to yield a more meaningful exception, such as "Multiple views on the same model must have different names".
MVE:
from sqlalchemy import Column, Integer, String, create_engine, select, Select, func
from sqlalchemy.orm import declarative_base, Session
from fastapi import FastAPI
from sqladmin import Admin, ModelView
from starlette.requests import Request
Base = declarative_base()
engine = create_engine(
"sqlite:///example.db",
connect_args={"check_same_thread": False},
)
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
name = Column(String)
email = Column(String)
Base.metadata.create_all(engine)
with Session(engine) as session:
if session.query(User.id).count() == 0:
session.add(User(name='Demo1', email='[email protected]'))
session.add(User(name='Demo2', email='demo2@bad_domain.org'))
session.commit()
# ------------------------
app = FastAPI()
admin = Admin(app, engine)
class UserAdmin(ModelView, model=User):
column_list = [User.id, User.name]
class BadDomainUserAdmin(ModelView, model=User):
column_list = [User.id, User.name]
name = 'Bad user' # omitting this leads to a TypeError
identity = 'bad_user'
def list_query(self, request: Request) -> Select:
return select(User).where(User.email == 'demo2@bad_domain.org')
def count_query(self, request: Request) -> Select:
return select(func.count()).select_from(User).where(User.email == 'demo2@bad_domain.org')
admin.add_view(UserAdmin)
admin.add_view(BadDomainUserAdmin)
There should be two distincts views with distincts URLs (or at least, I didn't find anything suggesting that this in not supported).
Both menu entries lead to /admin/user/list
, instead of /admin/bad_user/list
.
This seems to be due to identity
being overwritten by the slugified model name:
Line 89 in 751329c
Changing the line to
cls.identity = attrs.get("identity", slugify_class_name(model.__name__))
seems to fix it at least at first glance, however, identity
is referenced both in the templates and in models.py
as a parameter to build urls, so this is not sufficient. Indeed, the urls for user edititing and detailed display both point to user
instead of bad_user
.
The intention was to provide a customized list view for certain items in the table (so, listing only, no detail/edit view) with a custom form widget to allow the user to perform an action on some of these items.
Pay now to fund the work behind this issue.
Get updates on progress being made.
Maintainer is rewarded once the issue is completed.
You're funding impactful open source efforts
You want to contribute to this effort
You want to get funding like this too