GaretJax
GaretJax

Reputation: 7780

How to display a boolean property in the django admin

As we all know, displaying a method return value as boolean in the Django admin is easily done by setting the boolean attribute:

class MyModel(models.Model):
    def is_something(self):
        if self.something == 'something':
            return True
        return False
    is_something.boolean = True

How can you achieve the same effect for a property, like in the following case?

class MyModel(models.Model):
    @property
    def is_something(self):
        if self.something == 'something':
            return True
        return False

Upvotes: 40

Views: 19640

Answers (6)

Nick Vee
Nick Vee

Reputation: 1052

Nowadays you can use @admin.display decorator

class MyModelAdmin(admin.ModelAdmin):
    list_display = ['is_something']

    @admin.display(boolean=True)
    def is_something(self, obj):
        return obj.is_something

Upvotes: 1

Peter
Peter

Reputation: 6669

You need to create a shadowing function to the property in the model. What I mean is that you will need to recreate a function in the ModelAdmin class with the same name as the property defined in the main Model.

Example:

# Model
class Product(models.Model):

    @property  # you can omit this decorator if you will access this property as a method of the model instance
    def in_stock(self):
        # boolean check return
        return self.quantity > 0

...

# Django-modeladmin
class ProductAdmin(admin.ModelAdmin):
    list_display = ('in_stock', ...)
    def in_stock(self, instance):
        return instance.in_stock

    in_stock.boolean = True        

Upvotes: 18

Xavier-Lam
Xavier-Lam

Reputation: 513

You can create a decorator like this

from six.moves import reduce

def list_property(field_name, **kwargs):
    def _from_property(obj):
        rv = reduce(getattr, field_name.split("."), obj)
        return rv() if callable(rv) else rv

    for key, value in kwargs.items():
        setattr(_from_property, key, value)
    return _from_property

here are your model and admin definitions:

# model

class MyModel(models.Model):
    @property
    def is_something(self):
        if self.something == 'something':
            return True
        return False


# admin

class MyModelAdmin(admin.ModelAdmin):
    list_display = [list_property("is_something", boolean=True)]

for readonly fields in modeladmin you can use this decorator instead:

def field_property(field_name, **kwargs):
    def _from_property(admin, obj=None):
        if not obj:
            return None
        rv = reduce(getattr, field_name.split("."), obj)
        return rv() if callable(rv) else rv

    for key, value in kwargs.items():
        setattr(_from_property, key, value)
    return _from_property

# admin
class MyModelAdmin(admin.ModelAdmin):
    readonly_fields = ["is_something"]

    is_something = field_property("is_something", boolean=True)

Upvotes: 3

user7297468
user7297468

Reputation: 451

this is the simplest way I found, directly in the ModelAdmin:

class MyModelAdmin(admin.ModelAdmin):
    def is_something(self, instance):
        return instance.something == "something"
    is_something.boolean = True
    is_something.short_description = u"Is something"

    list_display = ['is_something']

Upvotes: 45

esauro
esauro

Reputation: 1286

If you define is_something as a property, it will be an immutable object, instead of a function, but that object contains a reference to the decorated getter in the fget attribute. I think that the Django admin interface use the getter of that property, thus this may works

class MyModel(models.Model):
    @property
    def is_something(self):
        if self.something == 'something':
            return True
        return False
    is_something.fget.boolean = True

Upvotes: -1

GaretJax
GaretJax

Reputation: 7780

Waiting for better solutions to come up, I've solved it in the following way:

class MyModel(models.Model):
    def _is_something(self):
        if self.something == 'something':
            return True
        return False
    _is_something.boolean = True
    is_something = property(_is_something)

I'll then reference the _is_something method in the ModelAdmin subclass:

class MyModelAdmin(admin.ModelAdmin):
    list_display = ['_is_something']

And the is_something property otherwise:

if my_model_instance.is_something:
    print("I'm something")

Upvotes: 38

Related Questions