I really hate boilerplate. However, I can't deny that code such as the following is a huge benefit. So my question, what does one do in Python to make up for the fact that it doesn't come with a macro (template) pre-processor?
One idea would be to write a factory function, but I'll willingly admit that I don't know where to start. (Please note that this is Django with its declarative classes and interesting "magic" metaclassy stuff going on underneath, which I know enough to recognise and not enough to understand or debug if I break it)
The other would be to turn this into a template and import it through a trivial pre-processor that implements something like ${var:-default}
in Bash. (see What is an alternative to execfile in Python 3? ),
with my_preprocessor("somefile.py") as f:
code = compile(f.read(), "somefile.py", 'exec')
exec(code) # in the current namespace
But there are lots of warnings about exec
that I've seen over the years. The cited SO answer mentions line numbers for debugging as an issue. Then there is this, http://lucumr.pocoo.org/2011/2/1/exec-in-python/ , warning of subtle problems including memory leaks. I suspect they won't apply to a code defining classes which are "never" deleted, but on the other hand I don't want the slightest risk of introducing obscure problems to a production setting.
Any thoughts or pointers welcome. Is the best thing to do is to accept cut and paste boilerplate? There are unlikely to be more than twenty paste-modifies of any such template, usually less than ten.
Example code. Lines marked #V are the only ones that would commonly be customized. The first two classes are used once only, by the third.
#--- this is boilerplate for a select-view ----
#--- just replace the string "User" by the relevant model and customize
class UserSelectPopupTable( tables.Table):
id = SelectorColumn( clickme='<span class="glyphicon glyphicon-unchecked"></span>' ) #V
class Meta:
model=User
attrs={ 'class':'paleblue' }
empty_text='Sorry, that search did not match anything.'
fields=( 'name','address', ) #V
sequence=('id','name','address',) #V
class UserFilter2(django_filters.FilterSet):
name = django_filters.CharFilter(lookup_expr='icontains') #V
address = django_filters.CharFilter(lookup_expr='icontains') #V
class Meta:
model = User
fields = ('name','address', ) #V (usually same as previous)
class UserSelectPopup( FilterTableView ):
model=User
table_class=UserSelectPopupTable
filterset_class=UserFilter2
template_name='redacted/select_in_popup.html'
#--- end boilerplate