智能视图类(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@RestController(“/xxx”)映射   eclipse获取Java项目中所有构建错误的最快方法是什么?   java活动到为底部导航栏保存片段的活动永远不会到达片段,而是到由FrameLayout保存片段的活动   从SpringBoot 2.2.2 t SpringBoot 2.3.7迁移时,创建名为“tomcatServletWebServerFactory”的bean时发生java错误   java如何删除声音片段?   从客户机实现的角度来看,我可以比较Java可调用和角度可观测(RxJS)吗   C++中的java命名空间私有成员   Java中的字数计数给出错误的输出   java我应该为简单的switch语句使用多态性吗?   sql如何修复java中连接到数据库的网络协议错误(SQLNonTransient)   java如何在Kotlin中使用Lambda handleHavyContent()   javascript在安卓上以react native with JAVA执行dns srv请求   javacom。投递箱。果心NetworkIOException:软件导致的连接中止   Java中的“单代”垃圾收集器是什么?   java如何使用RecyclerView onCreate   java使用spring高效地扫描两个包的类路径   两个数组的java笛卡尔积   货币Java NumberFormat实例创建   java Spring引导到第三方的基本身份验证   JPA/Hibernate中带有JoinColumn的复合主键的java AnnotationException