文档了解模型
核心理念
文档的其余部分使用的单词 - 路由、页面、视图、组件、处理程序、端点 - 每个都在一行中,并带有指向更深入页面的链接。新来内克西?从Nexy 是什么? 开始。
如何阅读这些文档
| 级别 | 它回答的问题 | 开始于 |
|---|---|---|
| 应用架构 | 哪一层响应请求,以及拒绝执行什么操作 | Nexy 的工作原理 |
| 应用结构 | 代码所在的位置以及文件的内容 | 项目结构 |
| 演示和渲染 | 读者看到什么以及谁生成 HTML | 视图、渲染 |
| 应用交互 | 读者做了什么,以及响应了什么 | 行动 |
级别按该顺序读取一次。之后,您需要的页面是查找,而不是课程。
应用架构
决定哪些代码响应 URL 的三种方法。它们是替代方案,而不是层:
- 基于文件的路由(FBR):
src/routes/下的文件是一个路由。默认。 - 模块化路由器:
src/apps/下的控制器和模块,用装饰器声明,用于NestJS风格的代码库。 - 自定义路由器:应用程序中包含的现有 FastAPI
APIRouter。
选择的是 nexyconfig.py 中 NexyConfig 类的一行。
基于文件的路由不需要行:没有 useRouter,Nexy 读取 src/routes/。
from nexy.core.models import NexyConfigModel class NexyConfig(NexyConfigModel): pass # file-based: no useRouter, the files of src/routes/ are the routes模块化路由器是 src/apps/的根模块:
from nexy.core.models import NexyConfigModel from src.apps.app_module import AppModule class NexyConfig(NexyConfigModel): useRouter = AppModule # modular: the root module of src/apps/自定义路由器是您已经拥有的 APIRouter:
from nexy.core.models import NexyConfigModel from src.legacy import api # an APIRouter you already have class NexyConfig(NexyConfigModel): useRouter = api # custom: your router, included as it is选择三者之一就是一个决定。选择前端框架是另一个单独的框架:请参阅选择路由器 和视图。
应用结构
来自 Next.js 的读者通常会将五个概念合并为一个。它们不是同一件事,这种差异解释了大多数“为什么我的页面不渲染”的问题。
| 观念 | 它是什么 | 它不是什么 |
|---|---|---|
| 路线 | 由文件路径生成的 URL 模式 | 一个文件:一个文件可以回答多个 URL ([slug]) |
| 页 | 渲染视图的路由文件:.nexy、.md、.mdx、.tsx、.vue、.svelte |
端点:它回答文档,而不是数据 |
| 查看 | 生成页面正文的内容:Jinja2 和 Python、Markdown 或客户端组件 | 一条路线:同一个视图可以服务多个页面 |
| 组件 | 页面导入的可重用部分 | 路由:在服务器模式下,组件永远不会单独提供服务 |
| 路由处理程序 | .py 路由文件的功能,以 HTTP 方法命名(GET、POST、...) |
页面:它返回 JSON、文件或 Response |
| 端点 | 处理程序回答的对(URL、方法) | 处理程序:一个文件可以回答多个端点 |
用一句话来说:页面是一个路由文件,视图是渲染它的东西,组件是页面重用的东西,处理程序回答端点。
五合一小项目:
from "@/components/Like.tsx" import Like slug: prop[str]<h1>{{ slug }}</h1><Like post="{{ slug }}" />frontmatter及其下面的模板是页面的视图; Like 是它重用的组件。
async def GET(): # the endpoint GET /api/posts return {"posts": []} async def POST(): # the endpoint POST /api/posts return {"created": True}对于模块化路由器,路由是控制器的路径,处理程序是其方法之一,以 HTTP 动词命名:
from nexy.decorators import Controller @Controller("/api/posts")class PostsController: async def get(self) -> dict: # the endpoint GET /api/posts return {"posts": []} async def post(self) -> dict: # the endpoint POST /api/posts return {"created": True}from nexy.decorators import Module from .posts_controller import PostsController @Module()class AppModule: controllers = [PostsController]页面仍然是 src/routes/的文件,或者控制器以 useViews返回的视图。
对于自定义路由器,路由是 APIRouter 的路径,处理程序是其装饰器注册的函数:
from fastapi import APIRouter api = APIRouter() @api.get("/api/posts") # the endpoint GET /api/postsasync def list_posts(): return {"posts": []} @api.post("/api/posts") # the endpoint POST /api/postsasync def create_post(): return {"created": True}页面仍然是 src/routes/的文件:.nexy 页面在包含的路线旁边进行回答。
还有两个词随处可见:
演示和渲染
两个独立的决定,经常混淆:
| 观念 | 一条线 |
|---|---|
| 服务器模式 | 服务器呈现 .nexy 和 .md 页面;组件是岛屿(模式) |
| 客户端模式 | useCSR = True:框架文件是路线,导航发生在浏览器中 |
| SSR、ISR、CSR、岛屿 | 四种渲染模式,按页面决定,CSR 除外,CSR 是按项目决定的 (渲染) |
| 保湿 | 浏览器将框架附加到服务器已发送的 HTML (岛屿) |
| 道具 | 父级传递给组件的值,在 .nexy 文件(.nexy 文件)中声明为 name: prop[type] |
具有一个岛的服务器模式页面:服务器呈现页面,浏览器仅在图表滚动到视图中时才对图表进行水合。
from "@/components/Chart.tsx" import Chart<h1>Sales</h1><Chart directive="client:visible" />岛屿进入视图,控制器返回视图:
from "@/components/Chart.tsx" import Chart<h1>Sales</h1><Chart directive="client:visible" />from nexy.decorators import Controllerfrom nexy.hooks import useViews @Controller("/sales")class SalesController: async def get(self): return useViews("src/apps/sales_view.nexy")应用交互
| 观念 | 一条线 |
|---|---|
| 行动 | 标记为 @Action 的 Python 函数,用作 POST,可从表单调用或作为类型化函数 (操作) |
| 形式 | 发布到操作的 HTML 表单,验证错误返回到页面 (操作) |
| 导航 | 预取的链接,以及读取路径、查询、cookie 和会话的钩子 (钩子) |
| 数据获取 | 由需要它的页面或处理程序完成; Nexy 不提供客户端数据层(处理函数) |
一个操作和发布到它的表单,在任何脚本加载之前起作用:
from nexy.decorators import Action @Actionasync def subscribe(email: str) -> bool: return True<form method="post" action="{{ __actions_path['subscribe'] }}"> <input name="email" type="email"> <button type="submit">Subscribe</button></form><form method="post" action="{{ __actions_path['subscribe'] }}"> <input name="email" type="email"> <button type="submit">Subscribe</button></form>Nexy 不做什么
身份验证、授权、数据库、国际化、后台作业、电子邮件、付款和搜索是 您的应用程序的责任,而不是框架的责任。 Nexy 给出了扩展点并说明了每个扩展点的插入位置:请参阅 Nexy 留给您的内容 。
例如,身份验证插入到其保护的文件夹的依赖项中。 Nexy 在下面的每条路线之前运行它;用户是谁由您决定:
from nexy import unauthorizedfrom nexy.http import Request def require_login(request: Request) -> None: if not request.session.get("user"): unauthorized(scheme="Bearer") dependencies = [require_login]例如,身份验证插入其保护的控制器上的防护装置。 Nexy 在类的每个处理程序之前运行它;用户是谁由您决定:
from nexy import unauthorizedfrom nexy.decorators import Controller, UseGuardfrom nexy.http import Request def require_login(request: Request) -> None: if not request.session.get("user"): unauthorized(scheme="Bearer") @Controller("/account")@UseGuard(require_login)class AccountController: async def get(self) -> dict: return {"ok": True}例如,身份验证插入到它所保护的路由器的依赖项中,如 FastAPI 中所示;用户是谁由您决定:
from fastapi import APIRouter, Depends from nexy import unauthorizedfrom nexy.http import Request def require_login(request: Request) -> None: if not request.session.get("user"): unauthorized(scheme="Bearer") api = APIRouter(prefix="/account", dependencies=[Depends(require_login)])原因并不是极简主义本身:选择 ORM 或身份验证库的框架已经决定了只有您的应用程序才能决定的事情。
后续步骤
- 项目结构:项目的每个文件夹和文件
- 词汇表:相同的单词,在一个字母索引中
- Nexy 的工作原理:层、谁构建什么以及 Nexy 留给您什么