Traducción automática supervisada
Este contenido se traduce mediante generación automática guiada por glosarios y guías de estilo revisados por personas. Dado que el texto no se revisa manualmente línea por línea, pueden producirse errores ocasionales o expresiones poco naturales.
En caso de cualquier discrepancia, la versión en inglés constituye la autoridad y la fuente de referencia.
Guía de migración
Esta página recopila las instrucciones de actualización entre las versiones de starlette-admin. Salte a la sección correspondiente a la versión desde la que está actualizando.
De 0.17.x a 1.0.0
Esta versión refactoriza el funcionamiento interno de starlette-admin e introduce un amplio conjunto de nuevas funcionalidades. Aunque la API de alto nivel se mantiene prácticamente sin cambios, la actualización más significativa es la reescritura del renderizado de la página de lista. Hemos eliminado DataTables en favor de una tabla renderizada en el servidor. La mayoría de los demás cambios consisten en renombrados o modificaciones menores de firmas.
Esta guía cubre cada cambio incompatible en el orden en el que es más probable que los encuentre. Cada sección compara la API antigua junto con su reemplazo. Si su implementación se basa en lo básico o en personalizaciones ligeras (como una instancia de Admin, algunas subclases de ModelView, fields y searchable_fields), su migración probablemente se limitará a las secciones Requisitos y Constructor de Admin, más algunos renombrados.
Las personalizaciones de la página de lista antigua requieren mayor atención. Las opciones de DataTables y las funciones de renderizado en JavaScript no tienen equivalente directo y deben trasladarse a plantillas del lado del servidor (consulte Eliminación de DataTables).
Tip
Actualice sus dependencias en un solo paso e inicie su aplicación. La mayoría de los atributos eliminados o renombrados generan errores claros al arrancar en lugar de fallar silenciosamente en tiempo de ejecución.
Novedades
Además de los cambios incompatibles descritos a continuación, esta versión incluye:
- Tablas de lista nativas: DataTables ha sido eliminado en favor de una implementación integrada renderizada en el servidor. El estado de la tabla ahora está completamente controlado por la URL, lo que significa que todas las configuraciones de página, filtro y ordenación son inmediatamente compartibles y guardables como marcadores.
- Filtros: Un constructor de filtros anidado con
AND/ORsustituye a SearchBuilder de DataTables. Los filtros se derivan de los tipos de campo y son totalmente extensibles en Python puro. Puede escribir una clase de filtro sin necesidad de JavaScript. - Importación y exportación del lado del servidor: Importe datos desde CSV, JSON, Excel y más, con informes de error por fila, junto con exportadores del lado del servidor (CSV, JSON, Excel, PDF, etc.) que sustituyen a los botones del lado del cliente de DataTables.
- Eventos: Suscríbase a hooks del ciclo de vida como
before_create,after_edit_committed,after_loginy varios eventos de acciones. - Temas y Plugins: Empaquete y reutilice estéticas y comportamientos personalizados. Hay plantillas Cookiecutter disponibles para ayudarle a comenzar rápidamente.
- Widgets y dashboards: Cree páginas de índice y vistas personalizadas usando
StatWidget,ChartWidget,TableWidgety más. - Diseño de formularios: Organice los formularios de creación/edición de forma lógica mediante filas, columnas, fieldsets y pestañas.
- Edición en línea: Edite un solo campo directamente desde la página de lista.
- Formularios en línea: Edite modelos relacionados dentro de un formulario principal usando
InlineModelView. - Otras mejoras: Mensajes flash, inicio de sesión OAuth, un backend para Tortoise ORM, nuevos campos (
ComputedField,SlugField,UUIDField,IPAddressField),validatorsa nivel de campo y funcionalidad de copiado al portapapeles en cualquier campo. - Logging: El paquete ahora registra internamente bajo el namespace
starlette_admin, silencioso por defecto. PaseAdmin(debug=True)o llame astarlette_admin.logging.configure_logging()para ver el enrutamiento de solicitudes, middleware y decisiones de permisos en la consola, lo cual resulta especialmente útil durante la migración. - Cobertura de pruebas ampliada: La suite de pruebas es ahora considerablemente más grande, e incluye pruebas end-to-end con Playwright que validan flujos críticos en toda la interfaz de administración.
- Paquete más ligero: El tamaño del paquete publicado en PyPI se ha reducido en aproximadamente un 50 %.
Requisitos
- Soporte de Python: Se requiere Python 3.11 o posterior. El soporte para Python 3.9 y 3.10 ha sido eliminado.
- Dependencias principales:
itsdangerouses ahora una dependencia principal utilizada para firmar las cookies del admin (tokens CSRF y mensajes flash). -
Nuevos extras opcionales:
Extra Habilita starlette-admin[email]Validación del lado del servidor de EmailFieldmedianteemail-validatorstarlette-admin[pdf]Exportación a PDF mediante reportlabstarlette-admin[s3]Almacenamiento de archivos en S3 mediante aiobotocorestarlette-admin[tinymce]Saneamiento de HTML de TinyMCEEditorFieldmediantenh3starlette-admin[i18n]Traducciones mediante babel(sin cambios) -
Backend Beanie: Se requiere Beanie 2.0 o posterior.
- Backend Odmantic: Eliminado. Si depende de él, permanezca en
starlette-admin<=0.17.1y demuestre su interés abriendo un issue; el soporte puede volver a añadirse si hay suficiente demanda.
El constructor de Admin
# Before
admin = Admin(engine, statics_dir="statics")
# After
admin = Admin(engine, static_dir="statics", secret_key=os.environ["ADMIN_SECRET_KEY"])
statics_dirha sido renombrado astatic_dir.- Establezca una
secret_key. Esta clave firma las cookies CSRF y de mensajes flash. Si se omite, se genera una clave aleatoria al arrancar (lo cual es aceptable para desarrollo). Sin embargo, los valores firmados quedarán invalidados en cada reinicio y entre múltiples workers. Pase siempre un secreto estable en producción. logo_url,login_logo_urlyfavicon_urlahora aceptan un callable(request) -> str | None. Esto reemplaza la personalización de marca por solicitud que antes proporcionabaAdminConfig.- Nuevos parámetros opcionales:
theme,plugins,additional_loaders,import_configyexport_config. - Particularidades de SQLAlchemy: El primer argumento ahora es
session_provider. Acepta unEngineoAsyncEngine, y ahora también acepta unsessionmakeroasync_sessionmaker. Las llamadas existentes aAdmin(engine)seguirán funcionando. timezone_configtiene como valor predeterminadoTimezoneConfig()en lugar deNone. Los datetimes ahora se muestran en la zona horaria local del usuario que los visualiza de forma predeterminada. Pasetimezone_config=Nonepara conservar los valores originales.
Identificadores de vista renombrados
La convención de nombres para las vistas ahora está unificada. Actualice los constructores y atributos de clase de sus ModelView en consecuencia:
| Antes | Después |
|---|---|
identity |
key |
name |
display_name |
label |
menu_label |
form_include_pk |
show_pk_in_forms |
# Before
admin.add_view(PostView(Post, identity="post", name="Post", label="Posts"))
# After
admin.add_view(PostView(Post, key="post", display_name="Post", menu_label="Posts"))
Tenga en cuenta que Link y DropDown también usan menu_label en lugar de label.
Eliminación de DataTables
La página de lista ya no utiliza DataTables. Los atributos que anteriormente lo configuraban han sido eliminados por completo:
| Eliminado | Reemplazo |
|---|---|
datatables_options |
Ninguno. La tabla se renderiza en el servidor. Personalícela mediante plantillas. |
search_builder |
El nuevo constructor de filtros, habilitado por searchable_fields. |
responsive_table |
Ninguno. La tabla gestiona el desbordamiento de forma nativa. |
save_state |
Siempre activo. El estado de la lista (página, ordenación, filtros, búsqueda, columnas visibles) ahora reside en la URL. |
BaseField.search_builder_type |
BaseField.filters (una lista de clases de filtro). |
BaseField.render_function_key |
BaseField.list_template (plantilla Jinja del lado del servidor). |
Si previamente escribió funciones de renderizado en JavaScript personalizadas o plugins de DataTables, trasládelos a overrides de list_template. Cada campo ahora renderiza su celda de lista directamente desde templates/fields/list/*.html.
Actions
Los manejadores de acciones por lotes ahora reciben un objeto ActionSelection en lugar de una lista de claves primarias. Esto da soporte al nuevo banner de «seleccionar todas las coincidencias», que afecta a cada fila que coincide con el filtro actual sin materializarlas en el lado del cliente.
# Before
@action(name="publish", text="Publish")
async def publish_action(self, request: Request, pks: List[Any]) -> str:
for article in await self.find_by_pks(request, pks):
...
return f"{len(pks)} articles were published"
# After
@action(name="publish", text="Publish")
async def publish_action(self, request: Request, selection: ActionSelection) -> None:
for article in await selection.rows():
...
flash(request, f"{await selection.count()} articles were published")
- Métodos como
selection.rows(),selection.pks()yselection.count()resuelven las filas objetivo de forma diferida (lazy). Esto aplica tanto si el usuario marcó filas individualmente como si seleccionó todas las coincidentes. - Propiedades como
selection.is_select_all,selection.filtersyselection.qle permiten delegar la operación como una única consulta masiva. - Devolver un string de mensaje de éxito se sustituye por los mensajes flash.
- Los manejadores de acciones por fila conservan su firma original
(request, pk). - Nuevas opciones de
@action:header,allow_empty_selection,dedicated_button,modal_sizey callablesformpor solicitud.
Autenticación
El módulo starlette_admin/auth.py es ahora el paquete starlette_admin.auth. Las importaciones existentes desde starlette_admin.auth seguirán funcionando, pero el contrato del provider ha cambiado.
# Before
class MyAuthProvider(AuthProvider):
async def login(self, username, password, remember_me, request, response):
request.session.update({"username": username})
return response
async def logout(self, request, response):
request.session.clear()
return response
async def is_authenticated(self, request) -> bool:
request.state.user = my_users_db.get(request.session.get("username"))
return request.state.user is not None
def get_admin_user(self, request) -> AdminUser:
return AdminUser(username=request.state.user["name"])
def get_admin_config(self, request) -> AdminConfig:
return AdminConfig(app_title="My Admin")
# After
class MyAuthProvider(AuthProvider):
async def login(self, username, password, remember_me, request):
if username in my_users_db:
request.session.update({"username": username})
return None # default redirect (`next` param or admin index)
raise LoginFailed("Invalid username or password")
async def logout(self, request):
request.session.clear()
async def authenticate(self, request) -> AdminUser | None:
user = my_users_db.get(request.session.get("username"))
return AdminUser(username=user["name"]) if user else None
- Los métodos
is_authenticated,get_admin_useryget_admin_configse fusionan en un único métodoauthenticate(request) -> AdminUser | None. DevolverNoneindica un estado no autenticado. - Los métodos
loginylogoutya no reciben ni devuelven el objetoresponsepreparado. DevuelvaNonepara la redirección predeterminada, o devuelva unResponsepersonalizado para modificar este comportamiento. AdminConfigha sido eliminado. Gestione títulos y logos por solicitud usando la forma callable delogo_urlylogin_logo_urlen la instancia deAdmin.- Un
OAuthProviderintegrado gestiona los flujos de inicio de sesión OAuth2/OIDC de forma inmediata. - El decorator
login_not_requiredpermanece sin cambios.
Exportación e importación
Las exportaciones se han trasladado de los botones del lado del cliente de DataTables a endpoints de streaming del lado del servidor. La funcionalidad de importación es totalmente nueva y ExportType ya no existe.
# Before
from starlette_admin import ExportType
class PostView(ModelView):
export_types = [ExportType.CSV, ExportType.EXCEL]
export_fields = ["id", "title"]
# After
class PostView(ModelView):
exporters = ["csv", "xlsx"]
importers = ["csv", "json"]
exclude_fields_from_export = ["content"]
exclude_fields_from_import = ["id"]
export_typespasa a serexporters. Acepta una lista de nombres de formato o instancias deBaseExporter. Los built-in compatibles incluyencsv,json,tsv,xlsx,ods,html,yamlypdf. Los formatos distintos decsvojsonrequierentablib, y PDF requiere el extrapdf.importersacepta una lista de nombres de formato o instancias deBaseImporter. Los built-in compatibles incluyencsv,tsv,json,yaml,xlsx,xls,ods,dbfyhtml. Los formatos distintos decsv,tsvojsonrequierentablib.export_fields(una lista de inclusión) se sustituye porexclude_fields_from_export(una lista de exclusión). Esto sigue la convención de nomenclatura de los demás atributosexclude_fields_from_*.- Los campos también aceptan
exclude_from_exportyexclude_from_importde forma individual. - Configure límites globales usando
ExportConfigyImportConfigen la instancia deAdmin. Consulte la documentación de Exportación e importación para más detalles.
Campos personalizados y overrides de plantillas
Las plantillas de campos se han reorganizado. Actualice sus rutas si hace override de las plantillas integradas o distribuye campos personalizados:
| Antes | Después |
|---|---|
templates/displays/*.html |
templates/fields/detail/*.html |
templates/forms/*.html |
templates/fields/form/*.html |
| (función de renderizado del lado del cliente) | templates/fields/list/*.html |
BaseField.display_template |
BaseField.detail_template |
BaseField.form_template (ruta) |
Mismo nombre de atributo, nuevo prefijo de ruta fields/form/ |
# Before
@dataclass
class RatingField(BaseField):
display_template: str = "displays/rating.html"
form_template: str = "forms/rating.html"
render_function_key: str = "rating"
# After
@dataclass
class RatingField(BaseField):
detail_template: str = "fields/detail/rating.html"
form_template: str = "fields/form/rating.html"
list_template: str = "fields/list/rating.html"
Entre las nuevas capacidades por campo que puede explorar se incluyen validators, filters, default, hooks (getter, formatter, parser), copy_to_clipboard y un diccionario extra para metadatos arbitrarios. Revise la documentación de Campos personalizados para obtener más información.
CustomView
La clase CustomView ya no acepta template_path ni methods. Cree páginas sencillas usando widgets. Para páginas que requieran control total, herede de CustomView y declare sus rutas directamente.
# Before
admin.add_view(CustomView(label="Home", path="/home", template_path="home.html"))
# After: widget-based page
admin.add_view(
CustomView(
menu_label="System Status",
path="/status",
widget=StatWidget(title="Pending jobs", value_callback=count_pending_jobs),
)
)
# After: full control
class HomeView(CustomView):
menu_label = "Home"
path = "/home"
@route("")
async def index(self, request: Request) -> Response:
return self.templates.TemplateResponse(request=request, name="home.html")
El decorator @route también permite que cualquier view exponga endpoints adicionales para necesidades como datos JSON de gráficos o webhooks.
Backends personalizados
Si implementó BaseModelView sobre una fuente de datos personalizada, tenga en cuenta el contrato de acceso a datos actualizado:
# Before
async def find_all(self, request, skip=0, limit=100, where=None, order_by=None): ...
async def count(self, request, where=None): ...
# After
async def find_all(
self, request, skip=0, limit=100, q=None, sorts=None, filters=None
): ...
async def count(self, request, q=None, filters=None): ...
- El parámetro
wherede tipo string se divide enq(para términos de búsqueda de texto completo) yfilters(un árbol tipado deFilterGroupproporcionado por el constructor de filtros). - El parámetro
order_by(antes una lista de strings"field direction") es ahorasorts, que toma una lista de tuplas(field_name, direction). - Cada backend incluye ahora un registro de filtros que asigna tipos de campo a implementaciones de filtros. Consulte la documentación de Backend personalizado para conocer el contrato completo y un ejemplo funcional.
Cambios de comportamiento a revisar
- Zonas horarias: Los datetimes se renderizan en la zona horaria local de quien los visualiza de forma predeterminada (consulte la nota sobre
timezone_configen la sección Constructor de Admin). - Estado en la URL: El estado de la lista ahora reside en la URL. Las URLs del admin guardadas como marcadores desde versiones anteriores mostrarán estados de lista predeterminados, porque los estados guardados de DataTables no se migran.
- Validación de correo electrónico:
EmailFieldahora valida en el servidor cuandoemail-validatorestá instalado. - Protección CSRF: La protección CSRF está integrada y basada en cookies. Si previamente envolvió el admin con un middleware CSRF personalizado, puede eliminarlo con seguridad. Asegúrese de que su
secret_keyesté configurada para que los tokens sobrevivan a los reinicios del servidor. - Tamaño de subida de FileField:
FileField.max_sizeahora tiene como valor predeterminado 50 MB en lugar de ilimitado. Pasemax_size=Nonepara restaurar el comportamiento anterior sin límites, o establezca un valor explícito para cambiar el límite.
Eliminado sin reemplazo
AdminConfig(consulte Autenticación).datatables_options,responsive_tableysave_state(consulte Eliminación de DataTables).- El backend Odmantic (consulte Requisitos).
Cómo obtener ayuda
Si encuentra un problema de migración no cubierto en esta guía, por favor abra un issue. Incluya una reproducción mínima del problema e indique la versión desde la que está actualizando. Ejecutar con Admin(debug=True) suele revelar la causa directamente, y los logs resultantes constituyen un excelente complemento para su reporte.