2016-09-29 5 views
0

Я действительно ненавижу шаблон. Однако я не могу отрицать, что такой код, как, например, следующий, является огромным преимуществом. Итак, мой вопрос, что делать в Python, чтобы компенсировать тот факт, что он не поставляется с предварительным процессором макроса (шаблона)?Как уменьшить шаблон шаблона на основе Django

Одна из идей - написать фабричную функцию, но я с готовностью признаю, что не знаю с чего начать. (Пожалуйста, обратите внимание, что это Django с его декларативными классами и интересными «волшебными» метаклассическими материалами, которые я знаю достаточно, чтобы распознать и не достаточно, чтобы понять или отладить, если я его сломаю).

Другой - это в шаблон и импортировать его через тривиальный предварительный процессор, который реализует что-то вроде ${var:-default} в Bash. (См 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 

Но есть много предупреждений о exec, которые я видел на протяжении многих лет. В приведенном ответе SO упоминаются номера строк для отладки как проблемы. Тогда есть это, http://lucumr.pocoo.org/2011/2/1/exec-in-python/, предупреждение о тонких проблемах, в том числе утечки памяти. Я подозреваю, что они не будут применяться к коду, определяющему классы, которые «никогда» не удаляются, но, с другой стороны, я не хочу ни малейшего риска вводить неясные проблемы в настройку производства.

Любые мысли или указатели приветствуются. Лучше всего сделать, чтобы принять разрез и вставить шаблон? Вероятно, не будет более двадцати пастовых модификаций любого такого шаблона, обычно менее десяти.

Пример кода. Линии, отмеченные #V, являются единственными, которые обычно настраиваются. Первые два класса используются только один, третий.

#--- 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 
+0

Можете ли вы привести пример того, как вы хотите использовать эти сгенерированные классы? –

+0

как виды: 'url (r '^ UserSelectPopup/$', views.UserSelectPopup.as_view(), name = 'userselectpopup'), ' – nigel222

+0

Написание фабрики получилось намного проще, чем я думал. Я прочитал и перечитал «тип» 3-arg doc, а затем ... отвечу на собственный вопрос после немного большего тестирования и убора. – nigel222

ответ

2

Python и Django являются удивительными.

Я читал и перечитывал (довольно короткую) документацию формы 3-аргумента type, которую вы используете для динамического создания классов (https://docs.python.org/3/library/functions.html#type). Я написал тривиальную вспомогательную процедуру Classfactory, чтобы обеспечить лучший интерфейс для type и перевел структуру класса в вызовы функций, которые в основном были вырезаны и вставлялись! Я прибыл на следующее (я думаю, что также доказывает, что вы можете написать Javascript в Python ... инстинкт вставки был сильным запятой)

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='<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 
) 

Теперь я вдруг понял, что это не только Django Meta классы, которые могут быть определенных внутри других классов. Любой класс, который не нужен нигде, может быть вложен в область, где это необходимо. Таким образом, я переместил первые два класса внутри третьего, а затем немного больше переставляя я был в состоянии перейти к функции фабрики с аргументами ...

def SelectPopupFactory(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',) , 
    ) 

Может кто-нибудь увидеть ничего принципиально плохого в этом? (Я немного удивлен, что все это побежало и не сработало при первой попытке, по модулю опечаток)

ОБНОВЛЕНИЕ рабочий день позже: Я думаю, что это нормально в качестве примера/доказательства концепции (это код, который запускался без сбоев), но есть несколько тонких моментов, связанных с фактическим использованием django_filters и django_tables2, которые здесь не правы. Моя фабричная функция эволюционировала и более способна, но менее легко связана с оригинальными определениями нефакторного класса.

Смежные вопросы