model methods and admin.py

What’s the correct way to set up a calculated field in admin.py?
Here’s my model,

class GateSale(models.Model):
    combinedGateProfit = models.DecimalField('Combined Gate Profit', null=True, blank=True, max_digits= 8, decimal_places=2)
    fiftyFiftyTotal = models.DecimalField('Fifty-Fifty Total', null=True, blank=True, max_digits= 8, decimal_places=2)
    officialsTotal = models.DecimalField('Officials', null=True, blank=True, max_digits= 8, decimal_places=2)

    def gameCalcs(self):
        gameProfit = (GateSale.combinedGateProfit + GateSale.fiftyFiftyTotal/2) - GateSale.officialsTotal
        
        return(gameProfit)

I would like to display gameProfit in admin.py. Is this possible? Not this way but how?

If you want to display this on the admin list page for the model, see: list_display

If you want to see this in the details page for an individual instance, see readonly_fields

From the descriptions you provided, I believe the first one works. To clarify I would like to display the the results of the calculation in the admin.py.

(GateSale.combinedGateProfit + GateSale.fiftyFiftyTotal/2) - GateSale.officialsTotal

The Djando docs confuse me. There are 4 examples after list_display. I was using list_display in my current admin.py however I don’t know what, if anything to use for the gateProfit return value I started with. That as an aside, using the 4th example but passing a decimal value

from django.contrib import admin
from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=50)
    birthday = models.DateField()

    @admin.display(description='Birth decade')
    def decade_born_in(self):
        return '%d’s' % (self.birthday.year // 10 * 10)

class PersonAdmin(admin.ModelAdmin):
    list_display = ('name', 'decade_born_in')

is all of this code in the admin.py or is the example showing both the model.py and the admin.py?
the first class refers to models.Model, that confuses me.
Secondly, if the code is all in the admin.py then the calculation is done in admin.py and not the model so I can remove

def gameCalcs(self):
        gameProfit = (GateSale.combinedGateProfit + GateSale.fiftyFiftyTotal/2) - GateSale.officialsTotal
        
        return(gameProfit)

correct?

That’s because there are four different, separate, and distinct sources of data that can be included in the list display. Those four examples demonstrate those four sources. You pick whichever one you need to use.

Which example? Depending on the case, it’s one or the other. They are two different sources handling two different situations.

So in your current situation, I think you’ve already recognized that the first case doesn’t apply.

Your choice among the other three is relatively arbitrary. Your selection among them would usually depend upon other factors. For example, if you need to use that calculation elsewhere in your system, you would likely prefer to have it in the Model, to be used in multiple locations.

I’m entering in values in the admin section currently. As I get to it it will be in a form from a webpage. That doesn’t matter though, just for context. I will leave the calc function in the model. So I’ll use the last example.

from django.contrib import admin
from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=50)
    birthday = models.DateField()

    @admin.display(description='Birth decade')
    def decade_born_in(self):
        return '%d’s' % (self.birthday.year // 10 * 10)

class PersonAdmin(admin.ModelAdmin):
    list_display = ('name', 'decade_born_in')

If that’s good I’ll ask another question. So far so good?

Appologies if I’m asking the obvious, but I’m not able to get this working yet. But, this code is in the model correct …?

rom django.contrib import admin
from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=50)
    birthday = models.DateField()

    @admin.display(description='Birth decade')
    def decade_born_in(self):
        return '%d’s' % (self.birthday.year // 10 * 10)

and the second class is in the admin, right?

class PersonAdmin(admin.ModelAdmin):
    list_display = ('name', 'decade_born_in')

Model

class GateSale(models.Model):
    combinedGateProfit = models.DecimalField('Combined Gate Profit', null=True, blank=True, max_digits= 8, decimal_places=2)
    fiftyFiftyTotal = models.DecimalField('Fifty-Fifty Total', null=True, blank=True, max_digits= 8, decimal_places=2)
    officialsTotal = models.DecimalField('Officials', null=True, blank=True, max_digits= 8, decimal_places=2)

    @admin.display(description='gameProfit')
    def gameProfit(self):
        gameProfit = (GateSale.combinedGateProfit + (GateSale.fiftyFiftyTotal/2)) - GateSale.officialsTotal
        
        return '%d' % (gameProfit)

Admin

from .models import GateSale

@admin.register(GateSale)
class GateSaleAdmin(admin.ModelAdmin):
    list_display = (
        'gameProfit'
        )

Error

TypeError at /admin/website/gatesale/
unsupported operand type(s) for /: 'DeferredAttribute' and 'int'

Assuming that PersonAdmin is registered as the admin class for Person, yes, this superficially looks right.

Notice the difference in how the earlier example for decade_born_in accesses the birthday field within the model with how you’re trying to access the fields within the model in gameProfit.

You mean is should be this right…?

@admin.display(description='gameProfit')
    def gameProfit(self):
        gameProfit = (self.combinedGateProfit + (self.fiftyFiftyTotal/2)) - self.officialsTotal
        
        return '%d' % (gameProfit)

That’s the appropriate way to reference fields in the current instance of the model, yes.

Courtesy of Ken …


Can’t thank you enough. I’m sure I’ll break it again!