Skip to content

django-admin-extra-buttons

Pypi coverage Test Documentation Django Supported Python versions

my image

This is a full rewriting of the original django-admin-extra-url. It provides decorators to easily add custom buttons to Django Admin pages and/or add views to any ModelAdmin

It allows easy creation of wizards, actions and/or links to external resources as well as api only views.

Four decorators are available:

  • @button() to mark a method as extra view and show related button
  • @link() This is used for "external" link, where you don't need to invoke local views.
  • @view() View only decorator, this adds a new url but do not render any button.
  • @choice() Menu like button, can be used to group multiple @views().

How to use it

class Admin1(ExtraButtonsMixin, admin.ModelAdmin):
    list_filter = [TestFilter]

    @button(permission="demo.add_demomodel1", change_form=True, change_list=False, html_attrs={"class": "aeb-green"})
    def refresh(self, request):
        self.message_user(request, "refresh called")

    @button(label="Refresh", permission=lambda request, object, **kw: False)
    def refresh_callable(self, request):
        opts = self.model._meta
        self.message_user(request, "refresh called")
        return HttpResponseRedirect(reverse(admin_urlname(opts, "changelist")))

    @button(pattern="a/b/")
    def custom_path(self, request):
        opts = self.model._meta
        self.message_user(request, "You invoked `custom_path` linked to 'a/b/' url ")
        return HttpResponseRedirect(reverse(admin_urlname(opts, "changelist")))

    @button(html_attrs={"style": "background-color:#EDD372;color:black"})
    def no_response(self, request):
        self.message_user(request, "No Response provided.")

    @button(html_attrs={"style": "background-color:#DC6C6C;color:black"})
    def confirm(self, request):
        def _action(request: HttpRequest) -> None:
            pass

        return confirm_action(
            self,
            request,
            _action,
            message="Confirm action",
            success_message="Successfully executed",
        )

    @button(permission="demo.delete_demomodel1")
    def update(self, request, pk):
        opts = self.model._meta
        self.message_user(request, "action called")
        return HttpResponseRedirect(reverse(admin_urlname(opts, "changelist")))

    @button()
    def no_response_single(self, request, object_id):
        self.message_user(request, "No_response_obj.")

    @button(permission=lambda request, obj, **kw: False)
    def update_callable_permission(self, request, object_id):
        opts = self.model._meta
        self.message_user(request, "action called")
        return HttpResponseRedirect(reverse(admin_urlname(opts, "changelist")))

    @button(pattern="a/b/<path:object_id>")
    def custom_update(self, request, object_id):
        opts = self.model._meta
        self.message_user(request, "action called")
        return HttpResponseRedirect(reverse(admin_urlname(opts, "changelist")))

    @button(visible=lambda btn: "BTN_SHOW" in os.environ)
    def custom_visibile(self, request):
        pass

    @button(enabled=False)
    def disabled(self, request):
        pass

    @button(enabled=lambda btn: "BTN_ENABLED" in os.environ)
    def enabled(self, request):
        pass

    @link(href="https://www.google.com/", visible=lambda btn: True)
    def invisible(self, button):
        button.visible = False

    @button()
    def error_message(self, request):
        try:
            1 / 0
        except Exception as e:  # noqa: BLE001
            self.message_error_to_user(request, e)