qdot
qdot

Reputation: 6345

Django admin short_description as callable

Is there a way to define short_description for a field in ModelAdmin as callable - sometimes one wants to provide extra dynamic information inside column names.

Or are there any ugly hacks that accomplish the same goals?

Upvotes: 5

Views: 1440

Answers (3)

Guillaume Cisco
Guillaume Cisco

Reputation: 2935

The only thing that worked for me was to override get_readonly_fields/get_list_display

as described in this answer: https://stackoverflow.com/a/66028062

@admin.register(models.EmployeeTrainingRecord)
class EmployeeTrainingRecordAdmin(admin.ModelAdmin):
    ordering = ('email',)
    list_display = [
        'id',
        'first_name',
        'last_name',
    ]

    def get_queryset(self, request):
        return (
            super().get_queryset(request)
            .annotate_training_dates()
        )

    def get_list_display(self, request):
        list_display = super().get_list_display(request)
        training_modules = models.Training.objects.all()
        for training in training_modules:
            attr_name = 'training_%s' % training.id

            if not hasattr(self, attr_name):
                list_display.append(attr_name)
                func = partial(self._get_training_id, field=attr_name)
                func.short_description = training.name
                setattr(self, attr_name, func)
        return list_display

    @staticmethod
    def _get_training_id(obj, field=''):
        return getattr(obj, field, '')

Upvotes: 0

qdot
qdot

Reputation: 6345

Peter DeGlopper's answer provided the needed direction - despite the fact that since the djangosnippet's posting a lot of things have changed.

This is indeed working:

class MyAdmin(admin.ModelAdmin):
    list_display = ('my_callable')

    class MyCallable:
        def __call__(self, obj):
            return 42

        @property
        def __name__(self):
            return 'Galaxy'

    @property
    def my_callable(self):
        if not hasattr(self, __my_callable):
            self.__my_callable = self.MyCallable()
        return self__my_callable

Importantly enough, the MyAdmin object is not passed to the MyCallable.__call__() call - if you need access to it, pass it in the __init__ initializer yourself.

Upvotes: 1

Peter DeGlopper
Peter DeGlopper

Reputation: 37364

As far as I know/remember properties can only be defined on new-style classes, in the class definition. So your ModelAdmin field would have to resolve to a callable object with the desired property. This snippet looks to me like it should allow that:

https://djangosnippets.org/snippets/2447/

The field itself becomes a property that resolves to an instance of the VotesToday class, on which short_description is also a property.

Upvotes: 2

Related Questions