Skip to content

Working with Custom Views

Basic example

You might need to add custom views to the existing SQLAdmin views, for example to create dashboards, show custom info or add new forms.

To add custom views to the Admin interface, you can use the BaseView included in SQLAdmin. Here's an example to add custom views:

Example

from sqladmin import BaseView, expose

class ReportView(BaseView):
    name = "Report Page"
    icon = "fa-solid fa-chart-line"

    @expose("/report", methods=["GET"])
    async def report_page(self, request):
        return await self.templates.TemplateResponse(request, "report.html")

admin.add_view(ReportView)

This will assume there's a templates directory in your project and you have created a report.html in that directory.

If you want to use a custom directory name, you can change that with:

from sqladmin import Admin

admin = Admin(templates_dir="my_templates", ...)

Now visiting /admin/report you can render your report.html file.

Database access

The example above was very basic and you probably want to access database and SQLAlchemy models in your custom view. You can use sessionmaker the same way SQLAdmin is using it to do so:

Example

from sqlalchemy import Column, Integer, String, select, func
from sqlalchemy.orm import sessionmaker, declarative_base
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqladmin import Admin, BaseView, expose
from starlette.applications import Starlette

Base = declarative_base()
engine = create_async_engine("sqlite+aiosqlite:///test.db")
Session = sessionmaker(bind=engine, class_=AsyncSession)

app = Starlette()
admin = Admin(app=app, engine=engine)


class User(Base):
    __tablename__ = "users"

    id = Column(Integer, primary_key=True)
    name = Column(String(length=16))


class ReportView(BaseView):
    name = "Report Page"
    icon = "fa-solid fa-chart-line"

    @expose("/report", methods=["GET"])
    async def report_page(self, request):
        # async with engine.begin() as conn:
        #     await conn.run_sync(Base.metadata.create_all)

        async with Session(expire_on_commit=False) as session:
            stmt = select(func.count(User.id))
            result = await session.execute(stmt)
            users_count = result.scalar_one()

        return await self.templates.TemplateResponse(
            request,
            "report.html",
            context={"users_count": users_count},
        )


admin.add_view(ReportView)

Next we update the report.html file in the templates directory with the following content:

Example

{% extends "layout.html" %}
{% block content %}
<div class="col-12">
<div class="card">
    <div class="card-header">
    <h3 class="card-title">User reports</h3>
    </div>
    <div class="card-body border-bottom py-3">
    Users count: {{ users_count }}
    </div>
</div>
</div>
{% endblock %}

Now running your server you can head to /admin/report and you can see the number of users.