from django.contrib import admin
from .models import Shop
@admin.register(Shop)
class ShopAdmin(admin.ModelAdmin):
@admin.display(description='Name')
def upper_case_name(self,obj):
return("%s" % (obj.name)).upper()
Django==3.1
I was fighting with this for a while, I didn't understand why the @admin.action()
decorator didn't appear, I started to read the Django code and I found that when the actions for the Django Admin start to load, it calls a method called _get_base_actions
, and this same method gets the action and description in this way:
# django.contrib.admin.ModelAdmin._get_base_actions
...
description = getattr(func, 'short_description', name.replace('_', ' '))
...
I had already tried several ways to load the action and to correctly take the description of the action, if it was not defined, what Django did was to take the name of the same function and replace the underscores with spaces, resulting in a somewhat frightening result.
The first thing I thought of as a quick and valid solution was to create a class and modify the __new__
method, which is called before the __init__
method.
This is an example of what I needed, to be able to generate a PDF from Django actions:
class GeneratePDF:
short_description = "WRITE THE DESCRIPTION OF ACTION HERE"
def __new__(cls, modeladmin, request, queryset):
result = cls.generate_pdf_resume(modeladmin, request, queryset)
return result
@classmethod
def generate_pdf_resume(cls, modeladmin, request, queryset):
...
Finally, I added it to the list of ModelAdmin actions.
from project.own_actions import GeneratePDF
@admin.register(Patient)
class PatientAdmin(admin.ModelAdmin):
...
actions = [GeneratePDF]
Then it appeared with the description that I had placed in the class as a class attribute.
I could also reuse this class to create a URL and successfully generate the PDF.
# project/urls.py
from project.own_actions import GeneratePDF
urlpatterns = [
path('admin/', admin.site.urls),
...
path('export/', GeneratePDF, name="export-pdf")
]
You can still achieve the same goal without using the display decorator.
list_display = ('upper_case_name',)
def upper_case_name(self, obj):
return "%s" % (obj.name.upper())
upper_case_name.short_description = "Name"
Using the answer from Jermaine, you can create your own decorator and monkey patch it to the admin module. This would allow you to use the @admin.display(description="...")
decorator.
# Monkey patch admin to include the display decorator (available in future Django versions)
if not hasattr(admin, "display"):
def display(description):
def decorator(fn):
fn.short_description = description
return fn
return decorator
setattr(admin, "display", display)
Complete example:
from django.contrib import admin
from .models import Shop
# Monkey patch admin to include the display decorator (available in future Django versions)
if not hasattr(admin, "display"):
def display(description):
def decorator(fn):
fn.short_description = description
return fn
return decorator
setattr(admin, "display", display)
@admin.register(Shop)
class ShopAdmin(admin.ModelAdmin):
@admin.display(description='Name')
def upper_case_name(self,obj):
return("%s" % (obj.name)).upper()
This is not a super clean approach, but if you would like to use the decorator you can do it this way.
In my case you should activate virtualenv , by typing "pipenv shell" command I think it helps you too
In my case, for some reason, django was downgraded. I ran "pipenv update django" and it worked.
© 2022 - 2024 — McMap. All rights reserved.
display
decorator was introduced in Django 3.2 and it doesn't exist in older versions. – Rosenblum