62

I am using django 1.4 and I have a many2many field, so when creating the admin site I wanted to add this field as an inline, here is some code:

class SummaryInline(admin.TabularInline):
    model = ParserError.summaries.through


class MyClassAdmin(admin.ModelAdmin):
    list_display = ('classifier', 'name', 'err_count', 'supported')
    fields = ('classifier', 'name', 'err_count', 'err_classifier', 'supported')
    inlines = (SummaryInline,)
    readonly_fields = ('classifier', 'err_count')

So my question is, how can I make the inline field readonly?

Hassek
  • 8,715
  • 6
  • 47
  • 59

4 Answers4

79

After a while of trying to find the name I figured out thanks to this answer, so I checked the names at self.opts.local_fields and found the name of the middle table and added it to readonly_fields, setting can_delete to False.

class SummaryInline(admin.TabularInline):
    model = ParserError.summaries.through
    readonly_fields = ('myclasssummary',)
    can_delete = False

pretty simple but took me a while so I figured out it was a good idea to add it here.

Community
  • 1
  • 1
Hassek
  • 8,715
  • 6
  • 47
  • 59
  • 1
    I'm not sure you can/should use `can_delete = False`. You can use `def has_delete_permission(self, request, obj=None): return False` instead. See docs: https://docs.djangoproject.com/en/2.1/ref/contrib/admin/ – Rustam Guliev Aug 28 '18 at 23:33
  • 2
    what is `myclasssummary` in the `readonly_fields`? is it table name or field name from `summaries` model? – Raju Singh Dec 17 '18 at 05:43
  • @tamarabyte answer worked for me, not this one. Maybe change the accepted answer ? – Arnaud P Jan 05 '22 at 17:00
  • @RustamGuliev I can't see anything in the documentation that says `can_delete` shouldn't be used. – alstr Nov 28 '22 at 09:44
47

Additionally, if you do not want the ability to add/delete the rows, you can add these definitions.

def has_add_permission(self, request, obj=None):
    return False

def has_delete_permission(self, request, obj=None):
    return False
Keval Prabhu
  • 990
  • 8
  • 10
36

You can make the entire inline readonly by adding:

class UnitsInline(admin.TabularInline):

    def has_change_permission(self, request, obj=None):
        return False

This will prevent anyone from editing the entry from the admin.

Another example that prevents, adding, deletion and displays all the inline fields as readonly:

class ReadOnlyInline(admin.TabularInline):
    def has_change_permission(self, request, obj=None):
        return False

    def has_add_permission(self, request, obj=None):
        return False

    def has_delete_permission(self, request, obj=None):
        return False

    def get_readonly_fields(self, request, obj=None):
        return list(super().get_fields(request, obj))
tamarabyte
  • 1,144
  • 13
  • 19
  • I'm using django 1.11 and this causes no related records to show. I guess because I can't edit them? – Matt Oct 31 '19 at 14:15
  • 1
    You'll have to add whatever fields you want to show up for the inline as readonly fields. I'll update my answer with an example. – tamarabyte Oct 31 '19 at 22:22
  • For me, this prevents the inline from being rendered even for folks that have those permissions. – Daniel Schaffer Mar 16 '21 at 18:34
  • 1
    This worked for me, but the `get_readonly_fields` was not required. Also make sure you specify `model`. – alstr Jun 09 '21 at 13:11
  • @Matt I'm also using 1.11 and have the same problem. If I'm not mistaken, I believe this was fixed last year with this ticket in a much newer version of Django -- https://code.djangoproject.com/ticket/31867 – Sean D. Oct 04 '22 at 19:45
4

Thanks Keval Prabhu

class UnitsInline(admin.TabularInline):
    model = Units
    extra = 0
    verbose_name = 'Units'
    verbose_name_plural = 'Units of company'
    
    def has_add_permission(self, request, obj=None):
        return False
    def has_delete_permission(self, request, obj=None):
        return False
VisioN
  • 143,310
  • 32
  • 282
  • 281