I have a table with about 30 columns and I'd like to attach five filters to most columns in a highly repetitive manner. So I hoped that I could use a class decorator to define them as per this SO answer. No joy. TypeError: 'NoneType' object is not callable
(at runtime when I invoke the view)
Anyway, then I read up about "proper" metaclassing and tried
class SettingsMeta(type):
def __new__(cls, clsname, bases, attrs):
for name in ('fx_t', 'status'): # just two for now but target ~60 with 5 different lookup_expr
attr_name = name + '_start'
attrs[attr_name] = FD.CharFilter(
field_name = name,
lookup_expr = 'istartswith' ,
label = name.replace('_t','').capitalize() + ' starts with',
)
return super(SettingsMeta, cls).__new__(cls, clsname, bases, uppercase_attrs)
class SelectMaskdataFilters( FD.FilterSet, metaclass=SettingsMeta):
class Meta:
model = Maskdata
fields = {
'notes': [ 'icontains',],
}
#status_sw = FD.CharFilter( field_name='status', lookup_expr='startswith')
...
Again no joy: TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
at server start-up.
SelectMaskDataFilters is itself working as expected in a view if I just remove metaclass=SettingsMeta
I'm in over my head, but I really don't like repeating myself with a hundred or so filter definitions all of which will be almost the same. So, does anybody know how to define a large number of filters in in a FilterSet other than copy, paste, and error-prone small changes? Note, most of the filters will use method=
not lookup_expr=
so the fields
attribute in the inner Meta
class is not useful
You can define these in the local scope of the SelectMaskdataFilters
:
import django_filters
class SelectMaskdataFilters(django_filters.FilterSet):
for name in ('fx_t', 'status'):
label = name.replace('_t','').capitalize()
locals()[f'{name}_start'] = django_filters.CharFilter(
field_name=name,
lookup_expr='istartswith' ,
label=f'{label} starts with'
)
class Meta:
model = Maskdata
fields = {
'notes': [ 'icontains',],
}