Search code examples
djangodjango-modelsdjango-admindjango-admin-actions

Django admin: How to show calculated value from entered values dynamically in Django admin form page?


I have a form which is having a 'price', 'tax' and 'discount' fields (IntegerFields). And then one more read-only field will be there called 'total_price'.

while we enter the 'price', 'discount' and 'tax', automatically 'total_price' value should display. If we change the 'discount' or 'price' then 'total_price' also change immediately.

After seeing the final price, we can click the 'Save' button.

How to attain this in Django admin?


Solution

  • To do this, you will have to add custom Javascript code to your admin page.

    Here's what you can do:

    1. Add read-only field to admin - it will display "total_price"
    2. Add custom script to admin page.
    3. Write JS script - this script will do "live update" of total price

    Your admin may look like this:

    @admin.register(YourModel)
    class YourModelAdmin(admin.ModelAdmin):
    
        # some code here...
    
        readonly_fields = ('total_price', )
    
        def total_price(self, obj):
            # return whatever initial value you want
            return obj.price - obj.price*obj.discount
    
        # This is important - adding custom script to admin page
        @property
        def media(self):
            media = super().media
            media._js.append('js/your-custom-script.js')
            return media
    

    Remember that js/your-custom-script.js must be in your static files folder.

    UPDATE: Instead of overwriting media property, you can include your JS using Meta nested class:

    class YourModelAdmin(admin.ModelAdmin):
        ...
        class Media:
            js = (
                'path-to-your-static-script-file.js',
            )
    

    The last step is to write a script to update value of total_price field whenever some other field is changed.

    Example: if you want to change total_price whenever price is changed, your script can look like this:

    if (!$) {
        $ = django.jQuery;
    }
    $(document).ready(function(){
        // Add event listener to "price" input
        $("#id_price").change(function(e){
            // Get entered value
            let price = parseFloat($(this).val());
    
            // Get discount value from another field 
            let discount = parseFloat($("#id_discount").val())
    
            // Compute total price in whatever way you want
            let total_price = price - price*discount;
    
            // Set value in read-only "total_price" field.
            $("div.field-total_price").find("div.readonly").text(total_price);
        });
    })
    

    If you want to update total_price when discount or tax fields are changed, simply add event listeners to them.