In our previous post on Django-Filters Part 2, we learned adding custom methods to filter field, Implementing widgets and modifying form attributes, and finally to Paginate. And in our final post, we’ll learn to use multiple choice fields and finally format with CSS bootstrap
class BookFilterExp7(django_filters.FilterSet):
BOOKS_SORT_CHOICES = (
('LESS_THAN', 'Less Than'),
('GREATER_THAN', 'Greater Than'),
)
BOOKS_ORDER_BY_CHOICES = (
('ASC', 'Ascending Order'),
('DESC', 'Descending Order'),
)
book_name = django_filters.CharFilter(lookup_expr='iexact')
author_name = django_filters.CharFilter(label="Author Name",field_name="author__author_name",lookup_expr='icontains',widget=forms.TextInput(attrs={'class':'form-control', 'placeholder' : "Search by Author..."}))
author_books = django_filters.NumberFilter(label="Number of Books Published By Author",method="author_books_count")
author_sort_books_by = django_filters.ChoiceFilter(empty_label='Select to Sort',label="Sort Number of Books",choices=BOOKS_SORT_CHOICES,method="author_sort_books")
books_by_order = django_filters.ChoiceFilter(empty_label='Select to Order',label="Order By",choices=BOOKS_ORDER_BY_CHOICES,method="books_by_order_method")
num_rows = django_filters.NumberFilter(label="Number of Rows to show",method="num_rows_method",widget=forms.TextInput(attrs={'min':'1', 'required' : True}))
multiple_authors = django_filters.MultipleChoiceFilter(choices=[],label="Filter by multiple Authors",method="multiple_authors_method",widget=forms.SelectMultiple(attrs={"class" : "form-control"}))
class Meta:
model = Book
fields = ['status']
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
self.form.fields['book_name'].widget.attrs = {'placeholder':'Type Book to search...'}
self.form.fields['multiple_authors'].choices = self.get_multiple_authors_choices()
self.request_data = args[0].dict()
def author_books_count(self, queryset, name, value):
sort_by = self.request_data.get('author_sort_books_by',None)
authors_qs = Author.objects.all()
authors_id = []
for author in authors_qs:
count = Book.objects.filter(author=author).count()
if sort_by==self.BOOKS_SORT_CHOICES[1][0]: #greater than
if count >= value:
authors_id.append(author.id)
else:
if count <= value:
authors_id.append(author.id)
qs = Book.objects.filter(author__in=authors_id)
return qs
def author_sort_books(self, queryset, name, value):
return queryset
def books_by_order_method(self, queryset, name, value):
order_by = "-book_name"
if value == self.BOOKS_ORDER_BY_CHOICES[0][0]:
order_by = "book_name"
return queryset.order_by(order_by)
@property
def qs(self):
qs = super().qs
num_rows = int(self.request_data.get('num_rows',5))
if num_rows <= 0:
num_rows = qs.count()
paginator = Paginator(qs,num_rows)
page = self.request_data.get('page')
paginated_qs = paginator.get_page(page)
return paginated_qs
def num_rows_method(self, queryset, name, value):
return queryset
def get_multiple_authors_choices(self):
choices = []
for author in Author.objects.all():
choices.append([author.id, author.author_name])
return choices
def multiple_authors_method(self, queryset, name, value):
ids = []
for item in value:
if item != "":
ids.append(item)
if len(ids):
qs = queryset.filter(author__in=ids)
else:
qs = queryset
return qs
The multiple_authors
is MultipleChoiceFilter
and to make it select multiple authors we added widget=forms.SelectMultiple(attrs={"class" : "form-control"})
.
The argument choices
is passed empty and on __init__
the method we’ll pass dynamically generated data from a method self.get_multiple_authors_choices()
.
In this method, we loop through all authors and add them to choices
which is a list and returned to multiple_authors
a field as choices.
#django framework #python #django #learn python