Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I make list_filter in django admin to only show referenced ForeignKeys?

I have a django application which has two models like this:

class MyModel(models.Model):     name = models.CharField()     country = models.ForeignKey('Country')  class Country(models.Model):     code2 = models.CharField(max_length=2, primary_key=True)     name = models.CharField() 

The admin class for MyModel looks like this:

class MyModelAdmin(admin.ModelAdmin):     list_display = ('name', 'country',)     list_filter = ('country',) admin.site.register(models.MyModel, MyModelAdmin) 

The Country table contains ~250 countries. Only a handful of countries are actually referenced by some MyModel instance.

The problem is that the list filter in the django admin lists ALL countries in the filter panel. Listing all countries (and not just those that are referenced by an instance) pretty much defeats the purpose of having the list filter in this case.

Is there some to only display the countries referenced by MyModel as choices in the list filter? (I use Django 1.3.)

like image 500
m000 Avatar asked Aug 31 '12 12:08

m000


People also ask

What is List_filter in Django admin?

For Django 1.4-1.7, list_filter allows you to use a subclass of SimpleListFilter . It should be possible to create a simple list filter that lists the values you want.

What is Admin ModelAdmin in Django?

One of the most powerful parts of Django is the automatic admin interface. It reads metadata from your models to provide a quick, model-centric interface where trusted users can manage content on your site. The admin's recommended use is limited to an organization's internal management tool.

Is Django's admin interface customizable if yes then how?

In this article, we will discuss how to enhance Django-admin Interface. Let us create an app called state which has one model with the same name(state). When we register app to admin.py it shows like. Now lets' customize django admin according to available options.


2 Answers

As of Django 1.8, there is a built in RelatedOnlyFieldListFilter, which you can use to show related countries.

class MyModelAdmin(admin.ModelAdmin):     list_display = ('name', 'country',)     list_filter = (         ('country', admin.RelatedOnlyFieldListFilter),     ) 

For Django 1.4-1.7, list_filter allows you to use a subclass of SimpleListFilter. It should be possible to create a simple list filter that lists the values you want.

If you can't upgrade from Django 1.3, you'd need to use the internal, and undocumented, FilterSpec api. The Stack Overflow question Custom Filter in Django Admin should point you in the right direction.

like image 115
Alasdair Avatar answered Sep 20 '22 17:09

Alasdair


I know question was about Django 1.3 however you mentioned on soon upgrading to 1.4. Also to people, like me who was looking for solution for 1.4, but found this entry, i decided to show full example of using SimpleListFilter (available Django 1.4) to show only referenced (related, used) foreign key values

from django.contrib.admin import SimpleListFilter  # admin.py class CountryFilter(SimpleListFilter):     title = 'country' # or use _('country') for translated title     parameter_name = 'country'      def lookups(self, request, model_admin):         countries = set([c.country for c in model_admin.model.objects.all()])         return [(c.id, c.name) for c in countries]         # You can also use hardcoded model name like "Country" instead of          # "model_admin.model" if this is not direct foreign key filter      def queryset(self, request, queryset):         if self.value():             return queryset.filter(country__id__exact=self.value())         else:             return queryset  # Example setup and usage  # models.py from django.db import models  class Country(models.Model):     name = models.CharField(max_length=64)  class City(models.Model):     name = models.CharField(max_length=64)     country = models.ForeignKey(Country)  # admin.py from django.contrib.admin import ModelAdmin  class CityAdmin(ModelAdmin):     list_filter = (CountryFilter,)  admin.site.register(City, CityAdmin) 

In example you can see two models - City and Country. City has ForeignKey to Country. If you use regular list_filter = ('country',) you will have all the countries in the chooser. This snippet however filters only related countries - the ones that have at least one relation to city.

Original idea from here. Big thanks to author. Improved class names for better clarity and use of model_admin.model instead of hardcoded model name.

Example also available in Django Snippets: http://djangosnippets.org/snippets/2885/

like image 40
darklow Avatar answered Sep 19 '22 17:09

darklow