Reputation: 2568
I am trying to implement a ListView with the filter capability like the one in Django Admin. I looked into django-filter, but its not clear how to use that on my template.
This is my ListView:
@method_decorator(login_required, name='dispatch')
class ListProjects(ListView):
model = Project
paginate_by = 100
list_filter=('start_dt','end_dt','status')
In this case I would like to filter by those three fields.
Upvotes: 2
Views: 826
Reputation: 2568
So I made a hybrid between my custom view and the admin. Here is the final solution:
class ListProjects(ListView):
model = Project
paginate_by = 100
adm_model = ProjectAdmin(Project,AdminSite())
changelist = None
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
self.changelist = self.adm_model.get_changelist_instance(self.request)
context['cl']=self.changelist
return context
def get_queryset(self):
qs = super().get_queryset()
get_params = self.request.GET.dict()
self.changelist = self.adm_model.get_changelist_instance(self.request)
(self.changelist.filter_specs, self.changelist.has_filters, remaining_lookup_params,
filters_use_distinct) = self.changelist.get_filters(self.request)
# Then, we let every list filter modify the queryset to its liking.
qs = self.changelist.root_queryset
for filter_spec in self.changelist.filter_specs:
new_qs = filter_spec.queryset(self.request, qs)
if new_qs is not None:
qs = new_qs
try:
qs = qs.filter(**remaining_lookup_params)
except:
pass
# Set ordering.
ordering = self.changelist.get_ordering(self.request, qs)
qs = qs.order_by(*ordering)
# Apply search results
qs, search_use_distinct = self.changelist.model_admin.get_search_results(self.request, qs, self.changelist.query)
return qs
In the template, I have for search piece
<div class="row-fluid">
<div class="span12">
<form class='form-inline' accept-charset='UTF-8' method='get' action=''>
<input type="text" size="40" name="q" value = "{{cl.params.q}}" id="searchbar" autofocus="">
<button type='submit' class="btn">Search</button>
</form>
</div>
</div>
filter piece
{% if cl.has_filters %}
<div id="changelist-filter">
<h3>{% trans 'Filter' %}</h3>
{% for spec in cl.filter_specs %}
{% admin_list_filter cl spec %}
</div>
{% endfor %}
</div>
{% endif %}
Upvotes: 2
Reputation: 1152
Django admin filters works by filtering the queryset based on the GET params passed depending on the chosen filter. Having said that, you can easily achieve the same by overriding the get_queryset
method of the ListView
and doing something like :
def get_queryset(self):
qs = super().get_queryset()
get_params = self.request.GET.dict()
# search
if get_params.get('q') and hasattr(self, 'search_fields'):
# logic for search goes here....
# filter
if hasattr(self, 'list_filter'):
filter_fields = self.list_filter
for key, value in get_params.items():
if key in filter_fields and key != 'q' and value != '':
qs = qs.filter(**{key:value})
return qs
Now in the template you can render the choices for the filters with a
tags just like in admin. Make sure to preserve the get params while using this method.
Hope this helps.
Upvotes: 0