Подтвердить что ты не робот

Django admin - изменить текст отображения ForeignKey

Как я могу изменить отображаемый текст при выборе при выборе поля, которое является ForeignKey? Мне нужно отобразить не только имя FK, но и имя его родителя.

Кто-нибудь может дать ключ?

4b9b3361

Ответ 1

Хорошо, если вы хотите, чтобы он вступил в силу только в admin, а не во всем мире, тогда вы можете создать пользовательский подкласс ModelChoiceField, использовать его в пользовательском ModelForm, а затем установить соответствующий класс администратора для использования вашей индивидуальной формы, Пример, который имеет FK для модели Person, используемой @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)

Ответ 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 и протестировано.

Ответ 3

Более новые версии django поддерживают это, которое можно перевести с помощью gettext:

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

Ответ 4

См. 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).

Привет,

Ответ 5

Альтернатива первому ответу:

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

Вы также можете сделать это прямо из вашего admin.ModelAdmin например, с использованием label_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)

Ответ 7

Я просто обнаружил, что вы можете заменить набор запросов другим набором запросов или даже удалить набор запросов и заменить его списком выбора. Я делаю это в 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 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\ Location')] + list(models.Location.objects.filter(is_corporate=False).values_list('id', 'name').order_by('name'))
        form.fields['blurb_location'].queryset = None

        return ret

Ответ 8

Основываясь на других ответах, вот небольшой пример для тех, кто имеет дело с 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().

Из документов:

... label_from_instance. Этот метод получит модельный объект и должен вернуть строку, подходящую для ее представления.