fastapi-amis-admin icon indicating copy to clipboard operation
fastapi-amis-admin copied to clipboard

如何实现一个动态内容的下拉选择?

Open myuanz opened this issue 3 years ago • 2 comments

我希望能在每一次加载页面的时候根据情况生成下拉选择框的成员, 我尝试在get_form_item里截取当前item然后往里面添加一些新的选项, 但是新的选项过不了FastApi的校验, 我尝试修改枚举也无效, 似乎fastapi总是持有最开始的那个枚举. 当前代码如下:

class NtpVersionEnum(Choices):
    t = "t"
    q = 'asd'

@site.register_admin
class 生成区域掩码(admin.FormAdmin):
    page_schema = '生成'

    form = Form(title='生成区域参数', submitText='提交')

    class schema(BaseModel):
        ntp_version: NtpVersionEnum = Field(NtpVersionEnum.t, title='NTP版本')

    async def handle(self, request: Request, data: BaseModel, **kwargs) -> BaseApiOut[Any]:
        return BaseApiOut(msg='登录成功!', data={'token': 'xxxxxx'})

    async def get_form_item(self, request: Request, modelfield: ModelField) -> Form:
        item = await super().get_form_item(request, modelfield)

        if item.label == 'NTP版本':
            global NtpVersionEnum
            new_enum = Choices('NtpVersionEnum', {'t': 't', 'q': 'q', 'apple': 'apple'})
            print(NtpVersionEnum._member_map_, NtpVersionEnum._member_names_)
            NtpVersionEnum._member_map_ = new_enum._member_map_
            NtpVersionEnum._member_names_ = new_enum._member_names_
            NtpVersionEnum._member_type_ = new_enum._member_type_
            objprint.objprint(NtpVersionEnum._member_map_, NtpVersionEnum._member_names_)
            objprint.objprint(NtpVersionEnum.__dict__)

            item.options.append(Select(value='apple', label='apple'))

        return item

报错为:

{"detail":[{"loc":["body","ntp_version"],"msg":"value is not a valid enumeration member; permitted: 't', 'q', 'apple'","type":"type_error.enum","ctx":{"enum_values":["t","q","apple"]}}]}

说是不允许 apple, 实际上传入的就是 apple.

我已经搜了一些关于如何动态定于应用于fastapi的enum的东西, 不过看起来很难, amis这里是否可能给出一个动态选项并且不使用枚举来约束呢? 如果不太复杂, 也可以给我一些指引, 我来做一个PR

myuanz avatar Jul 20 '22 10:07 myuanz

你可以参考amis相关组件文档,自定义相关属性: https://aisuda.bce.baidu.com/amis/zh-CN/components/form/select

 class schema(BaseModel):
     ntp_version: str= Field('', title='NTP版本',amis_form_item=amis.Select(value='apple', label='apple',source='xxxxxxx'),)

amisadmin avatar Jul 22 '22 13:07 amisadmin

你好, 我注意到另一个问题, 无论怎么改 schema 里的字段, 到前端的时候都是一个 input-text 或者 input-number, 比如写

ntp_version: str = Field(
    "",
    title="NTP版本",
    amis_form_item=amis.Select(
        value="apple", label="apple", source="/test-source"
    ),
)

会得到

{
    "type": "input-text",
    "name": "ntp_version",
    "label": "NTP版本",
    "required": false
}

而其他属性都消失, 目前我唯一发现能影响到前端的 json 的方式是在get_form_item里覆写. 比如在 class 里添加这段代码, 才能得到预期的 json:

async def get_form_item(self, request: Request, modelfield: ModelField) -> Form:
    '''删掉这个方法后, ntp_version 就不会显示下拉框了'''
    item = await super().get_form_item(request, modelfield)
    print(item)
    if item.label == 'NTP版本':
        item = Select(
            name='ntp_version', value="apple", label="NTP版本", source="/test-source"
        )
    return item
{
    "type": "select",
    "name": "ntp_version",
    "label": "NTP版本",
    "value": "apple",
    "source": "/test-source"
}

我的fastapi_amis_admin版本是 0.2.0, amis版本是0.1.1.


目前所有代码如下:

from typing import Any
from fastapi import FastAPI
from pydantic import BaseModel
from starlette.requests import Request
from fastapi_amis_admin.amis.components import Form, Select
from fastapi_amis_admin.admin import admin
from fastapi_amis_admin.admin.settings import Settings
from fastapi_amis_admin.admin.site import AdminSite
from fastapi_amis_admin.crud.schema import BaseApiOut
from fastapi_amis_admin.models.fields import Field
import amis
from pydantic.fields import ModelField


app = FastAPI()

site = AdminSite(
    settings=Settings(database_url_async="sqlite+aiosqlite:///amisadmin.db")
)


@app.get("/test-source")
def test_source():
    return {"message": "Hello World", 'zxc': 'zxc'}


@site.register_admin
class UserLoginFormAdmin(admin.FormAdmin):
    page_schema = "UserLoginForm"
    form = Form(title="这是一个测试登录表单", submitText="登录")

    class schema(BaseModel):
        username: str = Field(..., title="用户名", min_length=3, max_length=30)
        password: str = Field(..., title="密码")
        ntp_version: str = Field(
            'orange',
            title="NTP版本",
            amis_form_item=amis.Select(
                value="apple", label="apple", source="/test-source"
            ),
        )

    async def handle(
        self, request: Request, data: BaseModel, **kwargs
    ) -> BaseApiOut[Any]:
        print(data)
        return BaseApiOut(msg="登录成功!", data={"token": "xxxxxx"})

    async def get_form_item(self, request: Request, modelfield: ModelField) -> Form:
        '''删掉这个方法后, ntp_version 就不会显示下拉框了'''
        item = await super().get_form_item(request, modelfield)
        print(item)
        if item.label == 'NTP版本':
            item = Select(
                name='ntp_version', value="apple", label="NTP版本", source="/test-source"
            )
        return item


site.mount_app(app)

if __name__ == "__main__":
    import uvicorn
    uvicorn.run("main:app", debug=True, reload=True, workers=1)

myuanz avatar Jul 23 '22 03:07 myuanz