1

What am I doing wrong?
In django admin-panel I want to show/hide field(s) based on the choice dropdown. Also the, choice dropdown lies on parent foreign-key related model and the fields that are to be shown/hidden lies in child model or as an stacked inline.
I've followed this solution(stack overflow), but no success.

models.py

from django.db import models

CHOICES = (
        ('video', 'Video'),
        ('text', 'Text'),
        ('question', 'Question'),
)


class Section(models.Model):
    content_type = models.CharField(max_length=32)

    @property
    def contents(self):
        return self.content_set.all()

class Content(models.Model):
    content = models.ForeignKey(Section, on_delete=models.DCASCADE)
    video = models.FileField()
    text = models.TextField()
    question = models.CharField(max_length=512)

admin.py

from django.contrib import admin

from .models import Section, Content
from .forms import DropdownModelForm


class ContentInline(admin.StackedInline):
    model = Content
    fieldsets = (
        (None, {
            'fields': (('video',),),
            'classes': ('vid',)
        }),
        (None, {
            'fields': (('text',),),
            'classes': ('txt',)
        }),
        (None, {
            'fields': (('question',),),
            'classes': ('ques',)
        })
    )

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

@admin.register(Section)
class SectionAdmin(admin.ModelAdmin):
    form = DropdownModelForm
    inlines = (ContentInline,)

forms.py

from django import forms
from .models import Section, CHOICES

class DropdownModelForm(forms.ModelForm):

    class Meta:
        model = Section
        fields = ('content_type',)
        widgets = {
            'content_type': forms.Select(choices=CHOICES)
        }

base.js

(function($) {
    $(function() {
        var selectField = $('#id_content_type'),
            verified_1 = $('.vid'),
            verified_2 = $('.txt'),
            verified_3 = $('.ques');

        function toggleVerified(value) {
            if (value === 'video') {
                verified_1.show();
                verified_2.hide();
                verified_3.hide();
            } else if (value === 'text') {
                verified_1.hide();
                verified_2.show();
                verified_3.hide();
            } else if (value === 'question') {
                verified_1.hide();
                verified_2.hide();
                verified_3.show();
            }
        }

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

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

settings.py

from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent
.
.
.

INSTALLED_APPS = [
    'one.apps.OneConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]
.
.
.

STATIC_URL = '/static/'
STATICFILES_DIRS = [
    BASE_DIR / "static",
]

Project Structure

Again, What am I doing wrong?
In django admin-panel I want to show/hide field(s) based on the choice dropdown. Also the, choice dropdown lies on parent foreign-key related model and the fields that are to be shown/hidden lies in child model or as an stacked inline.
I've followed this solution(stack overflow), but no success.

Thank you very much for expending your valuable time & giving a look on my poor code

kiliman13
  • 91
  • 2
  • 4

3 Answers3

0

passing javascript file as a list in admin.py solved the problem.

class Media:
        js = ["one/js/base.js",]

also, don't know why jquery was not working properly. So for this wrap your javascript inside jQuery(document).ready(function ($) { ...your javascript... });, as

jQuery(document).ready(function ($) {
    (function ($) {
        $(function () {
            var selectField = $('#id_content_type'),
                verified_1 = $('.vid'),
                verified_2 = $('.txt'),
                verified_3 = $('.ques');

            function toggleVerified(value) {
                if (value === 'video') {
                    verified_1.show();
                    verified_2.hide();
                    verified_3.hide();
                } else if (value === 'text') {
                    verified_1.hide();
                    verified_2.show();
                    verified_3.hide();
                } else if (value === 'question') {
                    verified_1.hide();
                    verified_2.hide();
                    verified_3.show();
                }
            }

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

            // show/hide on change
            selectField.change(function () {
                toggleVerified($(this).val());
            });
        });
    })(django.jQuery);
});
kiliman13
  • 91
  • 2
  • 4
0

If anyone ever encounters the same problem as me and doesn't know JS, here is my case and solution.

Case: Need to create courses in django admin site with possible formats online/offline and if format is offline field city is showed.

Solution:

models.py

class Course(models.Model):
    FORMAT_CHOICES = (
        ('On', 'Online'),
        ('Off', 'Offline')
    )

    format = models.CharField(
        'Формат проведения',
        max_length=3,
        choices=FORMAT_CHOICES,
        default='On')
    city = models.ForeignKey(
        City,
        verbose_name='Город',
        on_delete=models.SET_NULL,
        related_name='courses',
        null=True,
        blank=True
    )

admin.py

@admin.register(Course)
class CourseAdmin(admin.ModelAdmin):
    list_display = ('name', 'category', 'format', 'city', 'date', 'date_add')
    list_filter = ('format' ,'date')
    search_fields = ('city', 'name', 'category')

    class Media:
        js = ('admin/js/hide_attribute.js',)

hide_attribute.js

document.addEventListener('DOMContentLoaded', function(){
  function toggleCity(value) {
    const cityWrapper = document.querySelector('.field-city');
    if (value === 'On') {
        cityWrapper.style.display = 'none';
    } else {
        cityWrapper.style.display = 'block';
    }
  }
  
  const formatSelect = document.querySelector('select#id_format');
  if (formatSelect) {
      toggleCity(formatSelect.value);
 
      formatSelect.addEventListener('click', function(){
          toggleCity(this.value);
      })    
  }

})
0

you can't use $('#id_content_type') to control inlines = (ContentInline,)

inlines has there own prefix, in your case, your first content inline will be like 'id_content-0-type'

Liao Zhuodi
  • 3,144
  • 5
  • 26
  • 46