Ace_Gentile
Ace_Gentile

Reputation: 244

Django admin: list_display/search_fields foreign key of a foreign key in admin view

I have a question for django programmer that should be quite easy but at the moment I cannot figure out how to solve.

I have these three models (I simplify as much as I can):

class Nations(models.Model):
    label = models.CharField(max_length=200)
    iso2 = models.CharField(max_length=2, unique=True)

class Cities(models.Model):
    label = models.CharField(max_length=200, null=True)
    country_code = models.ForeignKey(Nations, to_field='iso2', on_delete=models.SET_NULL, null=True, verbose_name='Nation')

class Person(models.Model):
    username = models.CharField(max_length=200, blank=False) 
    city = models.ForeignKey(Cities, on_delete=models.SET_NULL, null=True, blank=True)

As you can see, Person model is just connected with Cities model. What I need to do is to set PersonAdmin class in order to add in the admin view a column showing Nations.label value and make it searchable. In the example below I called this field city__country_code__label, just to make you figure out what I mean (but of course it doesn't work because there is no country_code object in Person model).

class PersonAdmin(admin.ModelAdmin):

  list_display = ('id', 'username', 'city', 'city__country_code__label')
  ordering = ('username',) 
  raw_id_fields = ('city',)
  search_fields = ['username', 'city__label', 'city__country_code__label']

[...]

how can I ask Django to do this?

Thanx in advance!

Upvotes: 4

Views: 7040

Answers (1)

Alasdair
Alasdair

Reputation: 308939

Add a method to your model admin that takes a person obj and returns the country label. Then add the method to list_display.

class PersonAdmin(admin.ModelAdmin):
    def country_label(self, obj):
        return obj.city.country_code.label

    list_display = ('id', 'username', 'city', 'country_label')
    list_select_related = ['city__country_code']
    ordering = ('username',) 
    raw_id_fields = ('city',)
    search_fields = ['username', 'city__label', 'city__country_code__label']

See the list_display docs for more info.

Note I have used list_select_related to reduce the number of SQL queries.

Upvotes: 7

Related Questions