Машинный перевод под контролем человека
Этот контент переведён с помощью машинной генерации, направляемой составленными людьми глоссариями и руководствами по стилю. Поскольку текст не проверяется вручную построчно, возможны отдельные ошибки или неестественные формулировки.
В случае любых расхождений авторитетным источником считается оригинальная версия на английском языке.
Интеграция с Tortoise ORM
Tortoise ORM — это нативный для asyncio объектно-реляционный преобразователь, вдохновлённый Django. Модуль starlette_admin.contrib.tortoise предоставляет специализированные классы Admin, ModelView и InlineModelView, которые предварительно настроены для прямой интеграции с вашими моделями Tortoise.
Ключевые возможности:
- Автоматическое преобразование полей: Поля моделей Tortoise напрямую сопоставляются с UI-компонентами. Это включает полную поддержку enum-ов, JSON, дат и автоматических меток времени.
- Сопоставление связей: Связи «один к одному» и внешние ключи преобразуются в поля
HasOne, а связи «многие ко многим» — в поляHasMany. Обратные связи автоматически отображаются в режиме только для чтения. - Расширенная фильтрация: В конструкторе фильтров используются выражения
Qиз Tortoise, а также доступен нечувствительный к регистру полнотекстовый поиск по строковым полям. - Преобразование ошибок: Ошибки валидации Tortoise напрямую сопоставляются с ошибками конкретных полей формы в интерфейсе.
Установка
Минимальный пример
Tortoise подключается к базе данных внутри контекстного менеджера lifespan вашего приложения. Поскольку admin-представления обычно создаются на этапе импорта (до выполнения Tortoise.init()), необходимо заранее разрешить связи.
Вызывайте Tortoise.init_models() сразу после определения моделей, чтобы связи были доступны к моменту построения admin-представлений.
from contextlib import asynccontextmanager
import uvicorn
from starlette.applications import Starlette
from tortoise import Tortoise, fields
from tortoise.models import Model
from starlette_admin.contrib.tortoise import Admin, ModelView
class Genre(Model):
id = fields.IntField(primary_key=True)
name = fields.CharField(max_length=100)
description = fields.TextField(null=True)
# Разрешение связей на этапе импорта до построения admin-представлений.
Tortoise.init_models(["app"], "models")
@asynccontextmanager
async def lifespan(app: Starlette):
await Tortoise.init(
db_url="sqlite://library.sqlite3", modules={"models": ["app"]}
)
await Tortoise.generate_schemas()
yield
await Tortoise.close_connections()
app = Starlette(lifespan=lifespan)
admin = Admin(title="Library Admin", secret_key="a-long-random-string")
admin.add_view(ModelView(Genre, icon="fa fa-tags"))
admin.mount_to(app)
if __name__ == "__main__":
uvicorn.run("app:app", reload=True)
ModelView принимает класс модели Tortoise Model напрямую и автоматически формирует список полей, формы и фильтры на основе схемы модели.
Основные классы
tortoise.Admin
Класс tortoise.Admin наследуется от BaseAdmin и не требует специфичной для базы данных конфигурации при инициализации. Настройка подключения полностью выполняется внутри lifespan приложения. Всегда импортируйте Admin из starlette_admin.contrib.tortoise, чтобы обеспечить совместимость с будущими улучшениями, специфичными для этого backend-а.
tortoise.ModelView
Класс tortoise.ModelView обеспечивает уровень интеграции между вашей базой данных и пользовательским интерфейсом. Он автоматически выполняет следующие операции:
- Заполнение полей: Если вы явно не указали поля, они генерируются из определения модели. Необработанные ключевые столбцы, лежащие в основе связей «к одному» (например,
author_idдля связи с именемauthor), а также обратные связи по умолчанию исключаются. - Разрешение связей: Все связи, отображаемые представлением, загружаются упреждающе. Это гарантирует, что списки и страницы деталей никогда не вызывают ленивую загрузку.
- Автоматические метки времени: Столбцы с
DatetimeField(auto_now=...)илиDatetimeField(auto_now_add=...)отображаются в режиме только для чтения и никогда не помечаются как обязательные. - Обработка ошибок: Ошибки валидации Tortoise (
"<field>: <detail>") преобразуются в ошибки конкретных полей формы, которые указывают пользователю прямо на некорректное значение.
from starlette_admin.contrib.tortoise import ModelView
class BookView(ModelView):
fields = ["id", "title", "isbn", "genres"]
searchable_fields = ["title", "isbn"]
sortable_fields = ["title"]
tortoise.InlineModelView
Встроенные представления позволяют редактировать связанные строки внутри родительской формы. Внешний ключ определяется автоматически, если дочерняя модель имеет ровно одну связь, указывающую на родительскую модель. Если связей несколько, необходимо явно задать fk_attr, указав либо имя связи, либо её необработанный ключевой столбец.
from starlette_admin.contrib.tortoise import InlineModelView, ModelView
class CommentInline(InlineModelView):
model = Comment
fields = ["id", "author", "body"]
extra = 2
class PostView(ModelView):
inlines = [CommentInline]
Работа со связями
Интеграция сопоставляет связи базы данных с полями admin-интерфейса в зависимости от типа поля. Для каждой связанной модели необходимо зарегистрировать ModelView, чтобы поля связей могли успешно разрешить свои внешние представления.
| Тип связи | Конфигурация Tortoise | Поведение в admin |
|---|---|---|
| Прямая (To-One) | ForeignKeyField, OneToOneField |
Преобразуется в HasOne. |
| Прямая (To-Many) | ManyToManyField |
Преобразуется в HasMany. |
| Обратная | свойства related_name |
Отображается в режиме только для чтения. Чтобы показать её, нужно явно добавить её в fields. |
Фильтрация и сортировка по связям:
Для связей «к одному» доступны фильтры «Is null» и «Is not null», работающие с необработанным ключевым столбцом. Чтобы сделать связь доступной в конструкторе фильтров, добавьте имя связи в searchable_fields. Чтобы включить сортировку по необработанному ключевому столбцу, добавьте имя связи в sortable_fields.
Поиск и фильтрация
Реестр фильтров
Каждый тип поля получает набор фильтров по умолчанию из TortoiseFilterRegistry, реализованный с помощью выражений Q из Tortoise:
- Сопоставление строк: Фильтры «содержит», «начинается/заканчивается на» и равенство используют поиск без учёта регистра (
__icontains,__istartswith,__iendswith,__iexact). - Enum-ы: Необработанные значения фильтров приводятся обратно к членам enum перед выполнением запроса как для столбцов
CharEnumField, так и дляIntEnumField. - Столбцы времени: Столбцы
TimeFieldподдерживают только проверки на null. Это ограничение существует потому, что параметры типа time невозможно переносимо привязать во всех поддерживаемых базах данных.
Полнотекстовый поиск
Поле поиска на странице списка выполняет нечувствительное к регистру сравнение contains (выражения Q, объединённые через OR) по всем доступным для поиска строковым полям. Это поведение можно настроить, переопределив метод get_search_query() в вашем представлении.
Полный рабочий пример
В этом разделе представлен полный, готовый к запуску пример интеграции Tortoise ORM с starlette-admin.
1. Установите зависимости
Пакет fastapi[standard] включает FastAPI CLI, что позволяет запустить сервер разработки командой fastapi dev.
2. Создайте приложение
Сохраните следующий код в файл с именем main.py.
from contextlib import asynccontextmanager
from enum import Enum
from fastapi import FastAPI
from starlette_admin import SlugField
from starlette_admin.contrib.tortoise import Admin, ModelView
from tortoise import Tortoise, fields
from tortoise.models import Model
DB_URL = "sqlite://blog.sqlite3"
class PostStatus(str, Enum):
DRAFT = "DRAFT"
PUBLISHED = "PUBLISHED"
ARCHIVED = "ARCHIVED"
class Author(Model):
id = fields.IntField(primary_key=True)
name = fields.CharField(max_length=100)
def __admin_repr__(self, request) -> str:
return self.name
class Post(Model):
id = fields.IntField(primary_key=True)
title = fields.CharField(max_length=200)
slug = fields.CharField(max_length=200, unique=True)
content = fields.TextField()
status = fields.CharEnumField(PostStatus, default=PostStatus.DRAFT)
created_at = fields.DatetimeField(auto_now_add=True)
author = fields.ForeignKeyField("models.Author", related_name="posts")
def __admin_repr__(self, request) -> str:
return self.title
# Разрешение связей на этапе импорта до построения admin-представлений.
Tortoise.init_models(["main"], "models")
class AuthorView(ModelView):
fields = ["id", "name"]
class PostView(ModelView):
fields = [
"id",
"title",
SlugField("slug", populate_from="title"),
"content",
"status",
"created_at",
"author",
]
searchable_fields = ["title", "content", "status"]
fields_default_sort = [("created_at", True)]
@asynccontextmanager
async def lifespan(app: FastAPI):
await Tortoise.init(db_url=DB_URL, modules={"models": ["main"]})
await Tortoise.generate_schemas()
yield
await Tortoise.close_connections()
app = FastAPI(lifespan=lifespan)
admin = Admin(title="Blog Admin", secret_key="change-me")
admin.add_view(AuthorView(Author, icon="fa fa-user"))
admin.add_view(PostView(Post, icon="fa fa-newspaper"))
admin.mount_to(app)
Поскольку created_at использует auto_now_add, admin автоматически отображает это поле в режиме только для чтения. Настраивать exclude_fields_from_create или exclude_fields_from_edit не требуется.
3. Запустите сервер
Запустите сервер разработки FastAPI:
Перейдите в браузере по адресу http://127.0.0.1:8000/admin, чтобы открыть панель администрирования и работать с ней.
Расширенный пример:
examples/17-tortoiseв репозитории содержит полнофункциональный пример, включающий связи, встроенные представления, enum-ы и JSON-поля на базе SQLite.
Что читать дальше
- Представления: Изучите параметры конфигурации
BaseModelView, независимые от используемого backend-а. - Фильтры: Узнайте о конструкторе фильтров и о том, как подключаются специфичные для ORM фильтры.
- SQLAlchemy: Документация по другому реляционному backend-у, встроенному в starlette-admin.