Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

call a function with a button in django admin

Tags:

django

I have a python class in models.py:

class Scenario(TemporalObject):
    name = models.CharField(max_length=200)
    user = models.CharField(max_length=200)
    start = models.DateTimeField(default=django.utils.timezone.now)
    end = models.DateTimeField(default=django.utils.timezone.now)

    def nb_hours(self):
        """Compute the number of hours between start and end"""
        return (int((self.end - self.start).total_seconds() // 3600))+1

    def activate_button(self):
        return format_html(
            '''<form action="activate/" method="POST">
                   <button type="submit"> Activate </button>
                </form>''')
    

And the correspondig

class ScenarioAdmin(admin.ModelAdmin):
    list_display = ("name", "user", "start", "end", "nb_hours","activate_button")

I want to call a function through the button that I created with activate_button. How can I do?

The function that i want is like an old action:

def make_active(scenario_admin, request, queryset):
    if len(queryset) == 0:
        logger.info("No scenario selected when activating one of them")
        return
    if len(queryset) > 1:
        msg = "Can't activate more than one scenario at a time."
        msg += " Please select only one scenario."
        scenario_admin.message_user(request, msg, level=messages.ERROR)
        return
    # Get the scenario to activate
    target = queryset[0]
    # It is already activated
    if target.user == request.user.username:
        msg = "Scenario already active"
        scenario_admin.message_user(request, msg, level=messages.WARNING)
        return
    if target.user is not None and len(target.user) > 0:
        msg = f"Can't activate scenario '{target}'"
        msg += f" because it is active for user '{target.user}'"
        scenario_admin.message_user(request, msg, level=messages.ERROR)
        return
    # Deactivate all other scenarios that are active
    for scenario in Scenario.objects.filter(user=request.user.username):
        scenario.user = ""
        scenario.save()
    # Activate the scenario
    target.user = request.user.username
    target.save()
    msg = f"Activated scenario '{target}'"
    scenario_admin.message_user(request, msg, level=messages.INFO)

I should replace queryset[0] by self inside the class Scenario

like image 711
noName Avatar asked Nov 16 '25 05:11

noName


2 Answers

You can use get_urls method and create a custom view method of the ScenarioAdmin.

models.py:

from django.utils.html import format_html
from django.urls import reverse_lazy

class Scenario(TemporalObject):
    ...

    def activate_button(self):
        return format_html('<a href="{}" class="link">Activate</a>',
            reverse_lazy("admin:admin_activate_scenario", args=[self.pk])
        )

admin.py:

from django.template.response import TemplateResponse
from django.urls import path
from django.shortcuts import redirect, get_object_or_404


class ScenarioAdmin(admin.ModelAdmin):
    list_display = (
        "name", "user", "start", 
        "end", "nb_hours", "activate_button")

    def get_urls(self):
        urls = super().get_urls()
        my_urls = [
            path('activate-scenario/<int:pk>/', self.acitvate_scenario, name="admin_activate_scenario"),
        ]
        return my_urls + urls

    def acitvate_scenario(self, request, pk):
        # ...
        context = dict(
           # Include common variables for rendering the admin template.
           self.admin_site.each_context(request),
           # Anything else you want in the context...
        )

        # Get the scenario to activate
        target = get_object_or_404(Scenario, pk=pk)
        # It is already activated
        if target.user == request.user.username:
            msg = "Scenario already active"
            self.message_user(request, msg, level=messages.WARNING)
            return redirect(request.META.get('HTTP_REFERER'))
        if target.user is not None and len(target.user) > 0:
            msg = f"Can't activate scenario '{target}'"
            msg += f" because it is active for user '{target.user}'"
            self.message_user(request, msg, level=messages.ERROR)
            return redirect(request.META.get('HTTP_REFERER'))
        # Deactivate all other scenarios that are active
        for scenario in Scenario.objects.filter(user=request.user.username):
            scenario.user = ""
            scenario.save()
        # Activate the scenario
        target.user = request.user.username
        target.save()
        msg = f"Activated scenario '{target}'"
        self.message_user(request, msg, level=messages.INFO)

        # redirect or TemplateResponse(request, "sometemplate.html", context)
        return redirect(request.META.get('HTTP_REFERER'))
like image 134
NKSM Avatar answered Nov 17 '25 18:11

NKSM


You can simply add a action button like this:

def activate_button(modeladmin, request, queryset):
    for scenario queryset:
        #Do something
        pass

class ScenarioAdmin(admin.ModelAdmin):
    list_display = ("name", "user", "start", "end", "nb_hours")
    actions = [activate_button]

admin.site.register(Scenario, ScenarioAdmin)

You can find it in the docs here: https://docs.djangoproject.com/en/3.1/ref/contrib/admin/actions/

like image 35
jojacobsen Avatar answered Nov 17 '25 20:11

jojacobsen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!