The answer by @Slipstream shows how to implement the solution, viz. by overriding the attributes for the formfield's widget, but, in my opinion, get_form
is not the most logical place to do this.
The answer by @cethegeek shows where to implement the solution, viz. in an extension of formfield_for_dbfield
, but does not provide an explicit example.
Why use formfield_for_dbfield
? Its docstring suggests that it is the designated hook for messing with form fields:
Hook for specifying the form Field instance for a given database Field instance.
It also allows for (slightly) cleaner and clearer code, and, as a bonus, we can easily set additional form Field
attributes, such as initial
value and/or disabled
(example here), by adding them to the kwargs
(before calling super
).
So, combining the two answers (assuming the OP's models are ModelA
and ModelB
, and the ForeignKey
model field is named b
):
class ModelAAdmin(admin.ModelAdmin):
def formfield_for_dbfield(self, db_field, request, **kwargs):
# optionally set Field attributes here, by adding them to kwargs
formfield = super().formfield_for_dbfield(db_field, request, **kwargs)
if db_field.name == 'b':
formfield.widget.can_add_related = False
formfield.widget.can_change_related = False
formfield.widget.can_delete_related = False
return formfield
# Don't forget to register...
admin.site.register(ModelA, ModelAAdmin)
NOTE: If the ForeignKey
model field has on_delete=models.CASCADE
, the can_delete_related
attribute is False
by default, as can be seen in the source for RelatedFieldWidgetWrapper
.