Skip to content

Instantly share code, notes, and snippets.

@zorky
Last active January 4, 2019 10:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zorky/47e808146b6dc00f1e09335b03418344 to your computer and use it in GitHub Desktop.
Save zorky/47e808146b6dc00f1e09335b03418344 to your computer and use it in GitHub Desktop.
Generic filter with operators (gt, lt, eq, ne) on model's field
import django_filters
import datetime
from django.db.models import Q
class FilterOperatorBase(django_filters.FilterSet):
"""
base filter for field_operator
field_operator is formatted as : field||type||operator||value
separator is ||
- field : model's field
- type : date, number, string, list
- operator : gt | lt | eq | ne or range for date (value must be in format : datebegin_dateend as YYYY-MM-DD_YYYY-MM-DD)
- value : value to test
"""
field_operator = django_filters.CharFilter(method="get_field_operator")
def get_field_operator(self, queryset, name, value):
"""
Management of fields operator "field_operator", multi values
ie : field_operator=val1&field_operator=val2&field_operator=valn where val has format field||type||operator||value
"""
qs = queryset
field_operator_list = self.request.GET.getlist('field_operator')
for field in field_operator_list:
field, type, operator, valuefield = field.split('||')
if field and type and operator and valuefield:
if type == 'date':
if operator == 'range':
# value = YYYY-MM-DD_YYYY-MM-DD : date_begin_date_end
date_begin, date_end = value.split('_')
values = {'date_begin': date_begin, 'date_end': date_end}
else:
year, month, day = valuefield.split('-')
date = datetime.date(int(year), int(month), int(day))
values = {'date': date, 'day': day, 'month': month, 'year': year}
q = self.__get_date_filter_operator(field=field, operator=operator, **values)
qs = qs.filter(q)
if type == 'number':
q = self.__get_number_filter_operator(field=field, operator=operator, value=valuefield)
qs = qs.filter(q)
if type == 'string':
q = self.__get_string_filter_operator(field=field, operator=operator, value=valuefield)
qs = qs.filter(q)
if type == 'list':
ids = list(valuefield)
filter = {
'{}__in'.format(field): ids
}
if operator == 'eq':
qs = qs.filter(**filter)
if operator == 'ne':
qs = qs.exclude(**filter)
return qs
def __get_string_filter_operator(self, field, operator, value, insensibleCasse = True):
"""
Creating Q for string (eq or ne only operators)
"""
q = None
filter = {
'{}__{}'.format(field, 'iexact' if insensibleCasse else 'exact'): value
}
if operator == 'eq':
q = Q(**filter)
if operator == 'ne':
q = ~Q(**filter)
return q
def __get_number_filter_operator(self, field, operator, value):
"""
Created Q for numbers (lte or gte or eq or ne)
"""
filter = {}
q = None
if operator == 'gte' or operator == 'lte' or operator == 'eq':
if operator == 'gte' or operator == 'lte':
filter = {
'{}__{}'.format(field, operator): value
}
if operator == 'eq':
filter = {
'{}'.format(field): value
}
q = Q(**filter)
if operator == 'ne':
filter = {
'{}'.format(field): value
}
q = ~Q(**filter)
return q
def __get_date_filter_operator(self, field, operator, **values):
"""
Created Q for date (lt or gt or eq or ne operators)
"""
filter = {}
q = None
if operator == 'gt' or operator == 'lt' or operator == 'eq':
if operator == 'gt' or operator == 'lt':
filter = {
'{}__{}'.format(field, operator): values['date']
}
if operator == 'eq':
filter = {
'{}__day'.format(field): values['day'],
'{}__month'.format(field): values['month'],
'{}__year'.format(field): values['year']
}
q = Q(**filter)
if operator == 'ne':
filter = {
'{}__day'.format(field): values['day'],
'{}__month'.format(field): values['month'],
'{}__year'.format(field): values['year']
}
q = ~Q(**filter)
if operator == 'range':
filter = {
'{}__range'=[values['date_begin'], values['date_end']]
}
q = Q(**filter)
return q
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment