2010-03-20 52 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並保存一些代碼。