diff --git a/backend/apps/blog/__init__.py b/backend/apps/blog/__init__.py index 99002ef..da249fc 100644 --- a/backend/apps/blog/__init__.py +++ b/backend/apps/blog/__init__.py @@ -2,8 +2,8 @@ def setup(app: FastAPI): - # 1. 导入管理应用 - # 2. 注册普通路由 + # 1. Import the admin application + # 2. Register normal routes from . import admin, apis, events app.include_router(apis.router) diff --git a/backend/apps/blog/admin.py b/backend/apps/blog/admin.py index 80c78fe..e0946e8 100644 --- a/backend/apps/blog/admin.py +++ b/backend/apps/blog/admin.py @@ -24,7 +24,7 @@ @site.register_admin class BlogApp(admin.AdminApp): - page_schema = PageSchema(label="博客应用", icon="fa fa-wordpress") + page_schema = PageSchema(label="Blog Application", icon="fa fa-wordpress") def __init__(self, app: "AdminApp"): super().__init__(app) @@ -36,34 +36,33 @@ def __init__(self, app: "AdminApp"): class CategoryAdmin(admin.ModelAdmin): - page_schema = PageSchema(label="分类管理", icon="fa fa-folder") + page_schema = PageSchema(label="Category Management", icon="fa fa-folder") model = Category search_fields = [Category.name] class TagAdmin(admin.ModelAdmin): - page_schema = PageSchema(label="标签管理", icon="fa fa-tags") + page_schema = PageSchema(label="Tag Management", icon="fa fa-tags") model = Tag search_fields = [Tag.name] link_model_fields = [Tag.articles] class UserGender(IntegerChoices): - unknown = 0, "保密" - man = 1, "男" - woman = 2, "女" + unknown = 0, "Unknown" + man = 1, "Male" + woman = 2, "Female" class TestAction(admin.ModelAction): - action = ActionType.Dialog(tooltip="自定义表单动作",icon="fa fa-star",level=LevelEnum.warning, dialog=Dialog()) + action = ActionType.Dialog(tooltip="Custom Form Action",icon="fa fa-star",level=LevelEnum.warning, dialog=Dialog()) - # 创建表单数据模型 class schema(BaseModel): - username: str = Field(..., title="用户名") - password: str = Field(..., title="密码", amis_form_item="input-password") - birthday: datetime.datetime = Field(None, title="出生日期") - gender: UserGender = Field(UserGender.unknown, title="性别") - is_active: bool = Field(True, title="是否激活") + username: str = Field(..., title="Username") + password: str = Field(..., title="Password", amis_form_item="input-password") + birthday: datetime.datetime = Field(None, title="Birth Date") + gender: UserGender = Field(UserGender.unknown, title="Gender") + is_active: bool = Field(True, title="Is Active") async def handle(self, request: Request, item_id: List[str], data: schema, **kwargs) -> BaseApiOut[Any]: items = await self.admin.fetch_items(*item_id) @@ -71,32 +70,27 @@ async def handle(self, request: Request, item_id: List[str], data: schema, **kwa class ArticleAdmin(admin.ModelAdmin): - page_schema = PageSchema(label="文章管理", icon="fa fa-file") + page_schema = PageSchema(label="Article Management", icon="fa fa-file") model = Article - # 配置列表展示字段 list_display = [ Article.id, Article.title, Article.img, Article.status, Category.name, - TableColumn(type="tpl", label="自定义模板列", tpl='ID:${id},Title:${title}'), + TableColumn(type="tpl", label="Custom Template Column", tpl='ID:${id},Title:${title}'), Article.create_time, Article.description, - Category.name.label("category"), # 重命名字段;也可以使用sqlalchemy函数, 例如: - # func.count('*').label('article_count'), 注意在`get_select`中修改对应的sql查询语句 + Category.name.label("category"), LabelField( Category.name.label("category2"), - Field("默认分类", title="分类名称"), # 通过Field配置Amis表格列信息,Amis表单字段信息. + Field("Default Category", title="Category Name"), ), ] - # 配置模糊搜索字段 search_fields = [Article.title, Category.name] - # 配置关联模型 link_model_fields = [Article.tags] - # 配置自定义动作 admin_action_maker = [ - lambda self: TestAction(self, name="test_action", label="自定义动作", flags=["item", "bulk"]), + lambda self: TestAction(self, name="test_action", label="Custom Action", flags=["item", "bulk"]), lambda self: AdminAction( self, name="iframe_action", @@ -104,7 +98,7 @@ class ArticleAdmin(admin.ModelAdmin): action=ActionType.Dialog( icon="fa fa-star", level=LevelEnum.warning, - tooltip="自定义Iframe动作", + tooltip="Custom Iframe Action", dialog=Dialog( size="lg", body=amis.Iframe( @@ -113,7 +107,7 @@ class ArticleAdmin(admin.ModelAdmin): events={ "detail": { "actionType": "dialog", - "dialog": {"title": "弹框", "body": "iframe 传给 amis 的 id 是:${iframeId}"}, + "dialog": {"title": "Dialog", "body": "iframe passed to amis id is:${iframeId}"}, } }, ), @@ -126,7 +120,7 @@ class ArticleAdmin(admin.ModelAdmin): name="toolbar_action1", flags=["toolbar"], action=ActionType.Ajax( - label="工具条ajax动作", + label="Toolbar Ajax Action", level=LevelEnum.danger, api="https://3xsw4ap8wah59.cfc-execute.bj.baidubce.com/api/amis-mock/mock2/form/saveForm", ), @@ -136,7 +130,7 @@ class ArticleAdmin(admin.ModelAdmin): name="toolbar_action2", flags=["toolbar"], action=ActionType.Link( - label="工具条link动作", level=LevelEnum.secondary, link="https://github.com/amisadmin/fastapi_amis_admin" + label="Toolbar Link Action", level=LevelEnum.secondary, link="https://github.com/amisadmin/fastapi_amis_admin" ), ), lambda self: AdminAction( @@ -144,37 +138,36 @@ class ArticleAdmin(admin.ModelAdmin): name="toolbar_action3", flags=["toolbar"], action=ActionType.Drawer( - label="工具条抽屉动作", + label="Toolbar Drawer Action", level=LevelEnum.info, drawer={ - "title": "表单设置", + "title": "Form Settings", "body": { "type": "form", "api": "https://3xsw4ap8wah59.cfc-execute.bj.baidubce.com/api/amis-mock/mock2/form/saveForm?waitSeconds" "=1", "body": [ - {"type": "input-text", "name": "text", "label": "文本"}, + {"type": "input-text", "name": "text", "label": "Text"}, { "type": "input-number", "name": "number", - "label": "数字", + "label": "Number", "placeholder": "", "inline": True, "value": 5, "min": 1, "max": 10, }, - {"type": "input-rating", "count": 5, "value": 3, "label": "评分", "name": "rating"}, - {"type": "input-datetime", "name": "datetime", "inline": True, "label": "日期+时间"}, + {"type": "input-rating", "count": 5, "value": 3, "label": "Rating", "name": "rating"}, + {"type": "input-datetime", "name": "datetime", "inline": True, "label": "Date + Time"}, ], }, }, ), ), ] - display_item_action_as_column = True # 将item_action显示为列 + display_item_action_as_column = True - # 自定义查询选择器 async def get_select(self, request: Request) -> Select: sel = await super().get_select(request) return sel.outerjoin(Category) diff --git a/backend/apps/blog/apis.py b/backend/apps/blog/apis.py index 8ea0b20..1838010 100644 --- a/backend/apps/blog/apis.py +++ b/backend/apps/blog/apis.py @@ -10,19 +10,15 @@ router = APIRouter(prefix="/articles", tags=["ArticleAPI"]) - -# 方式一: 通过FastAPI依赖自动处理,获取session.(推荐) 特点: -# 1.同一个请求FastAPI会缓存依赖,对于多级依赖,同一个请求多次使用session对象,会减少session的获取成本. -# 2.如果`site.db`使用的是`AsyncDatabase`异步连接,则获取的是`AsyncSession`. -# 3.如果`site.db`使用的是`Database`同步连接,则获取的是`Session`. -# 2.1.同步Session可以充分利用`sqlalchemy`模型懒加载的特性. -# 2.2.注意不要在异步方法中使用同步Session,否则可能堵塞异步循环. -@router.get("/read/{id}", response_model=Article, summary="读取文章") +# Way 1: Use FastAPI dependencies to handle sessions automatically. (Recommended) +# Note: FastAPI will cache dependencies for the same request. +# Be cautious when using synchronous sessions in asynchronous methods. +@router.get("/read/{id}", response_model=Article, summary="Read article") async def read_article(id: int, session: AsyncSess): return await session.get(Article, id) -@router.get("/update/{id}", response_model=Article, summary="更新文章") +@router.get("/update/{id}", response_model=Article, summary="Update article") async def update_article(id: int, session: AsyncSess): article = await session.get(Article, id) if article: @@ -30,22 +26,14 @@ async def update_article(id: int, session: AsyncSess): await session.flush() return article - -# 方式二: 通过`sqlalchemy-database`提供的快捷函数.特点: -# 1.会自动获取当前上下文的session.(请理解session的获取原理,否则不要使用此方式) -# 1.1.如果需要多次使用同一个session,可以通过封装一个函数, 使用`run_sync`方法,减少session获取成本. -# 2.通过`async_`前缀方法,可以不用区分数据库连接是同步连接,还是异步连接. -# 2.1对于特定的项目,在能确定数据库连接是同步或异步的情况下,建议明确调用对应的方法. -# 2.2如果开发一个python包,供其他人使用不能确定连接是同步或异步,应该统一使用`async_`前缀方法. - - -@router.get("/read2/{id}", response_model=Article, summary="读取文章") +# Way 2: Use the shortcut functions provided by `sqlalchemy-database`. +@router.get("/read2/{id}", response_model=Article, summary="Read article") async def read_article2(id: int): article = await site.db.async_get(Article, id) return article -@router.put("/update2/{id}", response_model=Article, summary="更新文章") +@router.put("/update2/{id}", response_model=Article, summary="Update article") async def update_article2(id: int): article = await site.db.async_get(Article, id) if article: @@ -54,34 +42,27 @@ async def update_article2(id: int): return article -@router.post("/create2/", response_model=int, summary="新增文章") +@router.post("/create2/", response_model=int, summary="Create article") async def create_article2(data: Article): - # 新增数据模型根据实际情况自己定义 stmt = insert(Article).values(data.dict(exclude={"id"})) result = await site.db.async_execute(stmt) return result.lastrowid -@router.get("/list2", response_model=List[Article], summary="读取文章列表") +@router.get("/list2", response_model=List[Article], summary="List articles") async def list_article2(): - # 通用的查询表达式可以写在ORM模型,提供一个方法调用. stmt = select(Article).where(Article.status == ArticleStatus.published.value).limit(10).order_by(Article.create_time) result = await site.db.async_scalars(stmt) return result.all() - -# 方式三: 通过注册中间件,在每次请求时自动获取session,并在请求结束时自动关闭session. -# 注意: 必须在fastapi应用中注册中间件,才能在请求中获取session.(请理解session的获取原理,否则不要使用此方式) -# 1.如果`site.db`使用的是`AsyncDatabase`异步连接,则获取的是`AsyncSession`. -# 2.如果`site.db`使用的是`Database`同步连接,则获取的是`Session`. -# 建议在`core.globals.py`中建立一个`db`对象,用于管理数据库连接. -@router.get("/read3/{id}", response_model=Article, summary="读取文章") +# Way 3: Register a middleware to handle session automatically on each request. +@router.get("/read3/{id}", response_model=Article, summary="Read article") async def read_article3(id: int): article = await site.db.session.get(Article, id) return article -@router.put("/update3/{id}", response_model=Article, summary="更新文章") +@router.put("/update3/{id}", response_model=Article, summary="Update article") async def update_article3(id: int): article = await site.db.session.get(Article, id) if article: @@ -90,17 +71,15 @@ async def update_article3(id: int): return article -@router.post("/create3/", response_model=int, summary="新增文章") +@router.post("/create3/", response_model=int, summary="Create article") async def create_article3(data: Article): - # 新增数据模型根据实际情况自己定义 stmt = insert(Article).values(data.dict(exclude={"id"})) result = await site.db.session.execute(stmt) return result.lastrowid -@router.get("/list3", response_model=List[Article], summary="读取文章列表") +@router.get("/list3", response_model=List[Article], summary="List articles") async def list_article3(): - # 通用的查询表达式可以写在ORM模型,提供一个方法调用. stmt = select(Article).where(Article.status == ArticleStatus.published.value).limit(10).order_by(Article.create_time) result = await site.db.session.scalars(stmt) return result.all() diff --git a/backend/apps/blog/events.py b/backend/apps/blog/events.py index de4e72c..77860d1 100644 --- a/backend/apps/blog/events.py +++ b/backend/apps/blog/events.py @@ -6,13 +6,15 @@ @event.listens_for(Article, "before_insert") def receive_before_insert(mapper, connection: Connection, article: Article): - """监听创建文章""" + """Listen for the creation of an article""" # sess = object_session(article) # do something @event.listens_for(Article.status, "set") def receive_set(article: Article, value, old, initiator): - """监听文章状态改变""" + """Listen for changes to the article's status""" # sess = object_session(article) # do something + + diff --git a/backend/apps/blog/models.py b/backend/apps/blog/models.py index 1b6b483..0727448 100644 --- a/backend/apps/blog/models.py +++ b/backend/apps/blog/models.py @@ -9,46 +9,52 @@ class ArticleStatus(IntegerChoices): - unpublished = 0, "未发布" - published = 1, "已发布" - inspection = 2, "审核中" - disabled = 3, "已禁用" + # Article status enum + unpublished = 0, "Unpublished" + published = 1, "Published" + inspection = 2, "Under Review" + disabled = 3, "Disabled" class Category(SQLModel, table=True): + # Article category id: int = Field(default=None, primary_key=True, nullable=False) - name: str = Field(title="CategoryName", sa_column=Column(String(100), unique=True, index=True, nullable=False)) + name: str = Field(title="Category Name", sa_column=Column(String(100), unique=True, index=True, nullable=False)) description: str = Field(default="", title="Description", amis_form_item="textarea") - status: bool = Field(None, title="status") + status: bool = Field(None, title="Status") articles: List["Article"] = Relationship(back_populates="category") class ArticleTagLink(SQLModel, table=True): + # Link table between articles and tags tag_id: Optional[int] = Field(default=None, foreign_key="tag.id", primary_key=True) article_id: Optional[int] = Field(default=None, foreign_key="article.id", primary_key=True) class Tag(SQLModel, table=True): + # Article tags id: int = Field(default=None, primary_key=True, nullable=False) - name: str = Field(..., title="TagName", sa_column=Column(String(255), unique=True, index=True, nullable=False)) + name: str = Field(..., title="Tag Name", sa_column=Column(String(255), unique=True, index=True, nullable=False)) articles: List["Article"] = Relationship(back_populates="tags", link_model=ArticleTagLink) class Article(SQLModel, table=True): + # Article model id: int = Field(default=None, primary_key=True, nullable=False) - title: str = Field(title="ArticleTitle", max_length=200) + title: str = Field(title="Article Title", max_length=200) img: str = Field( None, - title="ArticleImage", + title="Article Image", max_length=300, amis_form_item=InputImage(maxLength=1, maxSize=2 * 1024 * 1024, receiver="post:/admin/file/upload"), amis_table_column=ColumnImage(width=100, height=60, enlargeAble=True), ) - description: str = Field(default="", title="ArticleDescription", amis_form_item="textarea") - status: ArticleStatus = Field(ArticleStatus.unpublished, title="status") - content: str = Field(..., title="ArticleContent", amis_form_item=InputRichText()) - create_time: Optional[datetime] = Field(default_factory=datetime.utcnow, title="CreateTime") - category_id: Optional[int] = Field(default=None, foreign_key="category.id", title="CategoryId") + description: str = Field(default="", title="Article Description", amis_form_item="textarea") + status: ArticleStatus = Field(ArticleStatus.unpublished, title="Status") + content: str = Field(..., title="Article Content", amis_form_item=InputRichText()) + create_time: Optional[datetime] = Field(default_factory=datetime.utcnow, title="Create Time") + category_id: Optional[int] = Field(default=None, foreign_key="category.id", title="Category ID") category: Optional[Category] = Relationship(back_populates="articles") tags: List[Tag] = Relationship(back_populates="articles", link_model=ArticleTagLink) - source: str = Field(default="", title="ArticleSource", max_length=200) + source: str = Field(default="", title="Article Source", max_length=200) + diff --git a/backend/apps/demo/__init__.py b/backend/apps/demo/__init__.py index b5908da..a04eaee 100644 --- a/backend/apps/demo/__init__.py +++ b/backend/apps/demo/__init__.py @@ -2,5 +2,5 @@ def setup(app: FastAPI): - # 1. 导入管理应用 + # 1. Import the admin application from . import admin diff --git a/backend/apps/demo/admin.py b/backend/apps/demo/admin.py index 409a704..724685f 100644 --- a/backend/apps/demo/admin.py +++ b/backend/apps/demo/admin.py @@ -15,7 +15,7 @@ from starlette.requests import Request from starlette.templating import Jinja2Templates -api_docs_app = site.get_admin_or_create(APIDocsApp) # 获取或创建默认的APIDocsApp实例 +api_docs_app = site.get_admin_or_create(APIDocsApp) # Get or create a default APIDocsApp instance @api_docs_app.register_admin @@ -26,10 +26,10 @@ class DocsAdmin(admin.IframeAdmin): @api_docs_app.register_admin class ReDocsAdmin(admin.IframeAdmin): - # 设置页面菜单信息 + # Set page menu information page_schema = PageSchema(label="Redocs", icon="fa fa-book") - # 设置跳转链接 + # Set redirect link @property def src(self): return f"{self.app.site.settings.site_url}/redoc" @@ -37,10 +37,9 @@ def src(self): @site.register_admin class GitHubLinkAdmin(admin.LinkAdmin): - # 通过page_schema类属性设置页面菜单信息; - # PageSchema组件支持属性参考: https://baidu.gitee.io/amis/zh-CN/components/app + # Set page menu information via page_schema class attribute page_schema = PageSchema(label="GitHub", icon="fa fa-github") - # 设置跳转链接 + # Set redirect link link = "https://github.com/amisadmin/fastapi_amis_admin" @@ -59,49 +58,44 @@ def __init__(self, app: "AdminApp"): class HelloWorldPageAdmin(admin.PageAdmin): page_schema = PageSchema(label="HelloWorld", icon="fa fa-link") - # 通过page类属性直接配置页面信息; - # Page组件支持属性参考: https://baidu.gitee.io/amis/zh-CN/components/page - page = Page(title="标题", body="Hello World!") + page = Page(title="Title", body="Hello World!") class CurrentTimePageAdmin(admin.PageAdmin): page_schema = PageSchema(label="CurrentTime", icon="fa fa-link") - # 通过get_page类方法实现动态获取页面信息. async def get_page(self, request: Request) -> Page: page = await super().get_page(request) - page.body = "当前时间是: " + time.strftime("%Y-%m-%d %H:%M:%S") + page.body = "The current time is: " + time.strftime("%Y-%m-%d %H:%M:%S") return page class UserGender(IntegerChoices): - unknown = 0, "保密" - man = 1, "男" - woman = 2, "女" + unknown = 0, "Secret" + man = 1, "Male" + woman = 2, "Female" class UserRegFormAdmin(admin.FormAdmin): page_schema = PageSchema(label="UserRegForm", icon="fa fa-link") - # 创建表单数据模型 class schema(BaseModel): - username: str = Field(..., title="用户名") - password: str = Field(..., title="密码", amis_form_item="input-password") - birthday: datetime.datetime = Field(None, title="出生日期") - gender: UserGender = Field(UserGender.unknown, title="性别") - is_active: bool = Field(True, title="是否激活") + username: str = Field(..., title="Username") + password: str = Field(..., title="Password", amis_form_item="input-password") + birthday: datetime.datetime = Field(None, title="Birth Date") + gender: UserGender = Field(UserGender.unknown, title="Gender") + is_active: bool = Field(True, title="Active") avatar: str = Field( None, - title="头像", + title="Avatar", max_length=100, amis_form_item=InputImage(maxLength=1, maxSize=2 * 1024 * 1024, receiver="post:/admin/file/upload"), ) - # 处理表单提交数据 async def handle(self, request: Request, data: schema, **kwargs) -> BaseApiOut: if data.username == "amisadmin" and data.password == "amisadmin": - return BaseApiOut(msg="注册成功!", data={"token": "xxxxxx"}) - return BaseApiOut(status=-1, msg="用户名或密码错误!") + return BaseApiOut(msg="Registration successful!", data={"token": "xxxxxx"}) + return BaseApiOut(status=-1, msg="Username or password incorrect!") @site.register_admin diff --git a/backend/apps/demo/templates/element.html b/backend/apps/demo/templates/element.html index 3e3ebdb..cb24deb 100644 --- a/backend/apps/demo/templates/element.html +++ b/backend/apps/demo/templates/element.html @@ -3,28 +3,30 @@ - + - + - Element Plus demo + Element Plus Demo
Hello Element Plus
- + + active-text="Selected" inactive-text="Not Selected"> - + php + Copy code
- + - +
@@ -44,16 +46,18 @@
- - - - - + + + + + - ElementUI + ElementUI
diff --git a/backend/core/globals.py b/backend/core/globals.py index 93c0b7d..67a423a 100644 --- a/backend/core/globals.py +++ b/backend/core/globals.py @@ -7,7 +7,7 @@ from core import settings -# 同步数据库. +# Synchronize Database sync_db = Database.create( settings.database_url, session_options={ @@ -15,7 +15,7 @@ }, ) -# 异步数据库 +# Asynchronous Database async_db = AsyncDatabase.create( settings.database_url_async, echo=settings.debug, @@ -24,35 +24,32 @@ site = AdminSite(settings=settings, engine=async_db) - -# 1. 默认后台管理站点,无用户认证与授权系统 +# 1. Default administration site without user authentication and authorization system # site = AdminSite(settings=settings) -# 2. 从 fastapi_user_auth 导入安装用户认证与授权系统的后台管理站点 -# 使用之前先执行'pip install fastapi_user_auth'安装库 -# 参考文档: https://github.com/amisadmin/fastapi_user_auth +# 2. Import and install user authentication and authorization system from fastapi_user_auth +# Run 'pip install fastapi_user_auth' before using +# Reference Documentation: https://github.com/amisadmin/fastapi_user_auth # from fastapi_user_auth.site import AuthAdminSite # # site = AuthAdminSite(settings=settings) - -# 3. 自定义后台管理站点 +# 3. Custom Administration Site class NewAdminSite(AdminSite): - # 自定义应用模板,复制原模板文件修改,原路径: fastapi_amis_admin/amis/templates/app.html + # Customize application template, copy and modify the original template file, Original path: fastapi_amis_admin/amis/templates/app.html template_name = "/templates/new_app.html" def __init__(self, settings: Settings, *, fastapi: FastAPI = None, **kwargs): super().__init__(settings, fastapi=fastapi, **kwargs) app = self.get_admin_or_create(APIDocsApp) - # 取消注册默认管理类 + # Unregister default admin classes app.unregister_admin(DocsAdmin, ReDocsAdmin) async def get_page(self, request: Request) -> App: app = await super().get_page(request) - # 自定义站点名称,logo信息, 参考: https://baidu.gitee.io/amis/zh-CN/components/app + # Customize site name and logo information, Reference: https://baidu.gitee.io/amis/zh-CN/components/app app.brandName = "MyAdminSite" app.logo = "https://baidu.gitee.io/amis/static/logo_408c434.png" return app - # site = NewAdminSite(settings=settings) diff --git a/backend/core/settings.py b/backend/core/settings.py index 14510e2..f8f739d 100644 --- a/backend/core/settings.py +++ b/backend/core/settings.py @@ -5,10 +5,13 @@ from fastapi_amis_admin import admin +# Define the backend directory BACKEND_DIR = Path(__file__).resolve().parent.parent -sys.path.append(BACKEND_DIR.__str__()) +# Add the backend directory to a system path +sys.path.append(str(BACKEND_DIR)) +# Define a Settings class inheriting from admin.Settings class Settings(admin.Settings): name: str = "FastAPI-Amis-Admin-Demo" host: str = "127.0.0.1" @@ -17,7 +20,8 @@ class Settings(admin.Settings): allow_origins: List[str] = None -# 设置FAA_GLOBALS环境变量 +# Set the FAA_GLOBALS environment variable os.environ.setdefault("FAA_GLOBALS", "core.globals") +# Initialize settings with values from the .env file settings = Settings(_env_file=os.path.join(BACKEND_DIR, ".env")) diff --git a/backend/main.py b/backend/main.py index 2e91435..0f4fd2c 100644 --- a/backend/main.py +++ b/backend/main.py @@ -6,35 +6,38 @@ app = FastAPI(debug=settings.debug) -# 安装应用demo +# Setup demo application from apps import demo demo.setup(app) -# 安装应用blog +# Setup blog application from apps import blog blog.setup(app) -# 挂载后台管理系统 +# Mount the backend management system site.mount_app(app) -# 注意1: site.mount_app会默认添加site.db的session会话上下文中间件,如果你使用了其他的数据库连接,请自行添加.例如: +# Note 1: site.mount_app will by default add site.db's session context middleware. +# If you are using a different database connection, please add it yourself. +# For example: # from core.globals import sync_db -# app.add_middleware(sync_db.asgi_middleware) # 注意中间件的注册顺序. +# app.add_middleware(sync_db.asgi_middleware) +# Note the order in which middleware is registered. -# 注意2: 非请求上下文中,请自行创建session会话,例如:定时任务,测试脚本等. +# Note 2: In non-request context, please create your own session, +# such as scheduled tasks, test scripts, etc. # from core.globals import async_db # async with async_db(): # async_db.async_get(...) # async_db.session.get(...) # # do something - @app.on_event("startup") async def startup(): await site.db.async_run_sync(SQLModel.metadata.create_all, is_session=False) - # 运行后台管理系统启动事件 + # Run the startup event of the backend management system await site.router.startup()