ДокументацияПонять модель
Основные понятия
Слова, которые используются в остальных документах — маршрут, страница, представление, компонент, обработчик, конечная точка — каждое в одной строке со ссылкой на более глубокую страницу. Впервые в Некси? Начните с Что такое Nexy?.
Как читать эти документы
| Уровень | Вопрос, на который он отвечает | Начните с |
|---|---|---|
| Архитектура приложения | какой уровень отвечает на запрос и что он отказывается делать | Как работает Nexy |
| Структура приложения | где живет код и каким становится файл | Структура проекта |
| Презентация и рендеринг | что видит читатель и кто создает HTML | Просмотры, Рендеринг |
| Взаимодействие с приложением | что делает читатель и что происходит в ответ | Действия |
Уровни читаются в таком порядке один раз. После этого вам нужна страница — это справочник, а не курс.
Архитектура приложения
Три способа решить, какой код соответствует URL-адресу. Это альтернативы, а не слои:
- Маршрутизация на основе файлов (FBR): файл в папке
src/routes/является маршрутом. Значение по умолчанию. - Модульный маршрутизатор: контроллеры и модули из
src/apps/, объявленные с помощью декораторов, для кодовой базы в стиле NestJS. - Пользовательский маршрутизатор: существующий FastAPI
APIRouter, включенный в приложение.
Выбор — одна строка класса NexyConfig в nexyconfig.py.
Маршрутизация на основе файлов не требует строки: без 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 }}" />Фронтальная часть и шаблон под ней представляют собой вид страницы; 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 отвечает рядом с включенными маршрутами.
Еще два слова, которые повторяются повсюду:
- Layout: файл
layout.*, который оборачивает страницы под своей папкой; корневой владеет HTML-документом. См. Макеты. - Зависимость: функция, которая запускается перед обработчиком, применяется для каждого маршрута или для каждой папки. См. Зависимости.
Презентация и рендеринг
Два независимых решения, которые часто путают:
- Формат определяет, какой файл отображает страницу: Представления.
- Режим решает, кто и когда создает HTML: Рендеринг.
| Понятие | Одна линия |
|---|---|
| Режим сервера | сервер отображает страницы .nexy и .md; компоненты являются островами (режимы) |
| Клиентский режим | useCSR = True: файлы фреймворка представляют собой маршруты, а навигация происходит в браузере. |
| ССР, ИСР, КСР, острова | четыре режима рендеринга, определяемые для каждой страницы, кроме CSR, который устанавливается для каждого проекта (рендеринг) |
| Увлажнение | браузер прикрепляет фреймворк к уже отправленному сервером HTML (острова) |
| Реквизит | значения, которые родитель передает компоненту, объявленному name: prop[type] в файле .nexy (файлы .nexy) |
Страница в режиме сервера с одним островом: сервер отображает страницу, браузер увлажняет диаграмму только при ее прокрутке в поле зрения.
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")Взаимодействие с приложением
| Понятие | Одна линия |
|---|---|
| Действие | функция Python с пометкой @Action, служащая как 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 оставляет вам