Django Admin- disable Editing and remove “Save” buttons for a specific model

前端 未结 9 1214
眼角桃花
眼角桃花 2020-12-24 07:39

I have a Django Model which I wish to be only readonly. No adds and edits allowed.

I have marked all fields readonly and overridden has_add_permission in ModelAdmin

相关标签:
9条回答
  • 2020-12-24 07:54

    For Django 1.11:

    def has_add_permission(self, request, obj=None):
        return False
    
    def changeform_view(self, request, object_id=None, form_url='', extra_context=None):
        extra_context = extra_context or {}
        extra_context['show_save_and_continue'] = False
        extra_context['show_save'] = False
        return super(YourModelAdmin, self).changeform_view(request, object_id, extra_context=extra_context)
    
    0 讨论(0)
  • 2020-12-24 08:00

    Updated answer using Django 1.8 (Python 3 syntax).

    There are three things to do:
    1) extend the admin change form template, adding an if to conditionally suppress the submit buttons
    2) override admin.ModelAdmin.change_view() and set a context var for the template if to read
    3) prohibit unwanted POST requests (from DOM hacking, curl/Postman)


    MyProject/my_app/templates/admin/my_app/change_form.html

    {% extends "admin/change_form.html" %}
    {% load admin_modify %}
    {% block submit_buttons_top %}{% if my_editable %}{% submit_row %}{% endif %}{% endblock %}
    {% block submit_buttons_bottom %}{% if my_editable %}{% submit_row %}{% endif %}{% endblock %}
    

    MyProject/my_app/admin.py (MyModelAdmin)

    def change_view(self, request, object_id, form_url='', extra_context=None):
      obj = MyModel.objects.get(pk=object_id)
      editable = obj.get_status() == 'Active'
    
      if not editable and request.method == 'POST':
        return HttpResponseForbidden("Cannot change an inactive MyModel")
    
      more_context = {
        # set a context var telling our customized template to suppress the Save button group
        'my_editable': editable,
      }
      more_context.update(extra_context or {})
      return super().change_view(request, object_id, form_url, more_context)
    
    0 讨论(0)
  • 2020-12-24 08:03

    Based on the excellent answer from @mat_gessel, here's my solution:

    The main differences are UX'y:

    • use messages and redirect (with reversing-admin-urls), rather than HttpResponseForbidden to prevent a save
    • define get_readonly_fields conditionally to prevent un-saveable inputs being displayed

    Also:

    • override change_form.html app-wide, because read_only is such a useful, non-invasive enhancement
    • define has_delete_permission (may not be required by the OP)
    • test request.method != 'GET' to prevent PATCH and friends (not altogether sure if this is required, tbh)

    my_app/admin.py

    from django.core.urlresolvers import reverse
    from django.shortcuts import redirect
    
    from django.contrib import admin
    from django.contrib import messages
    
    
    class MyModelAdmin(admin.ModelAdmin):
        # let's assume two fields...
        fields = (field1, field2)
    
        def changeform_view(self, request, object_id=None, form_url='', extra_context=None):
            if object_id:
                extra_context = extra_context or {}
                extra_context['read_only'] = True
    
                if request.method != 'GET':
                    messages.error(request, "Cannot edit a MyModel object")
                    return redirect(
                        reverse('admin:myapp_mymodel_change', args=[object_id])
                    )
    
            return super(MyModelAdmin, self).changeform_view(request, object_id, extra_context=extra_context)
    
        def has_delete_permission(self, request, obj=None):
            return False
    
        def get_readonly_fields(self, request, obj=None):
            if obj:
                # display all fields as text, rather than inputs
                return (field1, field2)
            else:
                return []
    

    admin/change_form.html

    {% extends "admin/change_form.html" %}
    {% load admin_modify %}
    {# remove the save buttons if read_only is truthy #}
    {% block submit_buttons_top %}{% if not read_only %}{% submit_row %}{% endif %}{% endblock %}
    {% block submit_buttons_bottom %}{% if not read_only %}{% submit_row %}{% endif %}{% endblock %}
    

    (Tested on Django 1.9: heads up: some imports have moved since then, eg reverse)

    0 讨论(0)
  • 2020-12-24 08:04

    I had same problem. I fixed it in admin.py

    from django.contrib.admin.templatetags.admin_modify import register, submit_row as original_submit_row
    
    @register.inclusion_tag('admin/submit_line.html', takes_context=True)
    def submit_row(context):
    ''' submit buttons context change '''
    ctx = original_submit_row(context)
    ctx.update({
        'show_save_and_add_another': context.get('show_save_and_add_another',
                                                 ctx['show_save_and_add_another']),
        'show_save_and_continue': context.get('show_save_and_continue',
                                              ctx['show_save_and_continue']),
        'show_save': context.get('show_save',
                                 ctx['show_save']),
        'show_delete_link': context.get('show_delete_link', ctx['show_delete_link'])
    })
    return ctx
    

    In MyModelAdmin class, add following function

    @classmethod
    def has_add_permission(cls, request):
        ''' remove add and save and add another button '''
        return False
    
    def change_view(self, request, object_id, extra_context=None):
        ''' customize add/edit form '''
        extra_context = extra_context or {}
        extra_context['show_save_and_continue'] = False
        extra_context['show_save'] = False
        return super(MyModelAdmin, self).change_view(request, object_id, extra_context=extra_context)
    
    0 讨论(0)
  • 2020-12-24 08:05

    I had the same problem - the easiest way to do this, is to include some custom JS.

    In you admin.py file include

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

    Then in your admin.js file, include the following JS.

    (function($) {
        $(document).ready(function($) {
             $(".submit-row").hide()
        });
    })(django.jQuery);
    

    The row is gone - it should work in all versions of Django too.

    0 讨论(0)
  • 2020-12-24 08:09

    You could try this package Django Admin View Permission. This package adds a view permission for the specified models and handles the other stuff automatically.

    0 讨论(0)
提交回复
热议问题