Default filter in Django admin
class MyModelAdmin(admin.ModelAdmin):
def changelist_view(self, request, extra_context=None):
if not request.GET.has_key('decommissioned__exact'):
q = request.GET.copy()
q['decommissioned__exact'] = 'N'
request.GET = q
request.META['QUERY_STRING'] = request.GET.urlencode()
return super(MyModelAdmin,self).changelist_view(request, extra_context=extra_context)
Default filter in admin site
You'd need to create a custom list filter, inheriting from django.contrib.admin.filters.SimpleListFilter
and filtering on unclosed accounts by default. Something along these lines should work:
from datetime import date
from django.utils.translation import ugettext_lazy as _
from django.contrib.admin import SimpleListFilter
class IsClosedFilter(SimpleListFilter):
title = _('Closed')
parameter_name = 'closed'
def lookups(self, request, model_admin):
return (
(None, _('No')),
('yes', _('Yes')),
('all', _('All')),
)
def choices(self, cl):
for lookup, title in self.lookup_choices:
yield {
'selected': self.value() == lookup,
'query_string': cl.get_query_string({
self.parameter_name: lookup,
}, []),
'display': title,
}
def queryset(self, request, queryset):
if self.value() == 'closed':
return queryset.filter(isClosed=True)
elif self.value() is None:
return queryset.filter(isClosed=False)
class Admin(admin.ModelAdmin):
list_filter = [isClosedFilter]
django admin list data using default filter
You can override the get_queryset(…)
method [Django-doc] and work with:
# admin.py
@admin.register(Pizza)
class PizzaAdmin(admin.ModelAdmin):
list_display = ('id', 'name', 'price')
exclude = ('have_recipe',)
def get_queryset(self, *args, **kwargs):
return super().get_queryset(*args, **kwargs).filter(
have_recipe=True
)
You should also use @admin.register(Pizza)
as a decorator, so with a leading @
.
SimpleListFIlter Default
Had to do the same and stumbled upon your question. This is how I fixed it in my code (adapted to your example):
class CanceledFilter(SimpleListFilter):
title = 'Canceled'
# Parameter for the filter that will be used in the URL query.
parameter_name = 'canceled'
def lookups(self, request, model_admin):
return (
(2, 'All'),
(1, 'Yes'),
(0, 'No'),
)
def queryset(self, request, queryset):
if self.value() is None:
self.used_parameters[self.parameter_name] = 0
else:
self.used_parameters[self.parameter_name] = int(self.value())
if self.value() == 2:
return queryset
return queryset.filter(cancelled=self.value())
Some explanation is required. The querystring is just part of the URL, and exactly what the name implies: a query string. Your values come in as strings, not as booleans or integers. So when you call self.value()
, it returns a string.
If you examine the URL you get when you click on the Yes/No, when not using a custom list filter, you'll see it encodes it as 1/0, not True/False. I went with the same scheme.
For completeness and our future readers, I also added 2 for All. Without verifying, I assume that was None
before. But None
is also used when nothing is selected, which defaults to All. Except, in our case it needs to default to False
, so I had to pick a different value. If you don't need the All option, just remove the final if-block in the queryset
method, and the first tuple in the lookups
method.
With that out of the way, how does it work? The trick is in realising that self.value()
just returns:
self.used_parameters.get(self.parameter_name, None)
which is either a string, or None
, depending on whether the key is found in the dictionary or not. So that's the central idea: we make sure it contains integers and not strings, so that self.value()
can be used in the call to queryset.filter()
. Special treatment for the value for All, which is 2: in this case, just return queryset
rather than a filtered queryset. Another special value is None
, which means there is no key parameter_name
in the dictionary. In that case, we create one with value 0, so that False
becomes the default value.
Note: your logic was incorrect there; you want the non-cancelled by default, but you treat None
the same as True
. My version corrects this.
ps: yes, you could check for 'True'
and 'False'
rather than True
and False
in your querystring
method, but then you'd notice the correct selection would not be highlighted because the first elements in your tuple don't match up (you're comparing strings to booleans then). I tried making the first elements in the tuples strings too, but then I'd have to do string comparison or eval
to match up 'True'
to True
, which is kind of ugly/unsafe. So best stick to integers, like in my example.
How to show database in django-admin using filters by default?
This is possible with custom custom Managers:
Say you have a class called Book
:
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=50)
And you want the admin pages for book objects to only show books by Roald Dahl, then you can add a custom manager:
class DahlBookManager(models.Manager):
def get_query_set(self):
return super(DahlBookManager, self).get_query_set().filter(author='Roald Dahl')
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=50)
objects = models.Manager()
dahl_objects = DahlBookManager()
Then you just need to specify that your ModelAdmin
should use the dahl_objects
manager, which is explained here.
Related Topics
How to Remove Specific Tag/Sticker/Object from Images Using Opencv
How to Clone a Python Generator Object
Differencebetween Join and Merge in Pandas
How to Add Default Parameters to Functions When Using Type Hinting
Why Is Pip Installing an Old Version of My Package
Python: How to Ignore an Exception and Proceed
Python Replace String Pattern with Output of Function
Error When Loading Cookies into a Python Request Session
Interact with Other Programs Using Python
How to Get the Executable's Current Directory in Py2Exe
Why Isn't the Regular Expression's "Non-Capturing" Group Working
Return Multiple Columns from Pandas Apply()
Remove All Newlines from Inside a String