智能视图类(CBV)装饰

django-universal-view-decorator的Python项目详细描述


buildcode qualitycode healthcoveragepypigithublicense: MIT

About Class Based View (CBV) decoration

在django中,您可以用两种不同的方式实现视图

  1. FBV (Function Based View)
  2. CBV (Class Based View)

一个项目可以同时使用这两种技术。虽然装饰师在FBV上工作得很好,但使用它们 与CBV是有点丑陋。django文档建议使用两种技术来修饰基于类的视图:

https://docs.djangoproject.com/en/1.9/topics/class-based-views/intro/#decorating-class-based-views

  1. urlconf中的decoration:将decorator应用于View.as_view()类方法返回的view函数。

    urlpatterns=[url(r'^my_view/',permission_required('my_app.my_permission')(MyView.as_view())),]

    I think this decoration technique is solid. It treats your view class as a view function and places the decorator between the url config and the view function exactly as in case of decorating a FBV. The decorator is guaranteed to execute before any methods in the decorated CBV.

    My only problem is that I have to do this in the URLConf module and on a per-url basis instead of being able to apply the decorator onto the view class in the module in which it has been implemented.

  2. 在以下帮助下,将decorator应用于视图类的一个方法(例如:dispatch()@django.utils.decorators.method_decorator

    classMyView(View):@method_decorator(permission_required('my_app.my_permission'))defdispatch(self,*args,**kwargs):returnsuper(MyView,self).dispatch(*args,**kwargs)# django 1.9+: this way you don't have to override dispatch() just to be able to decorate it@method_decorator(permission_required('my_app.my_permission'),name='dispatch')classMyView(View):...

    Problems with this solution:

    • If someone subclasses the view and overrides the decorated method then the method override in the subclass is executed before the decorator. The decorator can actually be bypassed completely by not calling the super version of the overridden method. This may be a desired behavior sometimes but in case of some critical (e.g.: permission) decorators it is a problem. In case of decorating in URLConf this isn’t a problem: in that case the decorator is always executed before any view class methods.
    • Minor issue: I have to write ^{tt6}$ instead of simply ^{tt7}$.

正如你所见,这两种装饰手法有不同的表现。我发现技术1的行为(urlconf 装饰)更有用、更健壮,而我更喜欢在视图类实现中应用装饰器。 就像技术2(@method_decorator)一样。

这个库提供了一个@universal_view_decoratorhelper(类似于django的@method_decorator),它结合了 装饰手法1与手法2化妆品的行为:

  • 您可以直接将decorator应用于view类-除非您想 在每个url的基础上应用decorators。
  • 行为类似于装饰方法1:在引擎盖下,它将装饰器应用于 View.as_view()所以不能用子类化绕过它。

除了前面列出的特性之外,@universal_view_decorator提供了比 django的@method_decorator:使用此帮助程序包装视图装饰器之后,可以将其应用于fbvs、cbvs 和具有完全相同语法的cbv方法。还有一个@universal_view_decorator_with_args变体 与具有参数的视图装饰器配合使用的助手。

Usage

^{tt1}$

如果用@universal_view_decorator包装视图装饰器,则可以将其应用于:

  • fbvs(就像在用@universal_view_decorator包装它之前一样)
  • cbvs(行为与urlconf中的装饰View.as_view()相同)
  • cbv方法(在使用django的 @method_decorator
fromdjango_universal_view_decoratorimportuniversal_view_decorator@universal_view_decorator(login_required)deffunction_based_view(request):...# You can wrap multiple decorators at the same time@universal_view_decorator(login_required,permission_required('my_app.my_permission'))deffunction_based_view(request):...# This double decoration is equivalent in behavior to the previous example# where we used one wrapper to wrap both legacy decorators.@universal_view_decorator(login_required)@universal_view_decorator(permission_required('my_app.my_permission'))deffunction_based_view(request):...# Applying the decorator to view classes. Behavior is the same as applying# the permission decorator to ``ClassBasedView.as_view()`` in the URLConf.@universal_view_decorator(permission_required('my_app.my_permission'))classClassBasedView(View):...# Applying the decorator to view class methods.# Behavior is equivalent to that of django's @method_decorator.classClassBasedView(View):@universal_view_decorator(login_required)defhead(self,request):...# Wrapping the decorator only once for reuse in our project:reusable_universal_login_required=universal_view_decorator(logic_required)@reusable_universal_login_requiredclassClassBasedView(View):...

^{tt2}$

@universal_view_decorator_with_argsdecorator与@universal_view_decoratordecorator几乎相同,但是 它允许您在包装后对包装的装饰器进行参数化。如果你想包装的话这很有用 一个decorator只有一次可重用,但decorator具有在执行 包装:

fromdjango_universal_view_decoratorimportuniversal_view_decorator,universal_view_decorator_with_args# with @universal_view_decorator you have to bind args before wrapping :-(my_permission_required=universal_view_decorator(permission_required('my_app.my_permission'))# we can specify args for permission_required when we apply the decorator :-)universal_permission_required=universal_view_decorator_with_args(permission_required)@universal_permission_required('my_app.my_permission')deffunction_based_view(request):...@universal_permission_required('my_app.my_permission')classClassBasedView(View):...classClassBasedView(View):@universal_permission_required('my_app.my_permission')defdispatch(self,request,*args,**kwargs):...

Inheritance

装饰视图类的子类继承装饰器。在下面的示例中DerivedView继承 @login_requireddecorator来自其基类:

fromdjango_universal_view_decoratorimportuniversal_view_decorator@universal_view_decorator(login_required)classBaseView(View):...@universal_view_decorator(permission_required('my_app.my_permission'))classDerivedView(View):...

首先应用继承的基类修饰符。上面的示例对^{tt23}具有相同的效果$ 像这样在urlconf中装饰它:

urlpatterns=[url(r'^derived_view/',permission_required('my_app.my_permission')(login_required(DerivedView.as_view()))),]

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java为什么GetScaleInstance()不起作用?   如何筛选日期列表?   java启动文件中缺少以下必填字段:<jnlp>   Java:使枚举绑定到不同的字符串值   使用Java从sharepoint下载文件   Java的LinkedList中的链表peek和元素   java处理终止socket“客户端”的正确方法是什么   html从字符串java/gwt解析htmltags   swing“awteventque0”java。lang.NullPointerException在保存JTable时(DefaultTableModel)   java将数据从JSON ArrayList加载到spinner中   classloader我可以从外部JAR文件的另一个包中重新加载Java类吗?   用于多(并发)测试执行的java多浏览器配置文件?   java IntelliJ Idea标志着红色网络。工作良好的xml   如何设计以数据库为中心的Java Swing应用程序?   java RestrictionsFactoryUtil。in()与MySQL配合使用,与MS SQL Server配合使用失败。需要可行的解决办法