【问题标题】:How to return error message in decorator in Django?如何在 Django 的装饰器中返回错误消息?
【发布时间】:2020-06-14 04:46:36
【问题描述】:

我写了自己的装饰器,它检查当前登录的用户是否是老师。如果没有,装饰器会将用户重定向到登录页面,但对于用户来说有点混乱,所以我想传递一条消息,为什么用户被重定向到登录页面,但我不知道该怎么做。

# here is my decorator:
def teacher_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url='login'):
    '''
    Decorator for views that checks that the logged in user is a teacher,
    redirects to the log-in page if necessary.
    '''
    actual_decorator = user_passes_test(
        lambda u: u.is_active and u.is_teacher,
        login_url=login_url,
        redirect_field_name=redirect_field_name
    )
    if function:
        return actual_decorator(function)
    return actual_decorator

【问题讨论】:

    标签: python django python-decorators


    【解决方案1】:

    您可以将 Django 的内置 messages 与自定义装饰器一起使用。

    为此,Django 为匿名用户和经过身份验证的用户提供了对基于 cookie 和基于会话的消息传递的全面支持。

    在您的情况下,示例如下:

    装饰器.py

    # Import Django messages
    from django.contrib import messages
    
    # Custom Decorator
    def teacher_required(function):
        def _function(request, *args, **kwargs):
            if not request.user.is_teacher:
                messages.info(request, 'Custom message to user')
                return HttpResponseRedirect(reverse('app:url_name'))
            return function(request, *args, **kwargs)
    
        return _function
    

    views.py

    from django.utils.decorators import method_decorator
    from django.contrib.auth.decorators import login_required
    from foo.decorators import teacher_required
    
    @method_decorator([login_required, teacher_required], name='dispatch')
    class MyView(TemplateView):
        template_name = 'template.html'
    

    在这种情况下,您必须使用@method_decorator() 调用装饰器,并首先传递login_required,以确保用户在检查他是否是老师之前已登录。

    如果你想实现一个更优雅的系统,我在github上找到了一个例子。

    【讨论】:

      【解决方案2】:

      Django 带有内置消息框架。 https://docs.djangoproject.com/en/3.0/ref/contrib/messages/

      如果您必须按照以下步骤使用:

      确保您在 settings.py 中的已安装应用中添加了 django 消息。

      INSTALLED_APPS = [
          ...
      
          'django.contrib.messages',
      
          ...
      ]
      

      通过将以下行添加到您的 settings.py 中来配置消息存储:

      MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
      

      在返回actual_decorator之前在你的装饰器中添加消息:

      messages.warning(request, 'Access restricted, for teachers only')
      

      如果您使用引导程序,您可以通过以下方式在模板中显示更改:

      {% if messages %}
          {% for message in messages %}
          <div class="alert alert-warning">
          {{ message }}
          </div>
          {% endfor %}
      {% endif %}
      

      可在此处找到引导警报的文档:https://getbootstrap.com/docs/4.0/components/alerts/

      【讨论】:

        【解决方案3】:

        装饰器是一个函数,它以要装饰的函数(或类)为输入,并对其进行一些更改。我会选择两种方法,如果第一种方法是真的,那么他们是真正的老师,否则他们不是,在这种情况下给他们一个有效的输出。

        def teacher_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url='login'):
            '''
            Decorator for views that checks that the logged in user is a teacher,
            redirects to the log-in page if necessary.
            '''
            actual_decorator = user_passes_test(
                lambda u: u.is_active and u.is_teacher,
                login_url=login_url,
                redirect_field_name=redirect_field_name
            )
        

        我们可以简单地为装饰器user_passes_test做一个用例

        from django.contrib.auth.decorators import user_passes_test
        
        def teacher_required(function=None):
            def is_teacher(u):
                return Shopkeeper.objects.filter(user=u).exists()
            actual_decorator = user_passes_test(is_teacher)
            if function:
                return actual_decorator(function)
            else:
                return actual_decorator
        
        

        然后您可以将其实现为:

        @login_required
        @teacher_required
        def teacher_view(request):
            # ...
            pass
        
        @login_required
        def not_teacher_view(request):
            # ...
            pass
        
        

        我希望你明白这一点,为清楚起见,请参阅 this

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-11-14
          • 2013-04-28
          • 2017-02-27
          • 2012-09-25
          • 1970-01-01
          • 2011-07-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多