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

neo*_*aze 5 django views dry repeat

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

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

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

提前致谢.

fis*_*000 7

就我个人而言,我是装饰器的忠实粉丝,装饰器是一个不是 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"),
    }))
Run Code Online (Sandbox Code Playgroud)

...但是然后说你想让这些页面要求用户登录。你可以像这样添加登录代码:

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"),
        }))
Run Code Online (Sandbox Code Playgroud)

......即使是一个人为的例子,它也开始变得越来越大和重复。您可以使用装饰器使您的函数再次变瘦,如下所示:

从装饰器导入装饰器

@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):
    (...)
Run Code Online (Sandbox Code Playgroud)

发生的事情是装饰器函数在函数定义时执行。我的示例中的“f”是一个对象,表示装饰器应用于的函数,您可以以无休止的方式对其进行操作。

这需要装饰器库,它在 PyPI 上是免费的,你会发现很多好的 python 小点。

你不需要这个库来编写装饰器函数,但它很有帮助,尤其是在开始的时候。他们可以做更多的事情——任何可调用的都可以是装饰器;您可以装饰类方法并拦截self变量;装饰器可以链接起来,像这样:

@second
@first
def originalfunction(*args):
    (...)
Run Code Online (Sandbox Code Playgroud)

如果这个概念激起了您的胃口,我将留给您探索使用如此简单的高阶函数操作可以做什么。我还有更多示例,供您或任何其他好奇的新 Python 爱好者使用。祝你好运。


Eli*_*sky 5

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

有关更具体的答案,您必须显示要运行的代码的更具体示例.


Dan*_*man 5

抽象出共同内容有两种主要方式.

上下文处理器最适合传递您知道在每个视图上都需要的数据.

模板标签 - 尤其是包含标签 - 可用于呈现页面中在多个模板上相同的区域.