# Django 6.0.7 documentation

# Administrativa åtgärder

Det grundläggande arbetsflödet i Djangos admin är, i ett nötskal, ”välj ett objekt och ändra det sedan” Detta fungerar bra för en majoritet av användningsfallen. Men om du behöver göra samma ändring på många objekt samtidigt kan detta arbetsflöde vara ganska tråkigt.

I dessa fall låter Djangos admin dig skriva och registrera ”åtgärder” - funktioner som anropas med en lista över objekt som valts på sidan med ändringslistan.

Om du tittar på någon ändringslista i administratören ser du den här funktionen i aktion; Django levereras med en åtgärd ”ta bort valda objekt” som är tillgänglig för alla modeller. Till exempel:, här är användarmodulen från Djangos inbyggda `django.contrib.auth` app:

Varning

Åtgärden ”ta bort valda objekt” använder `QuerySet.delete()` av effektivitetsskäl, vilket har en viktig varning: din modells metod `delete()` kommer inte att anropas.

Om du vill åsidosätta detta beteende kan du åsidosätta `ModelAdmin.delete_queryset()` eller skriva en anpassad åtgärd som gör borttagningen på det sätt du föredrar - till exempel genom att anropa `Model.delete()` för vart och ett av de valda objekten.

Mer information om bulkdeletion finns i dokumentationen om object deletion.

Läs vidare för att ta reda på hur du lägger till dina egna åtgärder i listan.

## Skriva åtgärder

Det enklaste sättet att förklara åtgärder är genom exempel, så låt oss dyka ner i det.

Ett vanligt användningsfall för adminåtgärder är massuppdatering av en modell. Föreställ dig en nyhetsapplikation med en `Artikel`-modell:

    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

En vanlig uppgift som vi kan utföra med en sådan här modell är att uppdatera en artikels status från ”utkast” till ”publicerad”. Vi kan enkelt göra detta i administratören för en artikel i taget, men om vi vill masspublicera en grupp artiklar skulle det vara tråkigt. Så låt oss skriva en åtgärd som låter oss ändra en artikels status till ”publicerad”

### Skriva handlingsfunktioner

Först måste vi skriva en funktion som anropas när åtgärden utlöses från administratören. Åtgärdsfunktioner är vanliga funktioner som tar tre argument:

- Den aktuella `ModelAdmin`

- En `HttpRequest` som representerar den aktuella begäran,

- En `QuerySet` som innehåller den uppsättning objekt som användaren har valt.

Vår funktion publish-these-articles kommer inte att behöva `ModelAdmin` eller request-objektet, men vi kommer att använda queryset:

    def make_published(modeladmin, request, queryset):
        queryset.update(status="p")

Observera

För bästa prestanda använder vi querysets uppdateringsmetod. Andra typer av åtgärder kan behöva hantera varje objekt individuellt; i dessa fall skulle vi iterera över queryset:

    for obj in queryset:
        do_something_with(obj)

Det är faktiskt allt som krävs för att skriva en åtgärd! Vi ska dock ta ytterligare ett valfritt men användbart steg och ge åtgärden en ”fin” titel i admin. Som standard visas den här åtgärden i åtgärdslistan som ”Gör publicerad” - funktionsnamnet, med understreck ersatta av mellanslag. Det är bra, men vi kan ge ett bättre, mer människovänligt namn genom att använda `action()`-dekoratorn på `make_published`-funktionen:

    from django.contrib import admin

    ...

    @admin.action(description="Mark selected stories as published")
    def make_published(modeladmin, request, queryset):
        queryset.update(status="p")

Observera

Detta kanske ser bekant ut; admins `list_display`-alternativ använder en liknande teknik med `display()`-dekoratorn för att tillhandahålla mänskligt läsbara beskrivningar för återuppringningsfunktioner som registreras där också.

### Lägga till åtgärder till `ModelAdmin`

