Search code examples
pythondjangodjango-parler

Django Admin how to change text in relations field


I have the following code:

models.py

from django.db import models
from parler.models import TranslatableModel, TranslatedFields

class Federation(TranslatableModel):
    translations = TranslatedFields(
        name = models.CharField('name', max_length=50)
    )
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

class Athlete(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    federation = models.ForeignKey('Federation', on_delete=models.SET_NULL, null=True)
    height = models.IntegerField();
    weight = models.IntegerField();
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

admin.py

from django.contrib import admin
from parler.admin import TranslatableAdmin

from .models import Athlete, Federation

class AthleteAdmin(admin.ModelAdmin):
    list_display = ['first_name', 'last_name', 'height', 'weight', 'get_federation_name']
    fields = ['first_name', 'last_name', 'height', 'weight', 'federation']

    def get_federation_name(self, obj):
        obj.federation.set_current_language('en')
        return obj.federation.name
    get_federation_name.short_description = 'Federation'

class FederationAdmin(TranslatableAdmin):
    search_fields = ['translations__name']
    list_display = ['name']
    fields = ['name']

admin.site.register(Federation, FederationAdmin)
admin.site.register(Athlete, AthleteAdmin)

The federation field is shown as a list but the text in the select menu is shown as "Federation object." For the list, I created a function to fetch the data from related Federation model's translation relation. I want to do the same with the form fields. If I get this to work in form fields without a function, I will also change the list display to work the same way.

I am new to Python and Django (first time) and I can't seem to find a solution to this problem.

Thank you!


Solution

  • By default it uses the __str__() method of the object. So the easiest way to change this is to set this method. For instance:

    class Federation(models.Model):
        ...
    
        def __str__(self):
            return "{0} ({1})".format(self.translation, self.created_at)
    

    Another way — if you don't want to override the __str__ method — would be to override the label_from_instance of the form Field itself. But it's more tricky.

    def _federation_label_from_instance(self, obj):
        return "{0} ({1})".format(obj.translation, obj.created_at)
    
    class AthleteAdmin(admin.ModelAdmin):
        ...
    
        def formfield_for_foreignkey(self, db_field, request, **kwargs):
            formfield = super().form_field(db_field, request, **kwargs)
            if db_field.name == 'federation':
                formfield.label_from_instance = _federation_label_from_instance
            return formfield