In models.py I have:
class User(modals.Model):
name = models.CharField(max_length=255)
image = models.ImageField(blank=True, null=True)
And in admin.py:
class UserAdmin(admin.ModelAdmin):
list_filter = ['image']
admin.site.register(User, UserAdmin)
I just want to filter Users by have image or not (null or empty string)
But django shows filter by image urls =)
Is there a way to make list_filter = ['image']
behave like boolean field?
Big thx for advices!
null=True will make the field accept NULL values. Blank values for Django field types such as DateTimeField or ForeignKey will be stored as NULL in the database.
Django allows the user of the admin site to filter the instances of a Model by adding the list_filter attribute to your ModelAdmin objects. You can find more information about the Django's filtering utilities in the official documentation, in the Django Admin Site section.
admin.py
class ImageListFilter(admin.SimpleListFilter):
title = _('Has photo')
parameter_name = 'has_photo'
def lookups(self, request, model_admin):
return (
('yes', _('Yes')),
('no', _('No')),
)
def queryset(self, request, queryset):
if self.value() == 'yes':
return queryset.filter(image__isnull=False).exclude(image='')
if self.value() == 'no':
return queryset.filter(Q(image__isnull=True) | Q(image__exact=''))
class UserAdmin(admin.ModelAdmin):
list_filter = [ImageListFilter]
As of Django 3.1, you can use EmptyFieldListFilter
as follows:
list_filter = (
("my_fk_field", admin.EmptyFieldListFilter),
)
See the docs for details. See the release notes as well.
The code is available here, if you need to customize it or backport it.
Based on MaxCore's answer, I created customised class that I can use to modify title and parameter name:
from django.contrib import admin
from django.utils.translation import ugettext_lazy as _
from django.db.models import Q
class NotNullFilter(admin.SimpleListFilter):
title = _('Filter title not set')
parameter_name = 'parameter name not set'
def lookups(self, request, model_admin):
return (
('not_null', _('Not empty only')),
('null', _('Empty only')),
)
def queryset(self, request, queryset):
if self.value() == 'not_null':
is_null_false = {
self.parameter_name + "__isnull": False
}
exclude = {
self.parameter_name: ""
}
return queryset.filter(**is_null_false).exclude(**exclude)
if self.value() == 'null':
is_null_true = {
self.parameter_name + "__isnull": True
}
param_exact = {
self.parameter_name + "__exact": ""
}
return queryset.filter(Q(**is_null_true) | Q(**param_exact))
class YoutubeNotNullFilter(NotNullFilter):
title = "Youtube"
parameter_name = "youtube_videoid"
K.H.'s approach of a base class that could be reused easily was really helpful for me. I couldn't get the written example to work, but with a small tweak it worked perfectly (Python 2.7, Django 1.10) to achieve this.
from django.contrib import admin
class NotNullFilter(admin.SimpleListFilter):
title = 'Filter title not set'
parameter_name = 'parameter name not set'
def lookups(self, request, model_admin):
return (
('not_null', 'Not empty only'),
('null', 'Empty only'),
)
def queryset(self, request, queryset):
filter_string = self.parameter_name + '__isnull'
if self.value() == 'not_null':
is_null_false = {
filter_string: False
}
return queryset.filter(**is_null_false)
if self.value() == 'null':
is_null_true = {
filter_string: True
}
return queryset.filter(**is_null_true)
class YoutubeNotNullFilter(NotNullFilter):
title = "Youtube"
parameter_name = "youtube_videoid"
class SomeVideoClass(admin.ModelAdmin):
...
list_filter = [YouTubeNotNullFilter, ...]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With