Därefter måste vi informera vår `ModelAdmin` om åtgärden. Detta fungerar precis som alla andra konfigurationsalternativ. Så, den kompletta `admin.py` med åtgärden och dess registrering skulle se ut så här:

    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)

Den koden kommer att ge oss en ändringslista för administratörer som ser ut ungefär så här:

Det är verkligen allt som behövs! Om du är sugen på att skriva dina egna åtgärder vet du nu tillräckligt för att komma igång. Resten av det här dokumentet handlar om mer avancerade tekniker.

### Hantering av fel i åtgärder

Om det finns förutsebara felförhållanden som kan uppstå när du kör din åtgärd, bör du på ett elegant sätt informera användaren om problemet. Detta innebär att hantera undantag och använda `django.contrib.admin.ModelAdmin.message_user()` för att visa en användarvänlig beskrivning av problemet i svaret.

## Avancerade handlingstekniker

Det finns ett par extra alternativ och möjligheter som du kan utnyttja för mer avancerade alternativ.

### Åtgärder som `ModelAdmin`-metoder

I exemplet ovan är åtgärden `make_published` definierad som en funktion. Det är helt okej, men det är inte perfekt ur en koddesignsynpunkt: eftersom åtgärden är tätt kopplad till objektet `Article` är det vettigt att koppla åtgärden till själva objektet `ArticleAdmin`.

Du kan göra det så här:

    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")

Lägg först märke till att vi har flyttat `make_published` till en metod och bytt namn på parametern `modeladmin` till `self`, och sedan att vi nu har lagt strängen `'make_published` i `actions` istället för en direkt funktionsreferens. Detta säger till `ModelAdmin` att leta upp åtgärden som en metod.

Genom att definiera åtgärder som metoder får åtgärden en mer idiomatisk tillgång till själva `ModelAdmin`, vilket gör att åtgärden kan anropa vilken som helst av de metoder som tillhandahålls av administratören.

Vi kan t.ex. använda `self` för att skicka ett meddelande till användaren om att åtgärden var lyckad:

    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,
            )

This makes the action match what the admin itself does after successfully performing an action:

### Åtgärder som ger mellanliggande sidor

Som standard omdirigeras användaren tillbaka till den ursprungliga sidan i ändringslistan efter att en åtgärd har utförts. Vissa åtgärder, särskilt mer komplexa sådana, måste dock returnera mellanliggande sidor. Till exempel: ber den inbyggda åtgärden delete om bekräftelse innan de valda objekten raderas.

För att tillhandahålla en mellanliggande sida, returnera en `HttpResponse` (eller underklass) från din åtgärd. Du kan till exempel skriva en exportfunktion som använder Djangos serialiseringsfunktioner för att dumpa några utvalda objekt som JSON:

    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

Generellt sett anses något som ovanstående inte vara en bra idé. För det mesta är den bästa metoden att returnera en `HttpResponseRedirect` och omdirigera användaren till en vy som du har skrivit och skicka listan över valda objekt i GET-frågesträngen. Detta gör att du kan tillhandahålla komplex interaktionslogik på de mellanliggande sidorna. Om du till exempel vill tillhandahålla en mer komplett exportfunktion skulle du vilja låta användaren välja ett format och eventuellt en lista över fält som ska ingå i exporten. Det bästa du kan göra är att skriva en liten åtgärd som omdirigerar till din anpassade exportvy:

    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),
            )
        )

Som du kan se är åtgärden ganska kort; all komplex logik hör hemma i din exportvy. Denna skulle behöva hantera objekt av alla typer, därav verksamheten med `ContentType`.

Att skriva denna vy lämnas som en övning till läsaren.

### Göra åtgärder tillgängliga för hela webbplatsen

