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

发布于 2024-08-26 02:37:42 字数 279 浏览 6 评论 0原文

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

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

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

提前致谢。

I'm moving from a PHP background into Django development via python, mostly for the sake of tackling a MVC (or MVT) that I feel makes the most sense, although in this pattern I've started to notice a lot of repeated code in my views.

For example, when logged in I have information regarding the user that I would like to appear on every page, although when using render_to_response and in every view this is required I have to grab the information and pass it to the render_to_response function.

I'm wondering what would be the most efficient way to cut down on the duplicate code which would in essence be required in all views in a particular app.

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

§对你不离不弃 2024-09-02 02:37:42

就我个人而言,我是装饰器的忠实粉丝,装饰器是一个并非 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"),
        }))

...这开始变得明显更大且重复,即使对于人为的例子。您可以使用装饰器使您的函数再次精简,如下所示:

fromdecorator importdecorator

@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”是一个对象,表示应用装饰器的函数,您可以以无休止的方式对其进行操作。

这需要 装饰器库,它在 PyPI 上是免费的,就像许多好的 python 东西一样,你会寻找。

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

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

如果这个概念激起了您的兴趣,我将把对如此简单的高阶函数操作的探索留给您。对于您或任何其他好奇的新 Python 爱好者,我还有更多示例。祝你好运。

Personally I am a huge fan of decorators, which are a python feature that isn't specific to Django. Decorators are the perfect syntactic sugar on top of higher-order functions, and they're especially useful for reducing boilerplate in views -- you can quickly define a generalized wrapper function, in which you can put the repetitive code for easy reuse and convenient one-stop refactoring.

It's probably easier to show you than explain how they work. Here is a simplified view example:

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"),
    }))

... but then say you wanted to make these pages require the user to log in. You might add login code like so:

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"),
        }))

... which is starting to get notably bigger and repetitive, even for a contrived example. You can make your functions slim again with decorators, like so:

from 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):
    (...)

What happens is the decorator function is executed at the time of the function's definition. The 'f' in my example is an object representing the function that the decorator is applied to, which you can manipulate in unending ways.

This requires the decorator library, which is free on PyPI as are many good python morsels, you'll find.

You don't need the this library to write decorator functions, but it's helpful, especially in the beginning. They can do a whole lot more -- any callable can be a decorator; you can decorate class methods and intercept the self variable; decorators can be chained up, like so:

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

I'll leave the exploration of what you can do with such easy higher-order function manpipulation for you, should this notion whet your appetite. I have many more examples as well, for you or any other curious new python aficionados. Good luck.

淡忘如思 2024-09-02 02:37:42

将公共代码封装在一个函数中,并从不同的视图中调用它。听起来微不足道,但它可以满足 99% 的此类需求。

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

Encapsulate the common code in a function and call it from different views. Sounds trivial, but it's the solution for 99% of such needs.

For a more specific answer, you'll have to show a more concrete example of the code you want to run.

暖心男生 2024-09-02 02:37:42

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

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

模板标签 - 特别是包含标签 - 对于渲染单独的标签非常有用在多个模板上相同的页面区域。

There are two main ways for abstracting out common content.

Context processors are best for passing bits of data that you know you will need on every single view.

Template tags - especially inclusion tags - are useful for rendering separate areas of the page that will be the same on several templates.

Hello爱情风 2024-09-02 02:37:42

另外,不要忘记通用视图!在 90% 的情况下,您可以包装 object_list 或 object_detail 并节省一些代码。

Also, don't forget about generic views! In 90% of cases you can wrap object_list or object_detail and save yourself some code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文