I have models A
, B
, and AB
.
A
objects have a ManyToManyField
called A.m
that can link to many B
objects, through my intermediary model AB
.
I have a very nice TabularInline
section full of AB
objects, on my admin page for my A
model.
All is well. Except that the TabularInline
section shows "Add" and "Change" buttons for the B
object in each AB
object's row, and I want to remove those buttons. I still want to be able to add, change, and delete AB
objects rows, just not the B
objects they reference.
I have tried setting the can_add_related
, can_change_related
, can_delete_related
attributes to False
, but this does nothing.
class ABInline(admin.TabularInline):
model = AB
def get_form(self, request, obj=None, **kwargs):
form = super(ABInline, self).get_form(request, obj, **kwargs)
form.base_fields['m'].widget.can_add_related = False
form.base_fields['m'].widget.can_change_related = False
form.base_fields['m'].widget.can_delete_related = False
return form
Is this a bug? Or is there a different way to accomplish this for TabularInline
fields?
The OP's idea of setting the widget's attributes should work.
The basic idea is as follows:
The actual form field in the TabularInline
for AB
that allows you to select the B
object is a ModelChoiceField. This field has a Select widget, wrapped in a RelatedFieldWidgetWrapper. The latter controls the "add" and "change" (or "edit") buttons next to the select box. To remove these buttons, set the widget's can_add_related
and can_change_related
attributes to False
.
This is actually what the OP attempted to do. However, the OP tried to extend get_form
, but that method is only available on a ModelAdmin
, not on the TabularInline
, as far as I know (source).
Instead of using get_form
, we can extend e.g. formfield_for_dbfield
(source) on the TabularInline
, as illustrated below (based on OP's example):
class ABInline(admin.TabularInline):
model = AB
def formfield_for_dbfield(self, db_field, request, **kwargs):
formfield = super(ABInline, self).formfield_for_dbfield(
db_field, request, **kwargs)
if db_field.name == 'b':
# Assuming AB.b is the ForeignKey to B
formfield.widget.can_add_related = False
formfield.widget.can_change_related = False
# formfield.widget.can_delete_related = False # default is already False
return formfield
Here we assume that the OP's AB
model looks something like this:
class AB(models.Model):
a = models.ForeignKey(to='A', ...)
b = models.ForeignKey(to='B', ...)
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With