64π
If you want it to take effect only in admin, and not globally, then you could create a custom ModelChoiceField
subclass, use that in a custom ModelForm
and then set the relevant admin class to use your customized form.
Using an example which has a ForeignKey to the Person
model used by @Enrique:
class Invoice(models.Model):
person = models.ForeignKey(Person)
....
class InvoiceAdmin(admin.ModelAdmin):
form = MyInvoiceAdminForm
class MyInvoiceAdminForm(forms.ModelForm):
person = CustomModelChoiceField(queryset=Person.objects.all())
class Meta:
model = Invoice
class CustomModelChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
return "%s %s" % (obj.first_name, obj.last_name)
61π
Another way of doing so (useful when you change your queryset):
class MyForm(forms.Form):
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
self.fields['user'].queryset = User.objects.all()
self.fields['user'].label_from_instance = lambda obj: "%s %s" % (obj.last_name, obj.first_name)
'user'
is the name of field you want to override. This solution gives you one advantage: you can override queryset as well (e.g. you want User.objects.filter(username__startswith='a')
)
Disclaimer: solution found on http://markmail.org/message/t6lp7iqnpzvlt6qp and tested.
- [Django]-How to use Python type hints with Django QuerySet?
- [Django]-Switching to PostgreSQL fails loading datadump
- [Django]-Celery Flower Security in Production
19π
Newer versions of django support this, which can be translated with gettext:
models.ForeignKey(ForeignStufg, verbose_name='your text')
- [Django]-Fighting client-side caching in Django
- [Django]-Django: Use of DATE_FORMAT, DATETIME_FORMAT, TIME_FORMAT in settings.py?
- [Django]-Django REST Framework custom fields validation
18π
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)
- [Django]-Where does pip install its packages?
- [Django]-Converting timezone-aware datetime to local time in Python
- [Django]-Running django tutorial tests fail β No module named polls.tests
12π
See https://docs.djangoproject.com/en/1.3/ref/models/instances/#unicode
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
def __unicode__(self):
return u'%s %s' % (self.first_name, self.last_name)
you have to define what you want to display in the unicode method of your model (where is the ForeignKey).
Regards,
- [Django]-Can't install via pip because of egg_info error
- [Django]-Creating my own context processor in django
- [Django]-How to output Django queryset as JSON?
2π
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, subclassModelChoiceField
and overridelabel_from_instance
. This method will receive a model object and should return a string suitable for representing it.
- [Django]-Django modelform NOT required field
- [Django]-Django: Grab a set of objects from ID list (and sort by timestamp)
- [Django]-Permission denied β nginx and uwsgi socket
1π
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)
- [Django]-How to chcek if a variable is "False" in Django templates?
- [Django]-Django bulk_create with ignore rows that cause IntegrityError?
- [Django]-Change a form value before validation in Django form
1π
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
- [Django]-How to understand lazy function in Django utils functional module
- [Django]-What are the differences between django-tastypie and djangorestframework?
- [Django]-Running a specific test case in Django when your app has a tests directory
0π
I just found that you can replace the queryset with another queryset, or even remove the queryset and replace it with a choices list. I do this in the change_view
.
In this example, I let the parent set up the return value, then grab the specific field from it and set .choices
:
def change_view(self, request, object_id, form_url='', extra_context=None):
#get the return value which includes the form
ret = super().change_view(request, object_id, form_url, extra_context=extra_context)
# let's populate some stuff
form = ret.context_data['adminform'].form
#replace queryset with choices so that we can specify the "n/a" option
form.fields['blurb_location'].choices = [(None, 'Subscriber\'s Location')] + list(models.Location.objects.filter(is_corporate=False).values_list('id', 'name').order_by('name'))
form.fields['blurb_location'].queryset = None
return ret
- [Django]-Can I Make a foreignKey to same model in django?
- [Django]-Handle `post_save` signal in celery
- [Django]-How to create table during Django tests with managed = False