【问题标题】:How to reduce Django class based view boilerplate如何减少基于 Django 类的视图样板
【发布时间】:2016-09-29 09:02:19
【问题描述】:

我真的很讨厌样板。但是,我不能否认像下面这样的代码是一个巨大的好处。所以我的问题是,在 Python 中做了什么来弥补它没有附带宏(模板)预处理器的事实?

一个想法是编写一个工厂函数,但我愿意承认我不知道从哪里开始。 (请注意,这是 Django,它的声明性类和有趣的“神奇”元类东西在下面进行,我知道足以识别它们,但如果我破坏它,则不足以理解或调试)

另一种方法是将其转换为模板并通过一个简单的预处理器导入它,该预处理器在 Bash 中实现了 ${var:-default} 之类的东西。 (见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/ ,警告包括内存泄漏在内的细微问题。我怀疑它们不适用于定义“永不”删除的类的代码,但另一方面,我不希望在生产环境中引入晦涩的问题。

欢迎提出任何想法或建议。最好的办法是接受剪切和粘贴样板吗?任何此类模板的粘贴修改都不可能超过 20 次,通常少于 10 次。

示例代码。标有#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

【问题讨论】:

  • 你能举例说明你想如何使用这些生成的类吗?
  • 作为视图:url(r'^UserSelectPopup/$', views.UserSelectPopup.as_view(), name ='userselectpopup'),
  • 编写工厂比我想象的要容易得多。我阅读并重新阅读type 3-arg 文档,然后......经过更多测试和整理后将回答自己的问题。

标签: python django python-3.x boilerplate


【解决方案1】:

Python 和 Django 很棒。

我阅读并重新阅读了您用于动态创建类 (https://docs.python.org/3/library/functions.html#type) 的 type 的 3 参数形式的(非常短的)文档。我编写了一个简单的帮助程序Classfactory 来为type 提供更好的接口,并将类结构转换为函数调用,这主要是剪切和粘贴!我得出了以下结论(我认为这也证明了您可以在 Python 中编写 Javascript ......插入分号的本能很强)

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 使用有关的要点不在这里.我的工厂函数已经进化并且功能更强大,但不太容易与原始的非工厂类定义相关联。

【讨论】:

    猜你喜欢
    • 2015-08-10
    • 2018-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-13
    • 2014-02-16
    相关资源
    最近更新 更多