Python でプログラミング: Django ModelAdmin actions の詳細解説


Django の django.contrib.admin モジュールには、ModelAdmin クラスと呼ばれる強力なツールが含まれています。このクラスは、管理サイトでモデルを管理するためのさまざまな機能を提供します。その中でも、actions は、選択された複数のオブジェクトに対して一括処理を実行できる機能です。

仕組み

actions は、ModelAdmin クラスの属性として定義されます。この属性には、アクション関数と呼ばれる関数をリストで登録します。アクション関数は、選択されたオブジェクトのリストと、現在のリクエストオブジェクトを受け取ります。アクション関数内で、これらのオブジェクトに対して必要な処理を実行できます。

以下は、BlogPost モデルに対して "公開" と "非公開" のアクションを定義する例です。

from django.contrib import admin
from .models import BlogPost

class BlogPostAdmin(admin.ModelAdmin):
    actions = ['make_published', 'make_unpublished']

    def make_published(self, request, queryset):
        queryset.update(is_published=True)

    def make_unpublished(self, request, queryset):
        queryset.update(is_published=False)

この例では、make_published アクションは、選択されたすべてのブログ記事を公開に設定します。make_unpublished アクションは、選択されたすべてのブログ記事を非公開に設定します。

アクションの表示

アクションは、管理サイトの変更リストページに表示されます。ユーザーは、チェックボックスを使用して複数のオブジェクトを選択し、アクションを選択して実行できます。

利点

actions を使用すると、次の利点があります。

  • 開発者が簡単にカスタマイズできる
  • ユーザーインターフェースから簡単に実行できる
  • 複数のオブジェクトに対して一括処理を実行できる

注意点

actions を使用する場合、次の点に注意する必要があります。

  • アクション関数は、ユーザーが実行する前に確認ダイアログを表示する必要があります。
  • アクション関数は、変更をデータベースに保存する必要があります。
  • アクション関数は、選択されたすべてのオブジェクトに対して実行されます。
  • actions は、ModelAdmin クラスの check_selection 属性を使用して、アクションを実行する前に選択されたオブジェクトを確認するかどうかを制御できます。
  • actions は、ModelAdmin クラスの short_description 属性と description 属性を使用して、ユーザーインターフェースに表示される説明をカスタマイズできます。
  • actions は、ModelAdmin クラスの actions_on_top 属性と actions_on_bottom 属性を使用して、変更リストページのどこに表示するかを制御できます。


from django.contrib import admin
from .models import BlogPost

class BlogPostAdmin(admin.ModelAdmin):
    actions = ['make_published', 'make_unpublished']

    def make_published(self, request, queryset):
        queryset.update(is_published=True)

    def make_unpublished(self, request, queryset):
        queryset.update(is_published=False)

例 2: 選択された記事を削除する

この例では、BlogPost モデルに対して "削除" アクションを定義します。

from django.contrib import admin
from .models import BlogPost

class BlogPostAdmin(admin.ModelAdmin):
    actions = ['delete_selected']

    def delete_selected(self, request, queryset):
        queryset.delete()

例 3: 選択された記事を別のカテゴリに移動する

この例では、BlogPost モデルに対して "別のカテゴリに移動" アクションを定義します。

from django.contrib import admin
from .models import BlogPost, Category

class BlogPostAdmin(admin.ModelAdmin):
    actions = ['move_to_category']

    def move_to_category(self, request, queryset):
        category_id = request.POST.get('category_id')
        category = Category.objects.get(pk=category_id)
        queryset.update(category=category)

例 4: 選択された記事にタグを追加する

この例では、BlogPost モデルに対して "タグを追加" アクションを定義します。

from django.contrib import admin
from .models import BlogPost, Tag

class BlogPostAdmin(admin.ModelAdmin):
    actions = ['add_tag']

    def add_tag(self, request, queryset):
        tag_id = request.POST.get('tag_id')
        tag = Tag.objects.get(pk=tag_id)
        queryset.add(tag)
  • アクション関数は、選択されたオブジェクトが削除されるのを防ぐために、admin.ModelAdmin.has_delete_permission メソッドをチェックする必要があります。
  • アクション関数は、ユーザーが実行する前に確認ダイアログを表示する必要があります。これは、admin.action デコレータの confirm_message 引数を使用して行うことができます。
  • 上記の例では、アクション関数は単純な操作を実行しています。より複雑な処理を実行する場合は、アクション関数内で追加のロジックを実装する必要があります。


代替方法

以下に、actions の代替方法をいくつか紹介します。

カスタムビュー

カスタムビューを作成して、一括処理を実行することができます。この方法は、より複雑な処理や、actions では実現できない機能を実装する場合に適しています。

この例では、BlogPost モデルに対して "公開" と "非公開" のカスタムビューを作成します。

from django.contrib import messages
from django.shortcuts import redirect
from .models import BlogPost

def publish_blog_posts(request):
    if request.method == 'POST':
        queryset = BlogPost.objects.filter(pk__in=request.POST.getlist('selected'))
        queryset.update(is_published=True)
        messages.success(request, '記事を公開しました。')
        return redirect('admin:blog_blogpost_changelist')
    return render(request, 'blog/publish_blog_posts.html')

def unpublish_blog_posts(request):
    if request.method == 'POST':
        queryset = BlogPost.objects.filter(pk__in=request.POST.getlist('selected'))
        queryset.update(is_published=False)
        messages.success(request, '記事を非公開にしました。')
        return redirect('admin:blog_blogpost_changelist')
    return render(request, 'blog/unpublish_blog_posts.html')

Celery タスク

Celery などのタスクキューを使用すると、一括処理を非同期で実行することができます。この方法は、時間のかかる処理や、バックグラウンドで実行する必要がある処理に適しています。

この例では、BlogPost モデルに対して "公開" と "非公開" の Celery タスクを作成します。

from celery import shared_task
from .models import BlogPost

@shared_task
def publish_blog_posts(post_ids):
    queryset = BlogPost.objects.filter(pk__in=post_ids)
    queryset.update(is_published=True)

@shared_task
def unpublish_blog_posts(post_ids):
    queryset = BlogPost.objects.filter(pk__in=post_ids)
    queryset.update(is_published=False)

シグナル

Django シグナルを使用すると、オブジェクトが保存されたり、削除されたりするなどのイベントをトリガーして、一括処理を実行することができます。この方法は、他のコードで簡単にフックできる処理に適しています。

この例では、BlogPost モデルに対して "公開" と "非公開" のシグナルを作成します。

from django.dispatch import receiver
from .models import BlogPost

@receiver(post_save, sender=BlogPost)
def publish_blog_post(sender, instance, **kwargs):
    if instance.is_published:
        instance.publish()

@receiver(post_save, sender=BlogPost)
def unpublish_blog_post(sender, instance, **kwargs):
    if not instance.is_published:
        instance.unpublish()
方法利点欠点
カスタムビュー複雑な処理や、actions では実現できない機能を実装できる開発コストが高い
Celery タスク時間のかかる処理や、バックグラウンドで実行する必要がある処理に適しているCelery の設定と運用が必要
シグナル他のコードで簡単にフックできる複雑な処理には向かない