2010-03-20 51 views
5

我正在通过python从PHP背景转换到Django开发,主要是为了解决我认为最有意义的MVC(或MVT),尽管在此模式中我在我的观点中开始注意到许多重复的代码。Django - 避免在视图中重复代码的提示

例如,登录时我有关于用户的信息,我希望在每个页面上都显示,但是当使用render_to_response并且在每个视图中都需要时,我必须抓取信息并将其传递给render_to_response函数。

我想知道什么是最有效的方法来减少重复的代码,这实际上将在特定的应用程序的所有视图中需要。

在此先感谢。

回答

4

就我个人而言,我是装饰者的狂热粉丝,这是一个并不特定于Django的python特性。装饰器是高级函数之上的完美语法糖,它们对于减少视图中的样板文件尤其有用 - 您可以快速定义一个通用包装器函数,在该函数中可以将重复代码轻松重复使用并且方便停止重构。

向他们展示可能比向他们解释他们如何工作更容易。这里是一个简化的视图例如:

def listpage(request): 
    return HttpResponse(render_to_string("itemlist.html", { 
     "items": Item.objects.filter(visible=True).order_by("-modifydate") 
    })) 

def itemlist_tags(request, tags): 
    return HttpResponse(render_to_string("itemlist.html", { 
     "items": Item.objects.tagged(name=tags).filter(visible=True).order_by("-modifydate"), 
    })) 

...但后来说,你想使这些页面要求用户登录时,可能会添加像这样登录代码:

def listpage(request): 
    if not request.user.is_authenticated(): 
     return f(request, *args, **kwargs) 
    else: 
     return HttpResponse(render_to_string("itemlist.html", { 
      "items": Item.objects.filter(visible=True).order_by("-modifydate") 
     })) 

def itemlist_tags(request, tags): 
    if not request.user.is_authenticated(): 
     return f(request, *args, **kwargs) 
    else: 
     return HttpResponse(render_to_string("itemlist.html", { 
      "items": Item.objects.tagged(name=tags).filter(visible=True).order_by("-modifydate"), 
     })) 

..即使对于一个人为的例子,它开始变得明显更大和重复。你可以让你的功能与装饰再次苗条,像这样:

从装饰进口装饰

@decorator 
def loginrequired(f, request, *args, **kwargs): 
    if request.user.is_authenticated(): 
     return f(request, *args, **kwargs) 
    else: 
     return HttpResponseRedirect("/") 

@loginrequired 
def listpage(request): 
    return HttpResponse(render_to_string("itemlist.html", { 
     "items": Item.objects.filter(visible=True).order_by("-modifydate") 
    })) 

    @loginrequired 
def itemlist_tags(request, tags): 
    return HttpResponse(render_to_string("itemlist.html", { 
     "items": Item.objects.tagged(name=tags).filter(visible=True).order_by("-modifydate"), 
    })) 

@loginrequired 
def another_such_function(request): 
    (...) 

@loginrequired 
def and_again(request): 
    (...) 

会发生什么是装饰功能在函数定义的时间执行。在我的例子中,'f'是一个代表装饰器应用到的函数的对象,您可以以无数的方式操纵它。

这需要decorator library,它可以在PyPI上免费获得,就像许多好的python缺点一样。

你不需要这个库来编写装饰函数,但它是有帮助的,特别是在开始时。他们可以做更多 - 任何可调用的可以是装饰器;你可以修饰类方法并截取self变量;装饰可以链接起来,就像这样:

@second 
@first 
def originalfunction(*args): 
    (...) 

我会离开,你可以用这种简单的高阶函数manpipulation做探索适合你,应该这个概念激起你的食欲。我还有更多的例子,对于你或任何其他好奇的新Python爱好者。祝你好运。

+1

顺便说一下,第二个假视图中的'tagged()'函数不是拼写错误;它是我写给django-tagging应用程序的一个简化的界面,也是以样板文件缩减的名义编写的,这个好奇将会在这里找到:http://www.djangosnippets.org/snippets/1942/ – fish2000 2010-03-20 21:58:31

+0

非常有帮助,谢谢,装饰者似乎对我有很多额外的用途。 – neopickaze 2010-03-21 19:15:50

5

将通用代码封装在一个函数中,并从不同的视图调用它。听起来微不足道,但它是99%这种需求的解决方案。

对于一个更具体的答案,你将不得不展示你想运行的代码的更具体的例子。

5

抽象出共同内容有两种主要方法。

Context processors最适合传递您知道每个视图都需要的数据。

Template tags - 特别是包含标签 - 对于渲染单独的页面区域在几个模板上是相同的。

3

另外,不要忘了generic views!在90%的情况下,你可以包装object_list或object_detail并保存一些代码。