AdminSite.add_action(action, name=None)

  Some actions are best if they’re made available to any object in the admin site – the export action defined above would be a good candidate. You can make an action globally available using `AdminSite.add_action()`. For example:

      from django.contrib import admin

      admin.site.add_action(export_selected_objects)

  This makes the `export_selected_objects` action globally available as an action named ”export_selected_objects”. You can explicitly give the action a name – good if you later want to programmatically remove the action – by passing a second argument to `AdminSite.add_action()`:

      admin.site.add_action(export_selected_objects, "export_selected")

### Inaktivera åtgärder

Ibland behöver du inaktivera vissa åtgärder - särskilt de som registered site-wide - för vissa objekt. Det finns några olika sätt att inaktivera åtgärder:

#### Inaktivera en webbplatsomfattande åtgärd

AdminSite.disable_action(name)

  If you need to disable a site-wide action you can call `AdminSite.disable_action()`.

  Du kan t.ex. använda den här metoden för att ta bort den inbyggda åtgärden ”ta bort markerade objekt”:

      admin.site.disable_action("delete_selected")

  När du har gjort ovanstående kommer den åtgärden inte längre att vara tillgänglig på hela webbplatsen.

  Om du däremot behöver återaktivera en globalt inaktiverad åtgärd för en viss modell, listar du den uttryckligen i listan `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"]
          ...

#### Inaktivera alla åtgärder för en viss `ModelAdmin`

Om du vill ha inga bulkåtgärder tillgängliga för en viss `ModelAdmin`, sätt `ModelAdmin.actions` till `None`:

    class MyModelAdmin(admin.ModelAdmin):
        actions = None

Detta säger till `ModelAdmin` att inte visa eller tillåta några åtgärder, inklusive alla site-wide actions.

#### Villkorlig aktivering eller inaktivering av åtgärder

ModelAdmin.get_actions(request, action_location=ActionLocation.CHANGE_LIST)

  Slutligen kan du villkorligt aktivera eller inaktivera åtgärder per begäran (och därmed per användare) genom att åsidosätta `ModelAdmin.get_actions()`.

  This returns a dictionary of actions allowed for the specific `action_location`. The keys are action names, and the values are `Action` objects.

  Om du t.ex. bara vill att användare vars namn börjar med ”J” ska kunna radera objekt i bulk:

      class MyModelAdmin(admin.ModelAdmin):
          ...

          def get_actions(self, request, action_location=ActionLocation.CHANGE_LIST):
              actions = super().get_actions(request, action_location=action_location)
              if request.user.username[0].upper() != "J":
                  if "delete_selected" in actions:
                      del actions["delete_selected"]
              return actions

  Changed in Django 6.1:

  The keyword argument `action_location` was added. The return type was changed to a dictionary where the keys are action names and the values are `Action` objects, previously the values were `(function, name, description)` tuples.

### Ange behörigheter för åtgärder

Åtgärder kan begränsa sin tillgänglighet till användare med specifika behörigheter genom att omsluta åtgärdsfunktionen med `action()`-dekoratorn och skicka argumentet `permissions`:

    @admin.action(permissions=["change"])
    def make_published(modeladmin, request, queryset):
        queryset.update(status="p")

Åtgärden `make_published()` kommer endast att vara tillgänglig för användare som klarar `ModelAdmin.has_change_permission()`-kontrollen.

Om `permissions` har mer än en behörighet kommer åtgärden att vara tillgänglig så länge som användaren klarar minst en av kontrollerna.

Tillgängliga värden för `permissions` och motsvarande metodkontroller är:

- `'add'`: `ModelAdmin.has_add_permission()`

- `'change'`: `ModelAdmin.has_change_permission()`

- `'delete'`: `ModelAdmin.has_delete_permission()`

- `'view'`: `ModelAdmin.has_view_permission()`

Du kan ange vilket annat värde som helst så länge du implementerar en motsvarande `has_<value>_permission(self, request)`-metod på `ModelAdmin`.

Till exempel:

    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))

#### Controlling where actions are available

New in Django 6.1.

By default, admin actions are available on the change list page only. You can control where an action appears using the `location` argument of the `@admin.action` decorator.

For example, to make an action available only on the change form, set `location` to `ActionLocation.CHANGE_FORM`:

    from django.contrib import admin
    from django.contrib.admin import ActionLocation

    @admin.action(location=ActionLocation.CHANGE_FORM)
    def make_published(modeladmin, request, queryset): ...

To make an action available on both the change list and the change form:

    @admin.action(
        location=[ActionLocation.CHANGE_FORM, ActionLocation.CHANGE_LIST],
        description="Publish",
        description_plural="Mark selected stories as published",
    )
    def make_published(modeladmin, request, queryset): ...

Notice that `description` and `description_plural` were provided. These are optional but the admin action will be labeled by `description` in the admin change form and `description_plural` in the admin change list.

You can customize how actions are rendered by overriding admin templates. The change list page uses `admin/actions.html` and the change form page uses `admin/change_form_actions.html`. Note that the change form template inherits from the change list actions template.

## Dekoratorn ”action

action(*, permissions=None, description=None, description_plural=None, location=ActionLocation.CHANGE_LIST)

  Denna dekorator kan användas för att ställa in specifika attribut på anpassade åtgärdsfunktioner som kan användas med `actions`:

      @admin.action(
          permissions=["publish"],
          description="Mark selected stories as published",
      )
      def make_published(self, request, queryset):
          queryset.update(status="p")

  Detta motsvarar att ange vissa attribut (med de ursprungliga, längre namnen) på funktionen direkt:

      def make_published(self, request, queryset):
          queryset.update(status="p")

      make_published.allowed_permissions = ["publish"]
      make_published.short_description = "Mark selected stories as published"

  Det är inte obligatoriskt att använda denna dekorator för att skapa en actionfunktion, men det kan vara användbart att använda den utan argument som en markör i källan för att identifiera syftet med funktionen:

      @admin.action
      def make_inactive(self, request, queryset):
          queryset.update(is_active=False)

  I detta fall kommer det inte att lägga till några attribut till funktionen.

  Parametrar:

    - permissions – A list of permission codenames that restrict the action to users who have at least one of the defined permissions. This sets the `allowed_permissions` attribute on the function. See Ange behörigheter för åtgärder for details.

    - description – A human-readable description of the action to be rendered in the admin. If `description` is not provided, Django renders the function’s name, converting underscores to spaces and capitalizing the first letter of the first word. This sets the `short_description` attribute on the function.

    - description_plural – A human-readable description of the action used in contexts where plural wording is required, such as on the admin change list. If `description_plural` is not provided, falls back to `description`. This sets the `plural_description` attribute on the function.

    - location – Specifies where the action is available. Accepts either a single `ActionLocation` value or an iterable of values. If omitted, the action is only available on the admin change list. See Controlling where actions are available for details.

  Action description `%`-formatting support

  Action descriptions support `%`-formatting and may include `'%(verbose_name)s'` and `'%(verbose_name_plural)s'` placeholders. These are replaced with the model’s `verbose_name` and `verbose_name_plural`.

  Changed in Django 6.1:

  The keyword arguments `description_plural` and `location` were added.

## `ActionLocation`

New in Django 6.1.

class ActionLocation

  Enum of allowed values for the `location` parameter of the `action()` decorator.

  CHANGE_FORM

    The action is available on the admin change form. When an action is run, any unsaved changes on the admin change form will be lost.

  CHANGE_LIST

    The action is available on the admin change list.

## `Action`

New in Django 6.1.

class Action

  Represents an action. Actions should be defined using the `action()` decorator.

  func

    The action function. See Skriva handlingsfunktioner for details.

  name

    The action function name.

  description

    A human-readable description of the action to be rendered in the admin.

  plural_description

    A human-readable description of the action used in contexts where plural wording is required.

  locations

    A list of `ActionLocation` values the admin action can be rendered.