web-dev-qa-db-fra.com

Django admin - changer le texte d'affichage ForeignKey

Comment puis-je changer le texte d'affichage dans select tout en sélectionnant un champ qui est ForeignKey?.

Tout le monde peut donner un indice?

35
robos85

Eh bien, si vous souhaitez qu’elle ne prenne effet que dans admin, et non globalement, vous pouvez créer une sous-classe ModelChoiceField personnalisée, l’utiliser dans une ModelForm personnalisée, puis définir la classe admin appropriée pour qu’elle utilise votre formulaire personnalisé . qui a FK selon le modèle Person utilisé par @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)
51
Botond Béres

Une autre façon de le faire (utile lorsque vous modifiez votre requête):

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)

"utilisateur" est le nom du champ que vous souhaitez remplacer. Cette solution vous offre un avantage: vous pouvez également remplacer le jeu de requêtes (par exemple, vous voulez User.objects.filter (username__startswith = 'a'))

Avertissement: solution trouvée sur http://markmail.org/message/t6lp7iqnpzvlt6qp et testée.

45
alekwisnia

Les nouvelles versions de Django supportent cela, ce qui peut être traduit avec gettext:

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

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

vous devez définir ce que vous voulez afficher dans la méthode unicode de votre modèle (où est la clé étrangère).

Cordialement,

9
Enrique San Martín

Vous pouvez également accomplir cela directement à partir de votre instance admin.ModelAdmin en utilisant label_from_instance. Par exemple:

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

Une alternative à la première réponse:

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

En vous appuyant sur les autres réponses, voici un petit exemple pour ceux qui ont ManyToManyField. Nous pouvons également remplacer label_from_instance directement dans 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)
    ...

Je suppose que cela fonctionnerait également pour formfield_for_foreignkey().

De la docs

... label_from_instance. Cette méthode recevra un objet de modèle et devrait renvoyer une chaîne appropriée pour le représenter.

0
djvg

Je viens de découvrir que vous pouvez remplacer le jeu de requêtes par un autre, voire même le supprimer et le remplacer par une liste de choix. Je le fais dans le change_view.

Dans cet exemple, je laisse le parent définir la valeur de retour, puis en extraire le champ spécifique et définir .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
0
James S