Today I had the same problem, and I think I found an acceptable way to solve it. Here is what I did:
I needed to make inlines deleted only if a certain field had a certain value. In particular, since I am dealing with generic tasks and assignments, only missed tasks should be deleted. In terms of the model:
class Task(models.Model): STATUS_CHOICES = ( ('PND', 'Pending'), ('ACC', 'Accepted'), ) status = models.CharField( ----> If this != 'PND', inline instance max_length=3, should not be deletable choices=STATUS_CHOICES, default=STATUS_CHOICES[0][0])
Since I could not use has_delete_permission in my admin.TabularInline class, since this applies to the entire set of fields (i.e. to all built-in lines), and not to a single line, I went through the pattern override path:
tabular.html: 44-62 (original)
[...] {% for fieldset in inline_admin_form %} {% for line in fieldset %} {% for field in line %} {% if not field.field.is_hidden %} <td{% if field.field.name %} class="field-{{ field.field.name }}"{% endif %}> {% if field.is_readonly %} <p>{{ field.contents }}</p> {% else %} {{ field.field.errors.as_ul }} {{ field.field }} {% endif %} </td> {% endif %} {% endfor %} {% endfor %} {% endfor %} {% if inline_admin_formset.formset.can_delete %} <td class="delete">{% if inline_admin_form.original %}{{ inline_admin_form.deletion_field.field }}{% endif %}</td> {% endif %} [...]
tabular.html (overridden)
[...] {% for fieldset in inline_admin_form %} {% for line in fieldset %} {% for field in line %} {% if not field.field.is_hidden %} <td{% if field.field.name %} class="field-{{ field.field.name }}"{% endif %}> {% if field.is_readonly %} <p>{{ field.contents }}</p> {% else %} {% include "admin/includes/field.html" with is_tabular=True %} {% endif %} </td> {% endif %} {% endfor %} {% endfor %} <!-- Custom deletion logic, only available for non-accepted objects --> {% for line in fieldset %} {% for field in line %} {% if field.field.name == "status" %} {% if field.field.value == "PND" %} <td class="delete">{% if inline_admin_form.original %}{{ inline_admin_form.deletion_field.field }}{% endif %}</td> {% else %} <td class="delete"><input type="checkbox" disabled="disabled"> <img src="/static/admin/img/icon_alert.gif" data-toggle="tooltip" class="title-starter" data-original-title="Can't remove accepted tasks" /> </td> {% endif %} {% endif %} {% endfor %} {% endfor %} {% endfor %} <!-- Classic deletion, removed {% if inline_admin_formset.formset.can_delete %} <td class="delete">{% if inline_admin_form.original %}{{ inline_admin_form.deletion_field.field }}{% endif %}</td> {% endif %} --> [...]
As a result (non-standard graphics, as I use django-admin-bootstrap ):

Strictly speaking of "elegance," I have to go through the line fields twice to make it work, but I have not found a better way than reading this field value directly. I could not have anything like {{ line.fields.0.status }} or {{ line.fields.status }} . If anyone could point to direct syntax, I would gladly update my solution.
In any case, since it still works, and itโs not so bad, I will be fine with this method until nothing works better.