10

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?

4 Answers 4

24
+100

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.

Sign up to request clarification or add additional context in comments.

Comments

3

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.

2 Comments

This works great only if i am trying to edit a menu.. I want to .hide() .show() this on the fly (i am trying to avoid write javascript)
@ChrisPappas, I see what you mean. Sounds like you have to write some js stuff anyway..
2

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!

Comments

1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.