How To Reduce Django Class Based View Boilerplate
Solution 1:
Python and Django are awesome.
I read and re-read the (quite short) documentation of the 3-argument form of type
that you use to dynamically create classes (https://docs.python.org/3/library/functions.html#type). I wrote a trivial helper routine Classfactory
to provide a better interface to type
, and translated the class structure into function calls, which was mostly cut and paste! I arrived at the following (which I think also proves that you can write Javascript in Python ... the instinct to insert semicolons was strong)
defClassfactory( classname, inheritsfrom=(object,), **kwargs):
inh = inheritsfrom ifisinstance(inheritsfrom, tuple) else (inheritsfrom, )
returntype( classname, inh, kwargs)
ThisPopupFilter = Classfactory( 'ThisPopupFilter', django_filters.FilterSet,
name = django_filters.CharFilter(lookup_expr='icontains') ,
address = django_filters.CharFilter(lookup_expr='icontains') ,
Meta = Classfactory( 'Meta',
model = User,
fields = ('name','address', ),
),
)
ThisPopupTable = Classfactory( 'ThisPopupTable', tables.Table,
id = SelectorColumn( clickme='<span class="glyphicon glyphicon-unchecked"></span>' ),
Meta = Classfactory( 'Meta', # default inherit from object
model=User,
attrs={ 'class':'paleblue' },
empty_text='Sorry, that search did not match anything.',
fields=( 'name','address', ) ,
sequence=('id','name','address',) ,
),
)
UserSelectPopup = Classfactory( 'UserSelectPopup', FilterTableView,
model=User,
table_class=ThisPopupTable,
filterset_class=ThisPopupFilter,
template_name='silson/select_in_popup.html', # this template handles any such view
)
Now I suddenly realized that it's not just Django Meta
classes that can be defined inside other classes. Any class that is not needed elsewhere can be nested in the scope where it is needed. So I moved the first two classes inside the third, and then with a bit more rearranging I was able to move to a factory function with arguments ...
defSelectPopupFactory( Model, fields, sequence=None,
clickme='<span class="glyphicon glyphicon-unchecked"></span>' ,
empty_text='Sorry, that search did not match anything.',):
return Classfactory( 'UserSelectPopup', FilterTableView,
model=Model,
template_name='silson/select_in_popup.html', # this template handles any such view
table_class=Classfactory( 'ThisPopupTable', tables.Table,
id = SelectorColumn( clickme=clickme ),
Meta = Classfactory( 'Meta', # default inherit from object
model=Model,
attrs={ 'class':'paleblue' },
empty_text=empty_text,
fields=fields,
sequence=sequence,
)),
filterset_class=Classfactory( 'ThisPopupFilter', django_filters.FilterSet,
name = django_filters.CharFilter(lookup_expr='icontains') ,
address = django_filters.CharFilter(lookup_expr='icontains') ,
Meta = Classfactory( 'Meta',
model = Model,
fields = ('name','address', ),
)),
)
UserSelectPopup = SelectPopupFactory( User,
fields=('name','address', ),
sequence=('id','name','address',) ,
)
Can anybody see anything fundamentally wrong with this? (I'm feeling slightly amazed that it all ran and did not crash at the first attempt, modulo typos)
UPDATE a workday later: I think this is OK as an example / proof of concept (it is code that ran without crashing) but there are several fine points to do with the actual django_filters and django_tables2 usage that aren't right here. My factory function has evolved and is more capable, but less easy to relate to the original non-factory class definitions.
Post a Comment for "How To Reduce Django Class Based View Boilerplate"