How to reduce Django class based view boilerplate
<p>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?</p>

<p>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)</p>

<p>The other would be to turn this into a template and import it through a trivial pre-processor that implements something like <code>${var:-default}</code> in Bash. (see <a href="http://stackoverflow.com/questions/436198/what-is-an-alternative-to-execfile-in-python-3-0">What is an alternative to execfile in Python 3.0?</a> ), </p>

<pre><code>with my_preprocessor("somefile.py") as f:
    code = compile(f.read(), "somefile.py", 'exec')
    exec(code) # in the current namespace
</code></pre>

<p>But there are lots of warnings about <code>exec</code> that I've seen over the years. The cited SO answer mentions line numbers for debugging as an issue. Then there is this, <a href="http://lucumr.pocoo.org/2011/2/1/exec-in-python/" rel="nofollow">http://lucumr.pocoo.org/2011/2/1/exec-in-python/</a> , 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.</p>

<p>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.</p>

<p>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.</p>

<pre><code>#--- 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='&lt;span class="glyphicon glyphicon-unchecked"&gt;&lt;/span&gt;' ) #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
</code></pre>

<p>Python and Django are awesome.</p>

<p>I read and re-read the (quite short) documentation of the 3-argument form of <code>type</code> that you use to dynamically create classes (<a href="https://docs.python.org/3/library/functions.html#type" rel="nofollow">https://docs.python.org/3/library/functions.html#type</a>). I  wrote a trivial helper routine <code>Classfactory</code> to provide a better interface to <code>type</code>, 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)</p>

<pre><code>def Classfactory( classname, inheritsfrom=(object,), **kwargs):
    inh = inheritsfrom if isinstance(inheritsfrom, tuple) else (inheritsfrom, )
    return type( 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='&lt;span class="glyphicon glyphicon-unchecked"&gt;&lt;/span&gt;' ),

    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
)
</code></pre>

<p>Now I suddenly realized that it's not just Django <code>Meta</code> 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 ...</p>

<pre><code>def SelectPopupFactory( Model, fields, sequence=None, 
                clickme='&lt;span class="glyphicon glyphicon-unchecked"&gt;&lt;/span&gt;' ,
                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',) ,
    )
</code></pre>

<p>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)</p>

<p>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.</p>

python django python-3.x boilerplate