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?
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)
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.
Les nouvelles versions de Django supportent cela, ce qui peut être traduit avec gettext:
models.ForeignKey(ForeignStufg, verbose_name='your text')
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,
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)
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)
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.
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