在 Django 的 View 中利用 function decorator 可实现一定程度的代码重用
2007-04-03 17:18
761 查看
在 Django 中,假设有几个 view, 他们都接受类似的参数,做类似的处理,最后又输出类似的变量到模板中配合显示,唯一不同的就是模板路径。
最普通的写法可能是这样:
def view_a(request, some_id):
some_obj = SomeClass.objects.get(pk=some_id)
# 一些处理
#
return render_to_response("a.html", {'some_obj': some_obj},
context_instance=RequestContext(request))
def view_b(request, some_id):
some_obj = SomeClass.objects.get(pk=some_id)
# 一些处理
#
return render_to_response("b.html", {'some_obj': some_obj},
context_instance=RequestContext(request))
def view_c(request, some_id):
some_obj = SomeClass.objects.get(pk=some_id)
# 一些处理
#
return render_to_response("c.html", {'some_obj': some_obj},
context_instance=RequestContext(request))
这里显然很多代码重复,最容易想到的是把同样的代码取出来放到一个函数里,重构后代码变成了这样:
def some_logic(request, some_id, template_path):
some_obj = SomeClass.objects.get(pk=some_id)
# 一些处理
#
return render_to_response(template_path, {'some_obj': some_obj},
context_instance=RequestContext(request))
def view_a(request, some_id):
some_logic(request, some_id, "a.html")
def view_b(request, some_id):
some_logic(request, some_id, "b.html")
def view_c(request, some_id):
some_logic(request, some_id, "c.html")
好多了,可是我们注意到传递进 view 的一些参数(这里只有一个 some_id)仍然重复的写了很多次。有没有更好的办法呢?有的,用 function decorator,可以写成这样:
def foo_view(template_path):
def my_decorator(f):
def new_f(request, some_id, *args, **kwds):
some_obj = SomeClass.objects.get(pk=some_id)
# 一些处理
#
return render_to_response(template_path, {'some_obj': some_obj},
context_instance=RequestContext(request))
new_f.func_name = f.func_name
return new_f
return my_decorator
@foo_view("a.html")
def view_a(request, some_id):
pass
@foo_view("b.html")
def view_b(request, some_id):
pass
@foo_view("c.html")
def view_c(request, some_id):
pass
这样具体的 view 里面什么代码也没写,仅仅向 decorator 传递了一个模板名称的参数就搞定了。具体的实现,被封装到了 foo_view 这个 decorator 的内部函数里面。decorator 的作用看上去类似于 C# 的 Attribute, 但实际上强大很多,Attribute 仅仅相当于一个简单的元数据,具体实现还需要在其他类里面去分离实现,并且查找理解起来也不太方便,尤其在阅读大型类库的时候。而 python 里的 decorator 可以对函数做任意的修改,可任意添加前置(pre),后置(post) 操作,甚至完全取代掉原来的函数。可以辅助做参数、返回值类型检测、AOP (用的比较多的有日志、异常处理等)等功能,十分强大和灵活。
最普通的写法可能是这样:
def view_a(request, some_id):
some_obj = SomeClass.objects.get(pk=some_id)
# 一些处理
#
return render_to_response("a.html", {'some_obj': some_obj},
context_instance=RequestContext(request))
def view_b(request, some_id):
some_obj = SomeClass.objects.get(pk=some_id)
# 一些处理
#
return render_to_response("b.html", {'some_obj': some_obj},
context_instance=RequestContext(request))
def view_c(request, some_id):
some_obj = SomeClass.objects.get(pk=some_id)
# 一些处理
#
return render_to_response("c.html", {'some_obj': some_obj},
context_instance=RequestContext(request))
这里显然很多代码重复,最容易想到的是把同样的代码取出来放到一个函数里,重构后代码变成了这样:
def some_logic(request, some_id, template_path):
some_obj = SomeClass.objects.get(pk=some_id)
# 一些处理
#
return render_to_response(template_path, {'some_obj': some_obj},
context_instance=RequestContext(request))
def view_a(request, some_id):
some_logic(request, some_id, "a.html")
def view_b(request, some_id):
some_logic(request, some_id, "b.html")
def view_c(request, some_id):
some_logic(request, some_id, "c.html")
好多了,可是我们注意到传递进 view 的一些参数(这里只有一个 some_id)仍然重复的写了很多次。有没有更好的办法呢?有的,用 function decorator,可以写成这样:
def foo_view(template_path):
def my_decorator(f):
def new_f(request, some_id, *args, **kwds):
some_obj = SomeClass.objects.get(pk=some_id)
# 一些处理
#
return render_to_response(template_path, {'some_obj': some_obj},
context_instance=RequestContext(request))
new_f.func_name = f.func_name
return new_f
return my_decorator
@foo_view("a.html")
def view_a(request, some_id):
pass
@foo_view("b.html")
def view_b(request, some_id):
pass
@foo_view("c.html")
def view_c(request, some_id):
pass
这样具体的 view 里面什么代码也没写,仅仅向 decorator 传递了一个模板名称的参数就搞定了。具体的实现,被封装到了 foo_view 这个 decorator 的内部函数里面。decorator 的作用看上去类似于 C# 的 Attribute, 但实际上强大很多,Attribute 仅仅相当于一个简单的元数据,具体实现还需要在其他类里面去分离实现,并且查找理解起来也不太方便,尤其在阅读大型类库的时候。而 python 里的 decorator 可以对函数做任意的修改,可任意添加前置(pre),后置(post) 操作,甚至完全取代掉原来的函数。可以辅助做参数、返回值类型检测、AOP (用的比较多的有日志、异常处理等)等功能,十分强大和灵活。
相关文章推荐
- 在 Django 的 View 中利用 function decorator 可实现一定程度的代码重用
- iPhone开发之UIScrollView滚动组件的使用(七)利用NSTimer计时器和UIPageControl组件代码实现图片轮播器
- 基于Django框架利用Ajax实现点赞功能实例代码
- iOS利用UIScrollView实现图片的缩放实例代码
- 提高生产力在一定程度上是通过创新、通过资源从衰退的旧利用方式向更加富有生产力的新利用方式转移来实现的。另外,生产力的提高也可以通过持续改善现有利用方式中资源的生产力来实现。
- Windows环境下利用“共享内存”实现进程间通信的C/C++代码---利用CreateFileMapping和MapViewOfFile
- [转]Windows环境下利用“共享内存”实现进程间通信的C/C++代码---利用CreateFileMapping和MapViewOfFile
- iOS tableView 的 cell上其它控件重用(利用view的tag属性巧妙实现重用,从xib中加在cell重载问题)
- 利用 UIImageView 实现全屏动画的代码例子
- Windows环境下利用“共享内存”实现进程间通信的C/C++代码---利用CreateFileMapping和MapViewOfFile
- 源码推荐(9.22):利用UIScrollView实现几个页面的切换,纯代码实现水滴和波浪动画
- Android 利用ViewPager实现图片可以左右循环滑动效果附代码下载
- 通过定义BaseActivity来实现项目中代码重用,重写setContentView实现多个Activity部分UI布局相同
- 利用Pillow,几行代码实现的最简单的Django页面验证码功能
- 2、利用反射技术得到泛型类型,实现对实体添删改查操作进行代码重用设计
- Windows环境下利用“共享内存”实现进程间通信的C/C++代码---利用CreateFileMapping和MapViewOfFile
- 第十九章 19 利用私有继承来实现代码重用
- activitygroup的子activity中嵌套webview,利用webview与js交互,在实现js点击的内部类代码中实现activity跳转出现的线程问题
- iPhone开发教程之利用 UIImageView 实现全屏动画的代码例子
- 利用RecyclerView实现探探的翻牌子功能