2011-07-17 76 views
1

我的应用程序中有以下装饰器,它检查当前用户是否创建了任何位置对象,并将它们重定向到另一个URL(如果它们没有)。Django将模型名称作为参数传递给装饰器

def location_required(f): 
    def wrap(request, *args, **kwargs): 
     locations = Location.objects.filter(user=request.user) 
     if locations.count() == 0: 
      return HttpResponseRedirect("/") 
     return f(request, *args, **kwargs) 
    wrap.__doc__=f.__doc__ 
    wrap.__name__=f.__name__ 
    return wrap 

我想为其他模型有类似的功能。我不希望创建多个装饰器,而是希望能够将模型名称作为参数传递(也可能是重定向到的url)。

这是可能的,我需要做些什么改变?

任何意见将不胜感激。

谢谢。

回答

1

绝对有可能。它可能最终看起来像下面这样(未经)代码:

def object_required(model_class, redirect_url): 
    def location_required(f): 
     def wrap(request, *args, **kwargs): 
      locations = model_class.objects.filter(user=request.user) 
      if locations.count() == 0: 
       return HttpResponseRedirect(redirect_url) 
      return f(request, *args, **kwargs) 
     wrap.__doc__=f.__doc__ 
     wrap.__name__=f.__name__ 
     return wrap 
    return location_required 

所有我在这里所做的是增加包装的另一层。您的原始装饰器自定义传入的函数f。我的外层自定义您的装饰器。你会以同样的方式使用它:在处理模型类另一个函数包装现有装饰的

@object_required(Location, '/') 
def my_view_func(request) 
    #your view code 
+0

感谢您的帮助! – Dan

2

加雷的做法和重定向URL是否正确。我建议以下的小变化:的

  • 使用exists(),而不是比较count()
  • 使用django.utils.functional.wraps更新包函数,而不是手动设置__name____doc__
  • wrap函数中的locations变量被错误命名,现在它可能是任何模型实例。

这给:

from django.utils.functional import wraps 

def object_required(model_class, redirect_url="/"): 
    # model_class and redirect_url are available to all inner functions 
    def decorator(f): 
     # this is called with f, the function being decorated 
     def wrapper(request, *args, **kwargs): 
      # this is called each time the real function is executed 
      instances = model_class.objects.filter(user=request.user) 
      if not instances.exists(): 
       return HttpResponseRedirect(redirect_url) 
      return f(request, *args, **kwargs) 
     return wraps(f)(wrapper) 
    return decorator 

在视图:

@object_required(Location, "/") 
def my_view_function(request): 
    # your view code 
+0

谢谢。在整个项目中重用的最佳位置是哪里?一个单独的应用程序仅用于装饰器功能是否过分矫枉过正? – Dan

+0

也许创建一个'utils'应用程序,并将装饰器放在'utils.decorators'中。 – Alasdair