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 の設定と運用が必要 |
シグナル | 他のコードで簡単にフックできる | 複雑な処理には向かない |