Files
fastapi-admin/docs/content.md

10 KiB

Builtin Auth And Permissions Control

You should inherit fastapi_admin.models.AbstractUser,fastapi_admin.models.AbstractPermission,fastapi_admin.models.AbstractRole and add extra fields.

from fastapi_admin.models import AbstractUser, AbstractPermission, AbstractRole

class AdminUser(AbstractUser):
    is_active = fields.BooleanField(default=False, description='Is Active')
    is_superuser = fields.BooleanField(default=False, description='Is Superuser')
    status = fields.IntEnumField(Status, description='User Status')
    created_at = fields.DatetimeField(auto_now_add=True)
    updated_at = fields.DatetimeField(auto_now=True)

class Permission(AbstractPermission):
    """
    must inheritance AbstractPermission
    """


class Role(AbstractRole):
    """
    must inheritance AbstractRole
    """


class AdminLog(AbstractAdminLog):
    """
    must inheritance AbstractAdminLog
    """

And set permission=True to active it:

await admin_app.init(
    ...
    permission=True,
    site=Site(
        ...
    ),
)

And createsuperuser:

> fastapi-admin -h
usage: fastapi-admin [-h] -c CONFIG [--version] {createsuperuser} ...

optional arguments:
  -h, --help            show this help message and exit
  -c CONFIG, --config CONFIG
                        Tortoise-orm config dict import path,like settings.TORTOISE_ORM.
  --version, -V         show the version

subcommands:
  {createsuperuser}

Before you use this command - remember that you have to define your own user model that inherits from fastapi-admin AbstractUser. eg.

from fastapi_admin.models import AbstractUser
from tortoise import fields

class User(AbstractUser):
    id = fields.BigIntField(pk=True)

Here's an example of how createsuperuser command can look like:

fastapi-admin -c "db.DB_CONFIG" createsuperuser -u User

The code above assumes that in your module's dir you have an db.py file in which there's, or that you provide a correct path on your own. -c flag proceeds the path to your database config dict. It can look something like this.

# db.py file
import os

DB_CONFIG: dict = {
    "connections": {
        "default": {
            "engine": "tortoise.backends.asyncpg",
            "credentials": {
                "host": os.environ.get("DB_HOST", "localhost"),
                "port": os.environ.get("DB_PORT", 5432),
                "user": os.environ.get("DB_USER", "user"),
                "password": os.environ.get("DB_PASSWORD", "secret_pass"),
                "database": os.environ.get("DB_DATABASE_NAME", "db"),
            },
        }
        # alternatively, probably only for testing purposes
        # "default": "sqlite://db.sqlite3",
    },
    "apps": {"models": {"models": ["app.db_models"]}},
}

Read more about configs and initialization in tortoise orm

After -u you can tell fastapi-admin which model inherits from AdminUser.

Custom Login

You can write your own login view logic:

await admin_app.init(
    ...,
    login_view="examples.routes.login"
)

And must return json like:

{
  "user": {
    "username": "admin",
    "is_superuser": false,
    "avatar": "https://avatars2.githubusercontent.com/u/13377178?s=460&u=d150d522579f41a52a0b3dd8ea997e0161313b6e&v=4"
  },
  "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyfQ.HSlcYkOEQewxyPuaqcVwCcw_wkbLB50Ws1-ZxfPoLAQ"
}

Enum Support

When you define a enum field of tortoise-orm,like IntEnumField,you can inherit fastapi_admin.enums.EnumMixin and impl choices() method, FastAPI-Admin will auto read and display and render a select widget in front.

class Status(EnumMixin, IntEnum):
    on = 1
    off = 2

    @classmethod
    def choices(cls):
        return {
            cls.on: 'ON',
            cls.off: 'OFF'
        }

Help Text

FastAPI-Admin will auto read description defined in tortoise-orm model Field and display in front with form help text.

ForeignKeyField Support

If ForeignKeyField is not passed in menu.raw_id_fields,FastAPI-Admin will get all related objects and display select in front with Model.__str__.

ManyToManyField Support

FastAPI-Admin will render ManyToManyField with multiple select in form edit with Model.__str__.

JSONField Render

FastAPI-Admin will render JSONField with jsoneditor as beauty interface.

Search Fields

Defined menu.search_fields in menu will render a search form by fields.

Xlsx Export

FastAPI-Admin can export searched data to excel file when define export=True in menu.

Bulk Actions

Current FastAPI-Admin supports builtin bulk action delete_all,if you want to write your own bulk actions:

  1. pass bulk_actions in Menu,example:
Menu(
    ...
    bulk_actions=[{
        'value': 'delete', # this is fastapi router path param.
        'text': 'delete_all', # this will show in front.
    }]
)
  1. write fastapi route,example:
from fastapi_admin.schemas import BulkIn
from fastapi_admin.factory import app as admin_app

