Django admin - 更改ForeignKey显示文本

时间:2011-07-26 21:18:34

标签: django django-admin

如何在选择字段为ForeignKey时更改select中的显示文本? 我不仅需要显示FK的名称,还需要显示它的父名称。

任何人都可以提供线索吗?

8 个答案:

答案 0 :(得分:51)

如果您希望它仅在admin中生效,而不是全局生效,那么您可以创建自定义ModelChoiceField子类,在自定义ModelForm中使用它,然后将相关的管理类设置为使用您的自定义表单。 以FK为例,介绍@Enrique使用的Person模型:

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)

答案 1 :(得分:47)

另一种方法(在更改查询集时很有用):

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上找到并经过测试的解决方案。

答案 2 :(得分:10)

较新版本的django支持此功能,可以使用gettext进行翻译:

models.ForeignKey(ForeignStufg, verbose_name='your text')

答案 3 :(得分:9)

请参阅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)。

此致

答案 4 :(得分:4)

您也可以使用admin.ModelAdminlabel_from_instance实例直接完成此操作。例如:

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 obj: "{} {}".format(obj.id, obj.first_name)
        return form


admin.site.register(Invoice, InvoiceAdmin)

答案 5 :(得分:1)

第一个答案的替代方案:

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)

答案 6 :(得分:0)

我刚发现您可以将查询集替换为另一个查询集,甚至删除查询集并将其替换为选项列表。我在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

答案 7 :(得分:0)

在其他答案的基础上,这是处理ManyToManyField的人的一个小例子。我们也可以直接在label_from_instance中覆盖formfield_for_manytomany()

class MyAdmin(admin.ModelAdmin):
    ...
    def formfield_for_manytomany(self, db_field, request, **kwargs):
        formfield = super(MyAdmin, self).formfield_for_manytomany(db_field, request, **kwargs)
        # For example, we can add the instance id to the original string
        formfield.label_from_instance = lambda instance: '{} (id={})'.format(instance.__str__(), instance.id)
    ...

我想这对formfield_for_foreignkey()也适用。

docs

  

... label_from_instance。此方法将收到一个模型对象,并且   应该返回一个适合表示它的字符串。