Django - 避免在视图中重复代码的提示

时间:2010-03-20 09:41:08

标签: django views dry repeat

我正在通过python从PHP背景转变为Django开发,主要是为了解决我认为最有意义的MVC(或MVT),尽管在这种模式中我开始注意到很多在我的观点中重复了代码。

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

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

提前致谢。

4 个答案:

答案 0 :(得分:5)

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

要获得更具体的答案,您必须显示您想要运行的代码的更具体的示例。

答案 1 :(得分:5)

有两种主要方法可以抽象出常见的内容。

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

Template tags - 特别是包含标记 - 对于渲染页面中在几个模板上相同的区域非常有用。

答案 2 :(得分: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 import decorator

@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 morsels。

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

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

如果这个概念引起你的胃口,我将继续探索你可以用这种简单的高阶函数操作来做什么。对于你或任何其他好奇的新python爱好者,我还有更多的例子。祝你好运。

答案 3 :(得分:3)

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