본문 바로가기
Django/Django개념

admin action custom 하기

by hyun-am 2023. 1. 3.

마케터 분의 요청

기존에 생성한 미션 7개를 2번 더 복사해서 14개를 만들어 총 21개를 만들고싶다고 했습니다. 이렇게 해야 단순 반복 action을 줄이고 더 빠르게 action 할 수 있기 때문입니다.

서버 쪽에서 해결 할 수 있는 방법

  • Django Admin에서 어떤것을 제공하는지 찾아보다가 custom action을 이용하면 해결할 수 있습니다.
    • admin에서 actions를 이용해서 해결

이제 이러한 문제를 해결하기 위해 공식문서에서 action부분을 확인했습니다.

 

 

Admin Action(개념)

Actions as ModelAdmin methods

다음 예시는 함수로 정의된 make_published action을 보여줍니다. 완벽하게 괜찮지만 코드 설계 관점에서 보면 완벽하지 않습니다. Action이 Article 개체에 밀접하게 연결되어 있기 때문에 Action을 ArticleAdmin 개체 자체에 연결하는 것이 좋습니다. 예시 코드는 다음과 같습니다.

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

먼저 make_published를 메서드로 옮기고 modeladmin 매개변수의 이름을 self로 변경했으며, 두 번째로 직접 함수 참조 대신 action에 문자열 ‘make_published’를 넣었습니다. 이는 ModelAdmin에게 조치를 메소드로 조회하도록 지시합니다.

예를 들어, 우리는 action을 성공적으로 사용자에게 알리는 메시지를 보낼 수 있습니다.

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)

이렇게 하면 작업을 성공적으로 수행한 후 관리자가 수행한 작업과 일치합니다.

우리 서비스 코드에 적용

이제 위에서 배운 내용을 기반으로 우리 코드에 적용 시키겠습니다.

method 생성하기

먼저 미션들을 복사하기 위해 make_duplicate_mission라는 method를 생성했습니다.

그리고 action이름은 “여러개 복사하기”를 사용하려고 admin에 action데코레이터를 이용했습니다.

@admin.action(description="여러개 복사하기")
    def make_duplicate_mission(self, request, queryset):

method 내용 채우기

요구사항 및 구현 해야할 사항

  1. 우선순위(1~7)인 것을 복사하면 새로 복사된 것들은 우선순위(8~14)이런식으로 설정되어 있어야 한다
  2. 미션에 연결되어 있는 이미지와 링크들도 그대로 복사 해야한다

전체코드

@admin.register(Mission)
class MissionAdmin(admin.ModelAdmin):
		
#		내용 생략
#		내용 생략
#		내용 생략

    @admin.action(description="여러개 복사하기")
    def make_duplicate_mission(self, request, queryset):
        mission_list = []
        mission_image_list = []
        mission_link_list = []
        count = queryset.count()
        for mission in queryset:
            mission_info = Mission(
                plan=mission.plan,
                id=mission.id,
#								코드 생략
                priority=mission.priority + count,

            )
            mission_list.append(mission_info)
            mission_images = mission.mission_image.all()
            mission_links = mission.mission_link.all()
            for mission_image in mission_images:
                mission_image_list.append(
                    MissionImage(
                        mission=mission_info,
#								코드 생략
                    )
                )

            for mission_link in mission_links:
                mission_link_list.append(
                    MissionLink(
                        mission=mission_info,
 #                       코드 생략
                    )
                )

        Mission.objects.bulk_create(mission_list)
        MissionImage.objects.bulk_create(mission_image_list)
        MissionLink.objects.bulk_create(mission_link_list)

        self.message_user(request, f"{count}개 복사 완료", messages.SUCCESS)
	actions = [make_duplicate_mission] -> 어드민 맨아래 추가사항

method 설명

mission_list = []
mission_image_list = []
mission_link_list = []
count = queryset.count()
  • mission_list, mission_image_list, mission_link_list는 쿼리셋을 담고 bulk_create를 하기위한 리스트 입니다.
  • queryset은 admin에서 체크한 것들을 의미하고 여기서 count는 체크한 것들의 개수를 의미합니다.
        for mission in queryset:
            mission_info = Mission(
                plan=mission.plan,
                id=mission.id,
#								코드 생략
                priority=mission.priority + count,

            )
            mission_list.append(mission_info)
            mission_images = mission.mission_image.all()
            mission_links = mission.mission_link.all()
            for mission_image in mission_images:
                mission_image_list.append(
                    MissionImage(
                        mission=mission_info,
#												코드 생략
                    )
                )

            for mission_link in mission_links:
                mission_link_list.append(
                    MissionLink(
                        mission=mission_info,
 #                       코드 생략
                    )
                )

        Mission.objects.bulk_create(mission_list)
        MissionImage.objects.bulk_create(mission_image_list)
        MissionLink.objects.bulk_create(mission_link_list)
  • queryset(체크한 미션들)개수만큼 for문을 돌면서 체크한 mission의 정보들을 mission_list, mission_image_list, mission_link_list에 담겠습니다.
  • 그 후 bulk_create를 통해 한꺼번에 생성했습니다.
self.message_user(request, f"{count}개 복사 완료", messages.SUCCESS)
	actions = [make_duplicate_mission] -> 어드민 맨아래 추가사항
  • 성공 시 메시지를 보내주기 위해 self.message_user를 사용했습니다.
  • 그 후 actions를 등록하기 위해 어드민 맨 아래 actions를 추가했습니다.

실행 장면

  • 원하는 미션 7개를 선택한 후 actions에 등록된 여러개 복사하기를 클릭하겠습니다

  • 상단에 7개 복사 완료라는 문구와 우선순위가 요구사항에 맞게 잘 들어간것을 확인할 수 있습니다.
  • 이미지와 링크도 복사된 것을 확인할 수 있습니다.

참고 링크

https://docs.djangoproject.com/en/4.1/ref/contrib/admin/actions/

 

Django

The web framework for perfectionists with deadlines.

docs.djangoproject.com

 

댓글