The basic workflow of Django’s admin is, in a nutshell, «select an object, then change it.» This works well for a mayoría de casos de uso. Sin embargo, si necesitas hacer el mismo cambio en muchos objetos al mismo tiempo, este flujo de trabajo puede ser bastante tedioso.
En estos casos, la administración de Django te permite escribir y registrar «acciones» – funciones que se llaman con una lista de objetos seleccionados en la página de lista de cambios.
Si miras cualquier lista de cambios en la administración, verás esta característica en acción; Django viene con una acción «eliminar objetos seleccionados» disponible para todos los modelos. Por ejemplo, aquí está el módulo de usuario desde la aplicación django.contrib.auth integrada de Django:
Advertencia
La acción «eliminar objetos seleccionados» utiliza QuerySet.delete() por razones de eficiencia, lo que tiene una importante advertencia: el método delete() de tu modelo no se llamará.
Si deseas sobreescribir este comportamiento, puedes sobreescribir ModelAdmin.delete_queryset() o escribir una acción personalizada que realice la eliminación de manera preferida – por ejemplo, llamando a Model.delete() para cada uno de los elementos seleccionados.
Para obtener más información sobre la eliminación en masa, consulta la documentación sobre eliminación de objetos.
Sigue leyendo para saber cómo agregar tus propias acciones a esta lista.
La forma más fácil de explicar las acciones es por ejemplo, así que vamos a sumergirnos en ello.
Un uso común de la administración de acciones es el actualización en masa de un modelo. Imagina una aplicación de noticias con un modelo Article:
from django.db import models
STATUS_CHOICES = {
"d": "Draft",
"p": "Published",
"w": "Withdrawn",
}
class Article(models.Model):
title = models.CharField(max_length=100)
body = models.TextField()
status = models.CharField(max_length=1, choices=STATUS_CHOICES)
def __str__(self):
return self.title
Una tarea común que podríamos realizar con un modelo como este es actualizar el estado de un artículo desde «borrador» a «publicado». Podríamos hacer esto fácilmente en la administración uno a la vez, pero si queríamos publicar en masa un grupo de artículos, sería tedioso. Así que, escribamos una acción que nos permita cambiar el estado de un artículo a «publicado».
Primero, necesitaremos escribir una función que se llame cuando la acción se active desde la administración. Las funciones de acción son funciones regulares que toman tres argumentos:
El ModelAdmin actual
Un objeto HttpRequest que representa la solicitud actual,
Un conjunto de objetos QuerySet seleccionados por el usuario.
Nuestra función para publicar estos artículos no necesitará el ModelAdmin o el objeto de solicitud, pero sí utilizaremos el conjunto de objetos:
def make_published(modeladmin, request, queryset):
queryset.update(status="p")
Nota
Para la mejor rendimiento, estamos utilizando el método update del conjunto de objetos. Otros tipos de acciones podrían necesitar manejar cada objeto individualmente; en estos casos iteraríamos sobre el conjunto de objetos:
for obj in queryset:
do_something_with(obj)
Eso es todo lo que hay que hacer para escribir una acción! Sin embargo, tomaremos un paso adicional y le daremos a la acción un «título amigable» en la administración. Por defecto, esta acción aparecería en la lista de acciones como «Hacer publicado» – el nombre de la función, con los guiones reemplazados por espacios. Eso está bien, pero podemos proporcionar un mejor título más humano-friendly usando el decorador action() sobre la función make_published:
from django.contrib import admin
...
@admin.action(description="Mark selected stories as published")
def make_published(modeladmin, request, queryset):
queryset.update(status="p")
Nota
Esto podría parecer familiar; la administración utiliza una técnica similar con el decorador display() para proporcionar descripciones legibles por humanos para las funciones de llamada registradas en la opción list_display.
A continuación, necesitaremos informar a nuestra ModelAdmin sobre la acción. Esto funciona exactamente igual que cualquier otra opción de configuración. Por lo tanto, el archivo admin.py completo con la acción y su registro sería algo así:
from django.contrib import admin
from myapp.models import Article
@admin.action(description="Mark selected stories as published")
def make_published(modeladmin, request, queryset):
queryset.update(status="p")
class ArticleAdmin(admin.ModelAdmin):
list_display = ["title", "status"]
ordering = ["title"]
actions = [make_published]
admin.site.register(Article, ArticleAdmin)
Ese código nos dará una lista de cambio administrativa que se vería algo así:
Eso es todo lo que hay que hacer. Si tienes ganas de escribir tus propias acciones, ahora sabes suficiente para empezar. El resto de este documento cubre técnicas más avanzadas.
Si existen condiciones de error previsibles que pueden ocurrir mientras se ejecuta la acción, debes informar amablemente al usuario sobre el problema. Esto significa manejar excepciones y utilizar django.contrib.admin.ModelAdmin.message_user() para mostrar una descripción amigable del usuario en la respuesta.
Hay un par de opciones adicionales y posibilidades que puedes explotar para opciones más avanzadas.
ModelAdmin¶El ejemplo anterior muestra la acción make_published definida como una función. Eso está bien, pero no es perfecto desde un punto de vista de diseño del código: ya que la acción está estrechamente acoplada al objeto Article, tiene sentido conectar la acción a el objeto ArticleAdmin mismo.
Puedes hacerlo de esta manera:
class ArticleAdmin(admin.ModelAdmin):
...
actions = ["make_published"]
@admin.action(description="Mark selected stories as published")
def make_published(self, request, queryset):
queryset.update(status="p")
Definir acciones como métodos da a la acción acceso más idiomático al ModelAdmin mismo, permitiendo a la acción llamar a cualquier de los métodos proporcionados por el administrador.
Por ejemplo, podemos usar self para hacer que se flash un mensaje al usuario informándoles de que la acción fue exitosa:
Esto hace que la acción coincida con lo que hace el propio administrador después de realizar con éxito una acción:
from django.contrib import messages
from django.utils.translation import ngettext
class ArticleAdmin(admin.ModelAdmin):
...
def make_published(self, request, queryset):
updated = queryset.update(status="p")
self.message_user(
request,
ngettext(
"%d story was successfully marked as published.",
"%d stories were successfully marked as published.",
updated,
)
% updated,
messages.SUCCESS,
)
Acciones que proporcionan páginas intermedias
Para proporcionar una página intermedia, devuelve un HttpResponse (o subclase) desde tu acción. Por ejemplo, podrías escribir una función de exportación que utiliza las funciones de serialización de Django (funciones de serialización ) para dump algunos objetos seleccionados como JSON:
En general, algo como lo anterior no se considera una gran idea. La mayoría del tiempo, la mejor práctica será devolver un HttpResponseRedirect y redirigir al usuario a una vista que has escrito, pasando la lista de objetos seleccionados en la cadena de consulta GET. Esto permite proporcionar lógica de interacción compleja en las páginas intermedias. Por ejemplo, si deseabas proporcionar una función de exportación más completa, querrías permitir al usuario elegir un formato y posiblemente una lista de campos para incluir en el exportación. La mejor opción sería escribir una acción pequeña que redirija a tu vista de exportación personalizada:
from django.core import serializers
from django.http import HttpResponse
def export_as_json(modeladmin, request, queryset):
response = HttpResponse(content_type="application/json")
serializers.serialize("json", queryset, stream=response)
return response
Como puedes ver, la acción es bastante corta; toda la lógica compleja pertenecería a tu vista de exportación. Esto tendría que manejar objetos de cualquier tipo, por lo que el asunto con ContentType.
from django.contrib.contenttypes.models import ContentType
from django.http import HttpResponseRedirect
def export_selected_objects(modeladmin, request, queryset):
selected = queryset.values_list("pk", flat=True)
ct = ContentType.objects.get_for_model(queryset.model)
return HttpResponseRedirect(
"/export/?ct=%s&ids=%s"
% (
ct.pk,
",".join(str(pk) for pk in selected),
)
)
As you can see, the action is rather short; all the complex logic would belong
in your export view. This would need to deal with objects of any type, hence
the business with the ContentType.
Escribir esta vista se deja como ejercicio para el lector.
Algunas acciones son mejores si se les hace disponibles para cualquier objeto en el sitio administrativo - la acción de exportación definida anteriormente sería un buen candidato. Puedes hacer que una acción esté disponible globalmente utilizando AdminSite.add_action(). Por ejemplo:
from django.contrib import admin
admin.site.add_action(export_selected_objects)
Hace que la acción export_selected_objects esté disponible globalmente como una acción llamada «export_selected_objects». Puedes darle explícitamente un nombre a la acción — lo cual es útil si más adelante deseas eliminarla programáticamente desactivando acciones administrativas — pasando un segundo argumento a AdminSite.add_action().
admin.site.add_action(export_selected_objects, "export_selected")
A veces necesitas deshabilitar ciertas acciones, especialmente aquellas registradas de manera global en el sitio , para objetos específicos. Hay varias formas de deshabilitar acciones:
Si necesitas deshabilitar una acción de sitio completo (sitio-widesite) puedes llamar a AdminSite.desactiva_acción() .
Ejemplo de uso de esta función para eliminar la acción integrada «eliminar objetos seleccionados»:
admin.site.disable_action("delete_selected")
Una vez que hayas realizado lo anterior, esa acción ya no estará disponible en el sitio.
Si, sin embargo, necesitas reactivar una acción globalmente deshabilitada para un modelo particular, enuméralo explícitamente en tu lista ModelAdmin.actions:
# Globally disable delete selected
admin.site.disable_action("delete_selected")
# This ModelAdmin will not have delete_selected available
class SomeModelAdmin(admin.ModelAdmin):
actions = ["some_other_action"]
...
# This one will
class AnotherModelAdmin(admin.ModelAdmin):
actions = ["delete_selected", "a_third_action"]
...
ModelAdmin particular¶Si deseas que no estén disponibles ninguna acción de masa para un ModelAdmin determinado, establece la propiedad ModelAdmin.actions en None:
class MyModelAdmin(admin.ModelAdmin):
actions = None
Esto le dice al ModelAdmin que no muestre ni permita ninguna acción, incluidas cualquier acción sitio.
Finalmente, puedes habilitar o deshabilitar acciones de manera condicional en una base por solicitud (y por lo tanto por usuario) sobrescribiendo el método ModelAdmin.get_actions().
Esto devuelve un diccionario de acciones permitidas. Las claves son nombres de acción, y los valores son tuplas de la forma (function, name, short_description).
Por ejemplo, si solo deseas que los usuarios cuyos nombres comiencen con “J” puedan eliminar objetos en masa:
class MyModelAdmin(admin.ModelAdmin):
...
def get_actions(self, request):
actions = super().get_actions(request)
if request.user.username[0].upper() != "J":
if "delete_selected" in actions:
del actions["delete_selected"]
return actions
Las acciones pueden limitar su disponibilidad a usuarios con permisos específicos al envolver la función de acción con el decorador action() y pasando el argumento permissions:
@admin.action(permissions=["change"])
def make_published(modeladmin, request, queryset):
queryset.update(status="p")
La traducción de los textos es la siguiente:
Si permissions tiene más de una permiso, la acción estará disponible siempre y cuando el usuario pase al menos uno de las comprobaciones.
Los valores disponibles para permissions y los correspondientes métodos de comprobación son:
'change': ModelAdmin.has_change_permission()
'delete': ModelAdmin.has_delete_permission()
'view': ModelAdmin.has_view_permission()
Puedes especificar cualquier otro valor siempre y cuando implementes un método correspondiente has_<value>_permission(self, request) en el ModelAdmin.
Por ejemplo:
from django.contrib import admin
from django.contrib.auth import get_permission_codename
class ArticleAdmin(admin.ModelAdmin):
actions = ["make_published"]
@admin.action(permissions=["publish"])
def make_published(self, request, queryset):
queryset.update(status="p")
def has_publish_permission(self, request):
"""Does the user have the publish permission?"""
opts = self.opts
codename = get_permission_codename("publish", opts)
return request.user.has_perm("%s.%s" % (opts.app_label, codename))
action¶Este decorador se puede utilizar para establecer atributos específicos en funciones de acción personalizadas que pueden usarse con :attr:`~django.contrib.admin.ModelAdmin.actions`.
@admin.action(
permissions=["publish"],
description="Mark selected stories as published",
)
def make_published(self, request, queryset):
queryset.update(status="p")
Esta es equivalente a establecer algunas atributos (con los nombres originales y más largos) directamente en la función:
def make_published(self, request, queryset):
queryset.update(status="p")
make_published.allowed_permissions = ["publish"]
make_published.short_description = "Mark selected stories as published"
El uso de este decorador no es obligatorio para hacer una función de acción, pero puede ser útil utilizarlo sin argumentos como un marcador en tu código para identificar el propósito de la función:
@admin.action
def make_inactive(self, request, queryset):
queryset.update(is_active=False)
En este caso, no agregará atributos a la función.
Las descripciones de acciones están formateadas con el símbolo “%” y pueden contener espacios reservados '%(verbose_name)s' y '%(verbose_name_plural)s', que se reemplazan, respectivamente, por los nombres verbales del modelo verbose_name y verbose_name_plural.
may 31, 2026