Django Admin Show / Hide Fields If Specific Value Is Selected In A Dropdown

10,251

Purpose of this question: to show / hide a fieldset if a specific option is selected in a Django admin form dropdown.

Solution overview: you need to break fieldsets up into two instead of one, custom javascript, define Media class in ModelAdmin.

[Step One] In my project named dropdown, I added the following folders / files:

  • static (directory)
  • static/dropdown (directory)
  • static/dropdown/js (directory)
  • static/dropdown/js/base.js (file)

[Step Two] In admin.py, a few things to note:

  1. I broke fieldsets up into two instead of one.
  2. Notice that I'm defining classes for each fieldset. abcdefg is the name of the class of the fieldset I'm trying to show and hide.
  3. I defined class Media. This tells django where to look for custom javascript and css files.

admin.py

from django.contrib import admin
from dropdown.models import DropdownModel
from dropdown.forms import DropdownModelForm

class DropdownModelAdmin(admin.ModelAdmin):

    fieldsets = (
        ('Date Range', {
            'fields': ('date_range',),
            'classes': ('predefined',)
        }),
        (None, {
            'fields': (('start_date', 'end_date'),),
            'classes': ('abcdefg',)
        })
    )

    form = DropdownModelForm

    class Media:
        js = ('dropdown/js/base.js',)

admin.site.register(DropdownModel, DropdownModelAdmin)

[Step Three] Add javascript. I take no credit for this script; I only modified it slightly from here.

base.js

(function($) {
    $(function() {
        var selectField = $('#id_date_range'),
            verified = $('.abcdefg');

        function toggleVerified(value) {
            if (value === 'Custom') {
                verified.show();
            } else {
                verified.hide();
            }
        }

        // show/hide on load based on existing value of selectField
        toggleVerified(selectField.val());

        // show/hide on change
        selectField.change(function() {
            toggleVerified($(this).val());
        });
    });
})(django.jQuery);

[Step Four]

forms.py

from django import forms
from dropdown.models import DropdownModel

class DropdownModelForm(forms.ModelForm):

    class Meta:
        model = DropdownModel
        fields = ('date_range',)
        widgets = {
            'date_range': forms.Select(choices=DropdownModel.CHOICES)
        }
Share:
10,251
Jarad
Author by

Jarad

I am many things. Programmer - Python primarily, trying to learn Javascript more Data scientist - machine learning with Python (Scikit-learn, Tensorflow, Keras, PyTorch, etc.) Entrepreneur - Build paid search software, creator of an index card sleeve (very useful next to your desk while you code), online course creator, paid advertising consultant and mentor, and so on.

Updated on July 10, 2022

Comments

  • Jarad
    Jarad almost 2 years

    In the Django admin, when the choice Custom is selected from a dropdown list, I want to display the inline start_date and end_date fields to allow the user to specify a specific start and end-date instead of a pre-defined time period.

    After researching for some time, suggestions include: use hidden fields, define override get_form in ModelAdmin, or use custom Javascript (which I have zero experience with).

    The Question: how can I display (show) the inline start_date and end_date fields when a specific value (Custom) is selected in the dropdown of a Django Admin field? When Custom is not selected, start_date and end_date would be hidden from view.


    Step 1: step 1 - select a date range

    Step 2: step 2 - if custom is selected

    Step 3: step 3 - show the inline custom date fields


    Below is a complete example of the exact example code I have locally:

    settings.py

    INSTALLED_APPS = [
        'django.contrib.admin',
        ...
        'dropdown.apps.DropdownConfig',
    ]
    

    apps.py

    from django.apps import AppConfig
    
    class DropdownConfig(AppConfig):
        name = 'dropdown'
    

    models.py

    from django.db import models
    
    class DropdownModel(models.Model):
    
        CHOICES = (
            ('Today', 'Today'),
            ('Yesterday', 'Yesterday'),
            ('Last 7 Days', 'Last 7 Days'),
            ('Last 14 Days', 'Last 14 Days'),
            ('Last 30 Days', 'Last 30 Days'),
            ('Last 60 Days', 'Last 60 Days'),
            ('Last 90 Days', 'Last 90 Days'),
            ('This Year', 'This Year'),
            ('All Time', 'All Time'),
            ('Custom', 'Custom')
        )
    
        date_range = models.CharField(max_length=15)
        start_date = models.DateField()
        end_date = models.DateField()
    

    forms.py

    from django import forms
    from dropdown.models import DropdownModel
    
    class DropdownModelForm(forms.ModelForm):
    
        class Meta:
            model = DropdownModel
            fields = ('date_range',)
            widgets = {
                'date_range': forms.Select(choices=DropdownModel.CHOICES)
            }
    

    admin.py

    from django.contrib import admin
    from dropdown.models import DropdownModel
    from dropdown.forms import DropdownModelForm
    
    class DropdownModelAdmin(admin.ModelAdmin):
        fieldsets = (
            ('Date Range', {
                'fields': ('date_range', ('start_date', 'end_date'))
            }),
        )
        form = DropdownModelForm
    
    admin.site.register(DropdownModel, DropdownModelAdmin)
    
  • Amechi
    Amechi over 6 years
    Just used this solution! Works like a charm :-)
  • Twimnox
    Twimnox over 5 years
    where do you get the id to fill var selectField = $('#id_date_range') ? is id_date_range the html id of the date range field?
  • Jarad
    Jarad over 5 years
    Yes, you are correct. Each form field has an ID attribute set to id_<field-name>.
  • Twimnox
    Twimnox over 5 years
    Is it possible to use your approach in a StackedInline class? I'm trying to do exactly the same, but in a tab of my admin page. I had no success so far. It seems that the Javascript isn't detecting my fieldsets classes, hence not showing or hiding conditionally.
  • Twimnox
    Twimnox over 5 years
    SOLVED MY ISSUE: My django project wasn't loading static file "base.js" correctly... the solution works like a charm with inlines!
  • kiliman13
    kiliman13 about 3 years
    @Twimnox how have you solved the loading of static file?