@admin_app.post(
    '/rest/{resource}/bulk/delete' # `delete` is defined in Menu before.
)
async def bulk_delete(
        bulk_in: BulkIn,
        model=Depends(get_model)
):
    await model.filter(pk__in=bulk_in.pk_list).delete()
    return {'success': True}

Default Menus

Default, FastAPI-Admin provide default menus by your models, without doing tedious works. Therefore you do not need to fill the optional argument menus in Site definition.

Custom Menus

You can define a custom menu that'll be used by fastapi-admin. Here's an example of how that might look.


menus = [
    Menu(name="Home", url="/", icon="fa fa-home"),
    Menu(
        name="Content",
        children=[
            Menu(name="Category", url="/rest/Category", icon="fa fa-list", search_fields=("slug",)),
            Menu(name="Config", url="/rest/Config", icon="fa fa-gear", import_=True, search_fields=("key",)),
            Menu(name="Product", url="/rest/Product", icon="fa fa-table", search_fields=("name",)),
        ],
    ),
    Menu(
        name="External",
        children=[
            Menu(name="Github", url="https://github.com/long2ice/fastapi-admin", icon="fa fa-github", external=True),
        ],
    ),
    Menu(
        name="Auth",
        children=[
            Menu(name="User", url="/rest/User", icon="fa fa-user", search_fields=("username",),),
            Menu(name="Role", url="/rest/Role", icon="fa fa-group", ),
            Menu(name="Permission", url="/rest/Permission", icon="fa fa-user-plus", ),
            Menu(name="Logout", url="/logout", icon="fa fa-lock", ),
            Menu(
                name="AdminLog",
                url="/rest/AdminLog",
                icon="fa fa-align-left",
                search_fields=("action", "admin", "model"),
            ),
        ],
    ),
]

Each menu can either be a single element menu that'll only link to a given resource, or it can be a gathering of multiple links, that you add by using the children optional argument.

children should be a list of Menu objects.

Now that you have your menus you can use them during the app initialization.


menus = ...  # look at the code above. You can define it here or in separate file to make things neat

@app.on_event("startup")
async def start_up():
    await admin_app.init(  # nosec
        admin_secret="test",
        permission=True,
        admin_log=True,
        site=Site(
            name="FastAPI-Admin DEMO",
            login_footer="FASweTAPI ADMIN - FastAPI Admin Dashboard",
            login_description="FastAPI Admin Dashboard",
            locale="en-US",
            locale_switcher=True,
            theme_switcher=True,
            menus=menus
        ),
    )

Table Variant

You can define RowVariant and CellVariants in computed of tortoise-orm, which will effect table rows and cells variant.

class User(AbstractUser):
    last_login = fields.DatetimeField(description="Last Login", default=datetime.datetime.now)
    avatar = fields.CharField(max_length=200, default="")
    intro = fields.TextField(default="")
    created_at = fields.DatetimeField(auto_now_add=True)

    def __str__(self):
        return f"{self.pk}#{self.username}"

    def rowVariant(self) -> str:
        if not self.is_active:
            return "warning"
        return ""

    def cellVariants(self) -> dict:
        if self.is_active:
            return {
                "intro": "info",
            }
        return {}

    class PydanticMeta:
        computed = ("rowVariant", "cellVariants")

Admin log

You can log each admin action like delete,create and update,just set admin_log=True in admin_app.init() and just create a model in your app that inherits from fastapi_admin.models.AbstractAdminLog.

Import from excel

You can enable import by set import_=True in Menu definition, and data format must same as Model fields.

Custom filters

There are two kinds of filters named Filter and SearchFilter.

Filter use to filter view list default, and SearchFilter add a custom search input in front.

To use Filter you should only inherit fastapi_admin.filters.Filter then implement get_queryset, for example:

from fastapi_admin.filters import Filter

class CustomFilter(Filter):
    @classmethod
    def get_queryset(cls, queryset: QuerySet) -> QuerySet:
        return queryset.filter(~Q(key="test"))

Then add it to Menu.custom_filters.

Menu(
    name="Config",
    url="/rest/Config",
    icon="fa fa-gear",
    import_=True,
    search_fields=("key",),
    custom_filters=[CustomFilter],
)

And to use SearchFilter, like Filter but inherit fastapi_admin.filters.SearchFilter, note that you show register it by register_filter, for example:

from fastapi_admin.filters import SearchFilter, register_filter
from fastapi_admin.site import Field

@register_filter
class LikeFilter(SearchFilter):
    @classmethod
    def get_queryset(cls, queryset: QuerySet, value: Any) -> QuerySet:
        return queryset.filter(name__icontains=value)

    @classmethod
    async def get_field(cls) -> Field:
        return Field(label="NameLike", type="text")

    @classmethod
    def get_name(cls) -> str:
        return "filter"

get_name must return an unque name for all SearchFilter and get_field should return a Field instance.