Search code examples
djangodjango-admindjango-modeladmin

Django-admin list_editable enable/disable on the fly (edit/view mode check)


I want to change edit/view mode of the page by button (or something like it). Edit mode is equal to list_editable specified in EntityModelAdmin body. View mode is equal to empty list_editable.

@admin.register(models.EntityModel)
class EntityModelAdmin(admin.ModelAdmin):
    list_display = ('name', 'barcode', 'short_code', )
    list_editable = ('barcode', 'short_code', )

How to achieve this? Seems I should override some class/function to consider the state of mode trigger.

Also it will be good to do the same (all fields is read-only) with add/change page of Entity instance.


Solution

  • As for me it's better to override changelist_view method of admin.ModelAdmin:

    class EntityModelAdmin(admin.ModelAdmin):
        list_display = ('name', 'barcode', 'short_code', )
        list_editable = ('barcode', 'short_code', )
    
        @csrf_protect_m
        def changelist_view(self, request, extra_context=None):
            """
            The 'change list' admin view for this model.
            Overrided only for add support of edit/view mode switcher.
            """
            ...parent code...
            try:
                cl = ChangeList(request, ...parent code...)
    
                # Customization for view/edit mode support
                if 'edit_mode' not in request.COOKIES:
                    cl.list_editable = ()
            ...parent code...
    

    Possible it's better to override another method. Not sure if it possible to override only some part of pretty big changelist_view method without copying most of all code as is (...parent code...).

    Button switcher can be like this:

    {% load myapp_various_tags %}  {# load get_item tag for dictionary #}
    
        <div id="mode">
            <div class="mode_item edit_mode {% if request.COOKIES|get_item:'edit_mode' %}selected{% endif %}" onclick="$.cookie('edit_mode', '1', { path: '/', expires: 30 }); location.reload(true);">
                <div class="header_icon"></div>
                <div class="header_text">{% trans "edit" %}</div>
            </div>
            <div class="mode_item view_mode {% if not request.COOKIES|get_item:'edit_mode' %}selected{% endif %}" onclick="$.cookie('edit_mode', null, { path: '/', expires: -1 }); location.reload(true);">
                <div class="header_icon"></div>
                <div class="header_text">{% trans "view" %}</div>
            </div>
        </div>
    

    Where myapp_various_tags.py is:

    from django.template.defaulttags import register
    @register.filter
    def get_item(dictionary, key):
        return dictionary.get(key)
    

    Possible it's not "true way" but all of this is just works.

    Also it will be good to do the same (all fields is read-only) with add/change page of Entity instance.

    django admin: separate read-only view and change view