web-dev-qa-db-de.com

Django-Admin - Anzeigetext für ForeignKey ändern

Wie kann ich den Anzeigetext in select ändern, während ich ein Feld auswählt, das als ForeignKey fungiert? Ich muss nicht nur den Namen von FK anzeigen, sondern auch den Namen des übergeordneten Elements.

Jeder kann einen Hinweis geben?

35
robos85

Wenn Sie möchten, dass es nur in admin und nicht global wirksam wird, können Sie eine benutzerdefinierte ModelChoiceField-Unterklasse erstellen, diese in einer benutzerdefinierten ModelForm verwenden und dann die entsprechende Admin-Klasse so einstellen, dass sie Ihr benutzerdefiniertes Formular verwendet welches FK zu dem von @Enrique verwendeten Person-Modell hat:

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)
51
Botond Béres

Eine andere Möglichkeit (nützlich, wenn Sie Ihr Abfrageset ändern):

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)

'Benutzer' ist der Name des Feldes, das Sie überschreiben möchten. Diese Lösung bietet Ihnen einen Vorteil: Sie können auch queryset überschreiben (z. B. möchten Sie User.objects.filter (username__startswith = 'a')).

Haftungsausschluss: Lösung auf http://markmail.org/message/t6lp7iqnpzvlt6qp gefunden und getestet.

45
alekwisnia

Neuere Versionen von Django unterstützen dies, das mit gettext übersetzt werden kann:

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

Siehe https://docs.djangoproject.com/de/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)

sie müssen festlegen, was in der Methode unicode Ihres Modells angezeigt werden soll (wobei der ForeignKey steht).

Grüße,

9

Sie können dies auch direkt von Ihrer admin.ModelAdmin-Instanz aus mit label_from_instance ausführen. Zum Beispiel:

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)
3
radtek

Eine Alternative zur ersten Antwort:

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)
1
C. Bartz

Aufbauend auf den anderen Antworten, hier ein kleines Beispiel für diejenigen, die sich mit einer ManyToManyField beschäftigen. Wir können label_from_instance auch direkt in formfield_for_manytomany() überschreiben:

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

Ich denke, das würde auch für formfield_for_foreignkey() funktionieren.

Aus den docs

... label_from_instance. Diese Methode erhält ein Modellobjekt und sollte eine für die Darstellung geeignete Zeichenfolge zurückgeben.

0
djvg

Ich habe gerade festgestellt, dass Sie das Queryset durch ein anderes Queryset ersetzen können, oder sogar das Queryset entfernen und durch eine Auswahlliste ersetzen können. Ich mache das in der change_view.

In diesem Beispiel ließ ich das übergeordnete Element den Rückgabewert einrichten, schnappte mir dann das spezifische Feld und stellte .choices ein:

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
0
James S