如何在 Django Admin 中更改 ForeignKey 显示文本?
Posted
技术标签:
【中文标题】如何在 Django Admin 中更改 ForeignKey 显示文本?【英文标题】:How to change ForeignKey display text in the Django Admin? 【发布时间】:2011-10-13 18:49:42 【问题描述】:如何在选择ForeignKey
字段时更改<select>
字段中的显示文本?
我不仅需要显示ForeignKey
的名称,还需要显示其父级的名称。
【问题讨论】:
【参考方案1】:如果您希望它仅在管理中生效,而不是全局生效,那么您可以创建一个自定义 ModelChoiceField
子类,在自定义 ModelForm
中使用它,然后设置相关的管理类以使用您的自定义表单。
使用具有 @Enrique 使用的 Person
模型的 ForeignKey 的示例:
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)
【讨论】:
【参考方案2】:另一种方法(在更改查询集时很有用):
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'
是您要覆盖的字段的名称。此解决方案为您提供了一个优势:您也可以覆盖查询集(例如,您想要User.objects.filter(username__startswith='a')
)
免责声明:在http://markmail.org/message/t6lp7iqnpzvlt6qp 上找到并经过测试的解决方案。
【讨论】:
老而金!谢谢!! 这确实有助于非管理员表单,并通过避免自定义类来保持简单。 像魅力一样工作! 不知道为什么它对我不起作用@Django 2.1.9,但所选答案有效。【参考方案3】:较新版本的django支持这个,可以用gettext翻译:
models.ForeignKey(ForeignStufg, verbose_name='your text')
【讨论】:
记录在docs.djangoproject.com/en/dev/topics/db/models/…。 这实际上解决了与被问到的问题不同的问题。【参考方案4】:您也可以使用label_from_instance
直接从您的admin.ModelAdmin
实例完成此操作。例如:
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)
【讨论】:
这很好用。唯一的问题是,在使用管理员“+”选项添加值后,它仍然显示“field_name(id)”值。重新加载页面后,它显示正确。知道如何让它正确显示而无需重新加载?【参考方案5】:见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)
您必须在模型的 unicode 方法中定义要显示的内容(ForeignKey 在哪里)。
问候,
【讨论】:
我知道,但我想在其他地方的 admin 上只更改 1 个位置,不应该更改,因为这种方法对我不利。 @robos85:检查我的答案,了解您要查找的内容。您还应该更新您的问题。【参考方案6】:在其他答案的基础上,这里有一个小例子,供那些处理ManyToManyField
的人使用。
我们可以直接在formfield_for_manytomany()中覆盖label_from_instance
:
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
这也适用于formfield_for_foreignkey()
或formfield_for_dbfield()。
来自ModelChoiceField docs:
将调用模型的
__str__()
方法来生成对象的字符串表示形式,以用于字段的选择。要提供自定义表示,请继承ModelChoiceField
并覆盖label_from_instance
。此方法将接收一个模型对象,并应返回一个适合表示它的字符串。
【讨论】:
【参考方案7】:第一个答案的替代方案:
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)
【讨论】:
【参考方案8】:我刚刚发现您可以用另一个查询集替换查询集,甚至可以删除查询集并用选择列表替换它。我在change_view
中执行此操作。
在这个例子中,我让父级设置返回值,然后从中获取特定字段并设置.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 Admin 中更改 ForeignKey 显示文本?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 django admin 中显示多个模型的更改列表?
如何在 Django Admin 中更改 OneToOne 模型字段默认消息?