From 88ae0f92781b33ad02e02b0d42d850070a813fde Mon Sep 17 00:00:00 2001 From: long2ice Date: Thu, 13 May 2021 16:10:04 +0800 Subject: [PATCH] Add `column_attributes` --- CHANGELOG.md | 4 +++ docs/en/docs/reference/login.md | 4 +-- docs/en/docs/reference/resource.md | 41 +++++++++++++++++++------- fastapi_admin/app.py | 6 ---- fastapi_admin/resources.py | 3 ++ fastapi_admin/routes/__init__.py | 2 -- fastapi_admin/routes/password.py | 47 ------------------------------ fastapi_admin/routes/resources.py | 3 +- fastapi_admin/template.py | 9 ++++-- pyproject.toml | 2 +- setup.cfg | 5 +++- 11 files changed, 53 insertions(+), 73 deletions(-) delete mode 100644 fastapi_admin/routes/password.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a3ac3b..9f7d983 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## 1.0 +### 1.0.1 + +- Add `column_attributes`. + ### 1.0.0 **This is a completely different version and rewrite all code. If you are using old version, you can't upgrade directly, diff --git a/docs/en/docs/reference/login.md b/docs/en/docs/reference/login.md index 3f0deb2..717518d 100644 --- a/docs/en/docs/reference/login.md +++ b/docs/en/docs/reference/login.md @@ -52,11 +52,11 @@ async def startup(): Admin, settings.GOOGLE_CLIENT_ID, settings.GOOGLE_CLIENT_SECRET, - redirect_uri="https://fastapi-admin-pro.long2ice.cn/admin/login/google_oauth2_provider", + redirect_uri="https://fastapi-admin-pro.long2ice.cn/admin/oauth2/google_oauth2_provider", ), ] ) ``` If you want custom oauth2 provider, just inherit `fastapi_admin.providers.login.OAuth2Provider` and implement its -methods. +methods. And the `redirect_uri` format is `{server_url}/{admin_path}/oauth2/{provider_name}`. diff --git a/docs/en/docs/reference/resource.md b/docs/en/docs/reference/resource.md index 45fa636..fa7fcbb 100644 --- a/docs/en/docs/reference/resource.md +++ b/docs/en/docs/reference/resource.md @@ -50,7 +50,8 @@ class AdminResource(Model): ] ``` -You can pass `str` or `Field` to `fields`, if is `str`, it will try to auto mapping display and input widget, such as `displays.Boolean` for `BooleanField`, `inputs.Date` for `DateField`. +You can pass `str` or `Field` to `fields`, if is `str`, it will try to auto mapping display and input widget, such +as `displays.Boolean` for `BooleanField`, `inputs.Date` for `DateField`. All kind of widgets you can find in [Display](/reference/widget/display/) and [Input](/reference/widget/input/). @@ -58,9 +59,11 @@ All kind of widgets you can find in [Display](/reference/widget/display/) and [I The `Action` define the action display in every end of row, and bulk action for every model. -By default there are two actions, Which are delete action and edit action, and one bulk action, which allow delete rows in bulk. +By default there are two actions, Which are delete action and edit action, and one bulk action, which allow delete rows +in bulk. -To use that, you should override the `get_actions` and `get_bulk_actions`. The following example hide all default actions with return empty list. +To use that, you should override the `get_actions` and `get_bulk_actions`. The following example hide all default +actions with return empty list. ```python @app.register @@ -74,7 +77,8 @@ class AdminResource(Model): ## Model -`Model` is the core resource, which make TortoiseORM model as a menu and display a data table with create, update, and delete. +`Model` is the core resource, which make TortoiseORM model as a menu and display a data table with create, update, and +delete. ```python @app.register @@ -101,8 +105,9 @@ class AdminResource(Model): - `model`: TortoiseORM model. - `page_pre_title`: Show page pre title in content. - `page_title`: Show page title in content. -- `filters`: Define filters for the model, which will display filter inputs in table above, all kinds of filters you can find in [Filter](/reference/widget/filter/). -- `can_delete`: Whether show a `create` button there. +- `filters`: Define filters for the model, which will display filter inputs in table above, all kinds of filters you can + find in [Filter](/reference/widget/filter/). +- `can_create`: Whether show a `create` button there. ### row_attributes @@ -119,17 +124,33 @@ class ConfigResource(Model): The example above will add the css `class = "bg-green text-white"` for the row which `status = enums.Status.on`. +### column_attributes + +You can add extra attributes to each column by use `column_attributes`. + +```python +@app.register +class LogResource(Model): + async def column_attributes(self, request: Request, field: Field) -> dict: + if field.name == "content": + return {"class": "w-50"} + return await super().column_attributes(request, field) +``` + +The example above will add the css `class = "w-50"` for the column which `content`. + ### cell_attributes -Same as `row_attributes` but for the cell, you can add extra attributes to cell depends on the row object and column field. +Same as `row_attributes` but for the cell, you can add extra attributes to cell depends on the row object and column +field. ```python @app.register class AdminResource(Model): async def cell_attributes(self, request: Request, obj: dict, field: Field) -> dict: - if field.name == "id": - return {"class": "bg-danger text-white"} - return await super().cell_attributes(request, obj, field) + if field.name == "id": + return {"class": "bg-danger text-white"} + return await super().cell_attributes(request, obj, field) ``` ## Dropdown diff --git a/fastapi_admin/app.py b/fastapi_admin/app.py index 9c449e3..4892042 100644 --- a/fastapi_admin/app.py +++ b/fastapi_admin/app.py @@ -4,15 +4,9 @@ from aioredis import Redis from fastapi import FastAPI from pydantic import HttpUrl from starlette.middleware.base import BaseHTTPMiddleware -from starlette.status import HTTP_403_FORBIDDEN, HTTP_404_NOT_FOUND, HTTP_500_INTERNAL_SERVER_ERROR from tortoise import Model from fastapi_admin import i18n -from fastapi_admin.exceptions import ( - forbidden_error_exception, - not_found_error_exception, - server_error_exception, -) from . import middlewares, template from .providers import Provider diff --git a/fastapi_admin/resources.py b/fastapi_admin/resources.py index d51bab5..b2e4644 100644 --- a/fastapi_admin/resources.py +++ b/fastapi_admin/resources.py @@ -75,6 +75,9 @@ class Model(Resource): async def row_attributes(self, request: Request, obj: dict) -> dict: return {} + async def column_attributes(self, request: Request, field: Field) -> dict: + return {} + async def cell_attributes(self, request: Request, obj: dict, field: Field) -> dict: return {} diff --git a/fastapi_admin/routes/__init__.py b/fastapi_admin/routes/__init__.py index 25eed4b..c4af80a 100644 --- a/fastapi_admin/routes/__init__.py +++ b/fastapi_admin/routes/__init__.py @@ -1,8 +1,6 @@ from fastapi import APIRouter -from .password import router as password_router from .resources import router as resources_router router = APIRouter() router.include_router(resources_router) -router.include_router(password_router, prefix="/password") diff --git a/fastapi_admin/routes/password.py b/fastapi_admin/routes/password.py deleted file mode 100644 index 093c15e..0000000 --- a/fastapi_admin/routes/password.py +++ /dev/null @@ -1,47 +0,0 @@ -from fastapi import APIRouter, Depends, Form -from starlette.requests import Request - -from fastapi_admin.depends import get_current_admin, get_resources -from fastapi_admin.i18n import _ -from fastapi_admin.models import AbstractAdmin -from fastapi_admin.template import templates - -router = APIRouter() - - -@router.get("") -async def update_password_view( - request: Request, - resources=Depends(get_resources), -): - return templates.TemplateResponse( - "password.html", - context={ - "request": request, - "resources": resources, - }, - ) - - -@router.post("") -async def update_password( - request: Request, - old_password: str = Form(...), - new_password: str = Form(...), - re_new_password: str = Form(...), - admin: AbstractAdmin = Depends(get_current_admin), - resources=Depends(get_resources), -): - login_provider = request.app.login_provider - error = None - if not login_provider.check_password(admin, old_password): - error = _("old_password_error") - elif new_password != re_new_password: - error = _("new_password_different") - if error: - return templates.TemplateResponse( - "password.html", - context={"request": request, "resources": resources, "error": error}, - ) - await login_provider.update_password(admin, new_password) - return await login_provider.logout(request) diff --git a/fastapi_admin/routes/resources.py b/fastapi_admin/routes/resources.py index eca61bd..ed6a95e 100644 --- a/fastapi_admin/routes/resources.py +++ b/fastapi_admin/routes/resources.py @@ -38,7 +38,7 @@ async def list_view( page_size = model_resource.page_size qs = qs.offset((page_num - 1) * page_size) values = await qs.values(*fields_name) - rendered_values, row_attributes, cell_attributes = await render_values( + rendered_values, row_attributes, column_attributes, cell_attributes = await render_values( request, model_resource, fields, values ) context = { @@ -48,6 +48,7 @@ async def list_view( "fields": fields, "values": values, "row_attributes": row_attributes, + "column_attributes": column_attributes, "cell_attributes": cell_attributes, "rendered_values": rendered_values, "filters": filters, diff --git a/fastapi_admin/template.py b/fastapi_admin/template.py index 1ff73df..bbbc0c0 100644 --- a/fastapi_admin/template.py +++ b/fastapi_admin/template.py @@ -1,7 +1,7 @@ import os import typing from datetime import date -from typing import Any, List, Tuple +from typing import Any, List from urllib.parse import urlencode from jinja2 import contextfilter @@ -51,7 +51,7 @@ async def render_values( fields: List["Field"], values: List[typing.Dict[str, Any]], display: bool = True, -) -> typing.Tuple[List[List[Any]], List[dict], List[List[dict]]]: +) -> typing.Tuple[List[List[Any]], List[dict], List[dict], List[List[dict]]]: """ render values with template render :param fields: @@ -64,6 +64,9 @@ async def render_values( ret = [] cell_attributes: List[List[dict]] = [] row_attributes: List[dict] = [] + column_attributes: List[dict] = [] + for field in fields: + column_attributes.append(await model.column_attributes(request, field)) for value in values: row_attributes.append(await model.row_attributes(request, value)) item = [] @@ -76,4 +79,4 @@ async def render_values( item.append(await fields[i].input.render(request, value[k])) ret.append(item) cell_attributes.append(cell_item) - return ret, row_attributes, cell_attributes + return ret, row_attributes, column_attributes, cell_attributes diff --git a/pyproject.toml b/pyproject.toml index 7f679ce..beb9c15 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,7 @@ packages = [ ] readme = "README.md" repository = "https://github.com/fastapi-admin/fastapi-admin.git" -version = "1.0.0" +version = "1.0.1" [tool.poetry.dependencies] Babel = "*" diff --git a/setup.cfg b/setup.cfg index 28b9283..ce500a4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,2 +1,5 @@ [flake8] -ignore = E501,W503 \ No newline at end of file +ignore = E501,W503 +[mypy] +pretty = True +ignore_missing_imports = True