以哪种顺序排序我的中间件路径匹配要求?

时间:2012-05-24 18:11:51

标签: django django-views

我创建了一个中间件,允许我使用字典列表为我的任何视图指定一些访问规则。这些词典中的每一个都是这样的:

REQUIREMENTS=(
    {'viewname':'addtag',
     'permissions':'can_add_tags'},
    {'regex':re.compile(r'^somestart'),
    'user_check':lambda request:request.user.username=='sam'}
)

在我的中间件中,我会尝试找出哪些要求与当前请求相匹配。为此,我过滤了完整的REQUIREMENTS,在过滤函数中,我使用此代码检查路径是否匹配:

def process_request(self,request):

    def path_matches(self,req):
        path_matches = False

        if  (req.has_key('url') and req['url'] == request.path ) or\
            (req.has_key('regex') and req['regex'].search(request.path)) or\
            (req.has_key('viewname') and resolve(request.path).url_name==req['viewname']):
            path_matches=True

        return path_matches

    requirements = filter(path_matches,REQUIREMENTS)
    # now use the returned requirements to determine if a user
    # matches the requirement and

我现在的问题是:我应该以哪种顺序使用支票?很明显,检查网址是最快的,所以这必须是第一个。但问题是如果正则表达式搜索或django的url解析函数应该首先遵循。

由于我现在没有任何表现问题,这更像是一个学术问题。如果有人能够有更好的解决方案来解决这个问题,那就更好了。


修改

对给定的答案做出反应:我要做的是创建一种可以在一个文件中限制几个外部应用程序的视图的可能性。所以装饰者不是一个选择,只要我不想做这样的事情:

from ext_app1 import view1,view2
from ext_app2 import view3

@permission_required('can_do_stuff')
def view1_ext(*args,**kwargs):
    return view1(args,kwargs)

每次更改权限时都会导致重写url规范。我想避免这种情况。另外,我的解决方案允许user_check函数对用户进行检查,如下所示:

def check_user(user):
    if len(Item.objects.get(creator=user,datetime=today)) > 3:
        return False
    return True

这将是一种简单的方法,即限制用户每天可以上传的项目数量。 (好的,也可以使用user_passes_test)。

还有一件事是,我有时只想在请求是POST时检查权限,或者请求是否包含某个键:值对(如'action':'delete'应该需要权限,而'action':'change'任何人都应该允许1}}。这也可以通过自定义装饰器来完成,但是只要我需要一个新的检查,我就需要一个新的装饰器。

2 个答案:

答案 0 :(得分:1)

您可能正在寻找user_passes_test decorator

您可以装饰所需的视图,而不是使用中间件。

代码如下所示:

from django.contrib.auth.decorators import user_passes_test

@user_passes_test(lambda user: user.has_perm('model.can_add_tags') \
                                and user.username == 'sam')
def my_view(request):
    ...  

答案 1 :(得分:1)

如果您使用的是内置user authentication and permissions systemdjango.contrib.auth)的Django,那么您应该考虑使用它提供的视图装饰器而不是中间件。这些有几个优点:

  • 一起更改的代码位于同一位置,即更改视图代码时更有可能需要更改特定视图的权限,而不是更改其他权限时。
  • 您不必自己编写大量代码,这样可以使您的项目更小,更易于维护。

对于简单情况,您可以使用login_requiredpermission_required装饰器,对于更复杂的条件,user_passes_test装饰器允许您检查用户是否通过了您需要指定的任何条件

对于视图函数(example is lifted from the documentation),代码看起来像这样:

from django.contrib.auth.decorators import permission_required

@permission_required('polls.can_vote')
def my_view(request):
    ...

如果您使用的是class-based views,那么它看起来会有所不同(同样,这个example is lifted from the documentation):

from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView

class ProtectedView(TemplateView):
    template_name = 'secret.html'

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super(ProtectedView, self).dispatch(*args, **kwargs)

如果你有充分的理由不使用Django的权限系统,那么你仍然可以采用类似的方法。 code for the django.contrib.auth decorators可以很容易地用作你自己的装饰者的基础。