code: def permission_required(perm, queryset=None,
                          login_url=None, raise_exception=False):
      
      def wrapper(cls):
          def view_wrapper(view_func):
              @wraps(view_func, assigned=available_attrs(view_func))
              def inner(self, request, *args, **kwargs):
                  # get object
                  obj = get_object_from_classbased_instance(
                          self, queryset, request, *args, **kwargs
                      )
  
                  if not request.user.has_perm(perm, obj=obj):
                      if raise_exception:
                          raise PermissionDenied
                      else:
                          return redirect_to_login(request, login_url)
                  return view_func(self, request, *args, **kwargs)
              return inner
          cls.dispatch = view_wrapper(cls.dispatch)
          return cls
      return wrapper
docs: Permission check decorator for classbased generic view
  
      This decorator works as class decorator
      DO NOT use ``method_decorator`` or whatever while this decorator will use
      ``self`` argument for method of classbased generic view.
  
      Parameters
      ----------
      perm : string
          A permission string
      queryset : queryset or model
          A queryset or model for finding object.
          With classbased generic view, ``None`` for using view default queryset.
          When the view does not define ``get_queryset``, ``queryset``,
          ``get_object``, or ``object`` then ``obj=None`` is used to check
          permission.
          With functional generic view, ``None`` for using passed queryset.
          When non queryset was passed then ``obj=None`` is used to check
          permission.
  
      Examples
      --------
      >>> @permission_required('auth.change_user')
      >>> class UpdateAuthUserView(UpdateView):
      ...     pass