Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django admin show field only if checkbox is false

models.py

class Menu(models.Model):

    ...
    has_submenu=models.BooleanField(default=1)
    page=models.ForeignKey(Page,null=True)

I want django admin shows the page attribute only if has_submenu checkbox is false (So django-admin must write some javascript for me :) )

Maybe i must extend the render_change_form method

Any advice?

like image 642
Chris P Avatar asked Apr 12 '13 18:04

Chris P


4 Answers

You can use jQuery within the Django admin:

class MenuAdmin(admin.ModelAdmin):
    # ...
    class Media:
        js = ('/static/admin/js/hide_attribute.js',)

ModelAdmin and InlineModelAdmin have a media property that returns a list of Media objects which store paths to the JavaScript files for the forms and/or formsets.

Contents of hide_attribute.js:

hide_page=false;
django.jQuery(document).ready(function(){
    if (django.jQuery('#id_has_submenu').is(':checked')) {
        django.jQuery(".page").hide();
        hide_page=true;
    } else {
        django.jQuery(".page").show();
        hide_page=false;
    }
    django.jQuery("#id_has_submenu").click(function(){
        hide_page=!hide_page;
        if (hide_page) {
            django.jQuery(".page").hide();
        } else {
            django.jQuery(".page").show();
        }
    })
})

Namespacing:

To avoid conflicts with user-supplied scripts or libraries, Django’s jQuery (version 3.3.1) is namespaced as django.jQuery.

like image 168
Chris P Avatar answered Nov 02 '22 12:11

Chris P


I actually had to modify this a little bit and figured I would share what I did here in case anyone else stumbles into this post. There were three main areas that I had to account for:

  1. Frequently errors out because it attempts to load django.jQuery before it is ready.
  2. Hide was not working in general (not sure why)
  3. Wanted to do the inverse, hiding unless the option was checked.

So, this solves all three of those problems for me. We do the following:

  1. Delay calling the function
  2. Hide the .form-row.field-, to hide an entire row (I recommend using chromes inspect feature to find the name of the row you want to hide.)
  3. We do the inverse, hiding the section as soon as the page is done loading and then unhiding if the box is checked.

So this is my final code:

window.addEventListener("load", function() {
    (function() {
        show_page=false;
        django.jQuery(document).ready(function(){
            if (django.jQuery('#id_override_timeline').is(':checked')) {
                django.jQuery(".form-row.field-next_milestone").show();
                show_page=true;
            } else {
                django.jQuery(".form-row.field-next_milestone").hide();
                show_page=false;
            }
            django.jQuery("#id_override_timeline").click(function(){
                show_page=!show_page;
                if (show_page) {
                    django.jQuery(".form-row.field-next_milestone").show();
                } else {
                    django.jQuery(".form-row.field-next_milestone").hide();
                }
            })
        })
    })(django.jQuery);
});


I hope this helps someone else who stumbles on this post!

like image 29
Snala Avatar answered Nov 02 '22 12:11

Snala


How about overriding get_form method on a ModelAdmin, like this:

class MenuModelAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        self.exclude = []
        if obj and obj.has_submenu:
            self.exclude.append('page')
        return super(MenuModelAdmin, self).get_form(request, obj, **kwargs)

Also, please, see get_form docs.

like image 3
alecxe Avatar answered Nov 02 '22 11:11

alecxe


You could extend Django admin template.

Just follow this structure:

Across an entire project:

templates/admin/change_form.html

Across an application

templates/admin/<my_app>/change_form.html

Across a Model

templates/admin/<my_app>/<my_model>/change_form.html

In your case, looks like you only need to extend the Menu model. I would do the following:

  1. grab the change_form.html teamplate from django folder
  2. inside the object loop, look for the page field
  3. do the condition check on has_submenu to decide whether to show or not the page attribute
like image 1
user1802310 Avatar answered Nov 02 '22 11:11

user1802310