I have ported the following code from Django 2.2 to Django 3.1, and replaced django.utils.functional.curry
with functools.partialmethod
:
class CurrencyField(models.DecimalField):
description = 'Currency amount'
def __init__(self, *args, **kwargs):
kwargs.setdefault('max_digits', 9)
kwargs.setdefault('decimal_places', 2)
super().__init__(*args, **kwargs)
def contribute_to_class(self, cls, name):
super().contribute_to_class(cls, name)
if hasattr(cls, '_get_value_as_currency'):
curried = partialmethod(cls._get_value_as_currency, field=self)
curried.admin_order_field = self.name
curried.short_description = self.verbose_name
setattr(cls, f'get_{self.name}_as_currency', curried)
The method works correctly, however the admin_order_field
and short_description
attributes don't "stick" to the method like they did when I used curry
.
getattr(cls, f'get_{self.name}_as_currency').short_description
*** AttributeError: 'function' object has no attribute 'short_description'
Is it possible to set attributes on a partialmethod
, or will I need to replace this with some other mechanism?
So after a week or two of no answers, and a little more experimentation, I've given up on trying to get an attribute to stick to a partialmethod
and instead dynamically defined a local function, and used the new @admin.display
decorator from Django 3.2 to set the admin attributes, though the same could have been achieved without that syntactic sugar:
def contribute_to_class(self, cls, name):
super().contribute_to_class(cls, name)
if hasattr(cls, '_get_value_as_currency'):
@admin.display(
ordering=self.name,
description=self.verbose_name,
)
def getter(obj):
return obj._get_value_as_currency(self)
setattr(cls, f'get_{self.name}_as_currency', getter)