How can I change the display text in a <select> field while selecting a field which is a ForeignKey?
I need to display not only the name of ForeignKey, but also the name of its parent.
How can I change the display text in a <select> field while selecting a field which is a ForeignKey?
I need to display not only the name of ForeignKey, but also the name of its parent.
You can also accomplish this straight from your admin.ModelAdmin instance using label_from_instance. For example:
class InvoiceAdmin(admin.ModelAdmin):
list_display = ['person', 'id']
def get_form(self, request, obj=None, **kwargs):
form = super(InvoiceAdmin, self).get_form(request, obj, **kwargs)
form.base_fields['person'].label_from_instance = lambda inst: "{} {}".format(inst.id, inst.first_name)
return form
admin.site.register(Invoice, InvoiceAdmin)
Building on the other answers, here's a small example for those dealing with a ManyToManyField.
We can override label_from_instance directly in formfield_for_manytomany():
class MyAdmin(admin.ModelAdmin):
def formfield_for_manytomany(self, db_field, request, **kwargs):
formfield = super().formfield_for_manytomany(db_field, request, **kwargs)
if db_field.name == 'person':
# For example, we can add the instance id to the original string
formfield.label_from_instance = lambda obj: f'{obj} ({obj.id})'
return formfield
This would also work for formfield_for_foreignkey() or formfield_for_dbfield().
From the ModelChoiceField docs:
The
__str__()method of the model will be called to generate string representations of the objects for use in the field’s choices. To provide customized representations, subclassModelChoiceFieldand overridelabel_from_instance. This method will receive a model object and should return a string suitable for representing it.
An alternative to the first answer:
class InvoiceAdmin(admin.ModelAdmin):
class CustomModelChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
return "%s %s" % (obj.first_name, obj.last_name)
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'person':
return self.CustomModelChoiceField(queryset=Person.objects)
return super(InvoiceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
By overriding formfield_for_foreignkey(), you can display the combination of foreign key and its parent to Django Admin without creating a custom "forms.ModelChoiceField" and a custom "forms.ModelForm" as shown below:
@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
def formfield_for_foreignkey(self, db_field, request, **kwargs):
formfield = super().formfield_for_foreignkey(db_field, request, **kwargs)
if db_field.name == "my_field":
formfield.label_from_instance = lambda obj: f'{obj} ({obj.my_parent})'
return formfield
In addition, this code below is with a custom "forms.ModelForm":
class MyModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['my_field'].label_from_instance = lambda obj: f'{obj} ({obj.my_parent})'
@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
form = MyModelForm
And, this code below is with a custom "forms.ModelChoiceField" and a custom "forms.ModelForm":
class CustomModelChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
return f'{obj} ({obj.my_parent})'
class MyModelForm(forms.ModelForm):
my_field = CustomModelChoiceField(queryset=MyField.objects.all())
@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
form = MyModelForm