Skip to main content

Easy-to-setup PWA Admin Panel solution based on FastAPI, async SQLAlchemy and pre-render Swelte UI

Project description

# NorthAdmin

Easy-to-setup PWA Admin Panel solution based on FastAPI, async SQLAlchemy and pre-render Swelte UI.

___

[PyPI](https://pypi.org/project/north_admin/) | [GitHub](https://github.com/OlenEnkeli/north_admin) | [Example App](https://github.com/OlenEnkeli/north_admin_testapp) | [Frontend](https://github.com/OlenEnkeli/north_admin_frontend)

___

**This is beta-version and frontend part (UI) currenly is in development.**

**Now in NorthAdmin available only backend/API part,**

## Requirements

- Python 3.11+
- [FastAPI](https://github.com/tiangolo/fastapi) and [SQLAlclhemy](https://github.com/sqlalchemy/sqlalchemy)
- Any async DB driver like [AsyncPG](https://github.com/MagicStack/asyncpg)
- Any ASGI Python server like [Uvicorn](https://github.com/encode/uvicorn)

## Key benefits

- **Easy to integrate** - The amount of code that needs to be completed for the integration of the admin panel is minimal.
- **Fast** - NorthAdmin using async DB drivers and Swelte as UI framework to make admin panel as fast as possible.
- **PWA** - Similar solutions are offered by SSR, which is slower, less convenient and creates additional load on the server.
- **Flexibility** - We can create almost any filters to expand the functionality of the admin panel.
- **Good-looking** - Modern Material UI-based interface thanks to [TailWindCSS](https://tailwindcss.com/)

## Example

Let's assume that we have project with:

- Postgres
- Some SQLAlchemy models

In this example we prefer to use AsyncPG as driver.

### Install NorthAdmin

**Poetry**:

```bash
poetry add sqlalchemy asyncpg uvicorn north_admin
```

**PIP**

```bash
pip3 install sqlalchemy asyncpg uvicorn north_admin
pip3 freezee -> requirements.txt
```

### Add NorthAdmin in projects

For example, this is our `User` table look like:

```python
class User(Base):
__tablename__ = 'users'

id: Mapped[int] = mapped_column(primary_key=True)
email: Mapped[str] = mapped_column(unique=True, nullable=False, index=True)
password: Mapped[str] = mapped_column(nullable=False)
fullname: Mapped[str] = mapped_column(nullable=True)
is_active: Mapped[bool] = mapped_column(default=False)
is_admin: Mapped[bool] = mapped_column(default=False)
created_at: Mapped[dt] = mapped_column(default=dt.now, server_default=func.current_timestamp())
```


Suppose we need the ability:
- To view a list of users
- To get detailed information about each of them
- Soft delete (block) them
- We can do it only with non-admin users (User.user_type == UserType.user)

**This is an artificial one-line example.**

If you need a more complete production-ready example, see [NorthAdmin Test App](https://github.com/OlenEnkeli/north_admin_testapp)

So, here an out `admin.py` file:

```python
from datetime import datetime as dt
from enum import Enum

from fastapi import FastAPI
from sqlalchemy import bindparam, and_, select, func
from sqlalchemy.orm import Mapped, mapped_column, DeclarativeBase
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.dialects.postgresql import ENUM
from north_admin import (
NorthAdmin,
FilterGroup,
Filter,
FieldType,
AdminRouter,
AdminMethods,
AuthProvider,
setup_admin,
UserReturnSchema,
)
from north_admin.types import ModelType, QueryType


class Base(DeclarativeBase):
pass


class UserType(str, Enum):
USER = 'user'
ADMIN = 'admin'


class User(Base):
__tablename__ = 'users'

id: Mapped[int] = mapped_column(primary_key=True)
email: Mapped[str] = mapped_column(unique=True, nullable=False, index=True)
password: Mapped[str] = mapped_column(nullable=False)
fullname: Mapped[str] = mapped_column(nullable=True)
is_active: Mapped[bool] = mapped_column(default=True)
user_type: Mapped[UserType] = mapped_column(ENUM(UserType, name='user_type'), default=UserType.USER)
created_at: Mapped[dt] = mapped_column(default=dt.now, server_default=func.current_timestamp())


class AdminAuthProvider(AuthProvider):
async def login(
self,
session: AsyncSession,
login: str,
password: str,
) -> User | None:
query = (
select(User)
.filter(User.email == login)
.filter(User.user_type == UserType.ADMIN)
)

return await session.scalar(query)

async def get_user_by_id(
self,
session: AsyncSession,
user_id: int | str,
) -> User | None:
query = (
select(User)
.filter(User.id == user_id)
.filter(User.user_type == UserType.ADMIN)
)

return await session.scalar(query)

async def to_user_scheme(
self,
user: User,
) -> UserReturnSchema:
return UserReturnSchema(
id=user.id,
login=user.email,
fullname=user.fullname,
)


admin_app = NorthAdmin(
sqlalchemy_uri='postgresql+asyncpg://postgres:@127.0.0.1:5432/north_admin_test_app',
jwt_secket_key='JNBjdejjn!w443@wer',
auth_provider=AdminAuthProvider,
)

user_get_columns = [
User.id,
User.email,
User.fullname,
User.user_type,
User.created_at,
]


def exclude_admin_users(query: QueryType) -> QueryType:
query = query.filter(User.user_type != UserType.ADMIN)
return query


admin_app.add_admin_routes(
AdminRouter(
model=User,
model_title='Users',
enabled_methods=[
AdminMethods.GET_ONE,
AdminMethods.GET_LIST,
AdminMethods.SOFT_DELETE,
],
process_query_method=exclude_admin_users,
pkey_column=User.id,
soft_delete_column=User.is_active,
get_columns=user_get_columns,
list_columns=user_get_columns,
filters=[
FilterGroup(
query=(
and_(
User.created_at > dt.now().replace(hour=0, minute=0, second=0),
bindparam('created_today_param'),
)
),
filters=[
Filter(
bindparam='created_today_param',
title='Created today',
field_type=FieldType.BOOLEAN,
),
],
),
FilterGroup(
query=(User.created_at > bindparam('created_after_gt')),
filters=[
Filter(
bindparam='created_after_gt',
title='Created after',
field_type=FieldType.DATETIME,
)
],
),
]
)
)

app = FastAPI()

setup_admin(
admin_app=admin_app,
app=app,
)
```

Don't forget to use `Alembic` or other migration tools or `DeclarativeBase.Meta.create_all()` to create `User` table in DB

Short Example with psycopg:

Add this in the end of `admin.py`:

```python
if __name__ == '__main__':
from sqlalchemy import create_engine


Base.metadata.create_all(
bind=create_engine(
'postgresql+psycopg://postgres:@127.10.0.1:5432/north_admin_test_app'
),
)
```

Install pscyopg and run it:

```bash
poetry add psycopg psycopg-binary
python3 -m admin
```



**Now we finally can run it**:

```bash
poetry run uvicorn north_admin.test_app:app --host 0.0.0.0 --port 8000 --reload
```

### Let's take a look at what's going on here

- Firstly, we create `AdminAuthProvider`, what must implement three methods - `login`, `get_user_id`, `to_user_scheme`

- `login` - get `User` by login and password
- `get_user_by_id` - get `User` by id
- `to_user_schema` - dump `User` model to `UserReturnSchema`.


- Next we create `NorthAdmin` application with 3 required parameters (`sqlalchemy_uri`, `jwt_secket_key` and `auth_provider` - we just created it before)


- Now we can add admin page to our admin panel (`add_admin_routes` methods)

### Admin Router parameters:

- `model` - SQLAlchemy model we want to administrate (**required**)

- `model_title` - Verbose title (displayed in UI). By default generate from `model`

- `emoji` - Emoji displayed near to model name in UI. By default - random emoji.

- `enabled_methods` - List of actions, awailable in admin panel (`GET_LIST`, `GET_ONE`, `CREATE`, `UPDATE`, `DELETE`, `SOFT_DELETE`). By default - all ot them.

- `process_query_method` - Function applied to SQLAlchemy query in (`GET_LIST`, `GET_ONE`, `UPDATE`, `DELETE`, `SOFT_DELETE`) methods. Feel free to excluding, filtering, etc.

- `pkey_column` - Primary Key column. By default `model.id`

- `list_columns` - Columns displayed when displaying a list of `model` items in UI. By default - all columns.

- `get_columns` - Similary for viewing one item. By default - all columns.

- `create_columns` - Similary for creatine new item. By default - all non-key columns.

- `update_columns` - Similary for updatings existing item. By default - all non-key columns.

- `soft_delete_column` - Boolean SQLAlchemy column. When soft deleting (blocking) item, it set to `False`, is restoring to `True`. **Required**, if you have `SOFT_DELETE` in `enabled_methods`

- `sortable_columns` - List of SQLAclehmy columns, A list of columns to which we can apply sorting in the UI. By default - all key column. (See `sort_by` params in list method)

- `filters` - list of `FilterGroup` object. By default no filters applied.


### Filters

Filters are represented by `FilterGroup` and `Filter` classes

`FilterGroup` contains SQLAlchemy query with some `bind_params`.

Value of `bind_params` is represented in `Filter` `title` field and this is exactly the parameter that the front-end will.

Also `Filter` object contains name of filter in UI (`title`) and UI type (`field_type`)

In our case, we will see two filters in the admin panel:

- Checkbox `Created Today`
- Date-picker `Created After`

Awailable `FieldType`: `INTEGER`, `BOOLEAN` (checkbox), `FLOAT`, `STRING`, `ENUM` (listpicker), `DATETIME` (datetime picker), `ARRAY` (several string input)


**Filter system it may seem confusing (overcomplex) at the beginning, but it gives unlimited variability of implemented filters.**

### Result

Restart FastAPI application and **admin panel is ready**.

E.q. we running app with Uvicorn on http://127.0.0.1 we have:

- Admin Panel UI in http://127.0.0.1/admin/
- Admin Panel API in http://127.0.0.1/admin/api/
- Swagger in http://127.0.0.1/admin/docs/

Create user with `user_type=UserType.Admin`, check out Swagger and **enjoy using your new admin panel**.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

north_admin-0.1.4.tar.gz (28.0 kB view details)

Uploaded Source

Built Distribution

north_admin-0.1.4-py3-none-any.whl (27.7 kB view details)

Uploaded Python 3

File details

Details for the file north_admin-0.1.4.tar.gz.

File metadata

  • Download URL: north_admin-0.1.4.tar.gz
  • Upload date:
  • Size: 28.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.7.1 CPython/3.12.0 Darwin/23.1.0

File hashes

Hashes for north_admin-0.1.4.tar.gz
Algorithm Hash digest
SHA256 6aad61c9640672e625a66cad48aed9424232d78eb06444a5609bd36153ca4c7a
MD5 a10521040785d8c8e9f75a4d28199001
BLAKE2b-256 1fb85c928478aa973b964c18a789f63bc69595e27a982e9de6467a4c90c415af

See more details on using hashes here.

Provenance

File details

Details for the file north_admin-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: north_admin-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 27.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.7.1 CPython/3.12.0 Darwin/23.1.0

File hashes

Hashes for north_admin-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 76f75472eab52c65ac96d554681818c93b5b17e23adfc84b4b8801a4663ec5b3
MD5 b6ff3f87202944b71014996512ffb485
BLAKE2b-256 72275b2f709efa76fa11c70b693f9806272d714e7c21673fe730b6a0ed2a0180

See more details on using hashes here.

Provenance

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page