【问题标题】:Django - Why should I ever use the render_to_response at all?Django - 为什么我应该使用 render_to_response 呢?
【发布时间】:2023-03-16 04:06:02
【问题描述】:

考虑一下:

return render(request, 'index.html', {..context..})
return render_to_response('index.html', {..context..})

一方面,render 更干净,更 Pythonic。另一方面,您使用request 作为您的第一个参数,我觉得这是多余且令人困惑的。所以我开始想知道更大的差异......

根据the docs

render() 与调用 render_to_response() 相同 强制使用 RequestContext 的 context_instance 参数。

所以区别只在于使用RequestContext。那么 RequestContext 有什么重要的呢?来看看docs again

一个特殊的 Context 类 [...] 的行为与 正常的 django.template.Context。第一个区别是它需要 一个 HttpRequest 作为它的第一个参数。

好的。这一点都不重要

第二个区别是它自动填充上下文 根据您的 TEMPLATE_CONTEXT_PROCESSORS 有几个变量 设置 [...] 除了这些,RequestContext 总是使用 django.core.context_processors.csrf [...] 它是故意硬编码的 在并且不能被 TEMPLATE_CONTEXT_PROCESSORS 关闭 设置。

所以这是重要的部分 - 确保所有上下文处理器正常工作,重点是 csrf。所以说真的,回到我的第一个例子,这些实际上是一样的:

return render(request, 'index.html', {...})
return render_to_response('index.html', {...}, context_instance=RequestContext(request))

现在,第二个例子显然要糟糕得多,整个事情似乎过于复杂了。所以我最大的问题是为什么要使用render_to_response?为什么不弃用它?

想到的其他问题:

  1. 难道没有更好的方法将RequestContext 强制为默认值吗?
  2. 有没有办法避免将request 作为参数传递?这是非常多余的。我发现 a blog post 展示了如何将 render_to_response 变成一个易于使用的装饰器。我们不能用render 做类似的事情吗?
  3. 有没有考虑过这个问题(如果它是一个问题的话)?我在future deprecation timeline 中什么也没看到。考虑到 render 是由 django 1.3 specifically to address the problems with render_to_responseeveryone agrees you shouldn't use render_to_response 产生的,我觉得这特别令人困惑

我知道这似乎有点离题,但我希望得到答案来解释为什么 render_to_response 会留下来和\或使用 render_to_response 的用例示例将优于 @987654340 @(如果有的话)

【问题讨论】:

    标签: django


    【解决方案1】:

    大多数应用程序都使用render_to_response,因为它是从一开始直到 Django 1.3 的默认推荐选项。两者共存的原因是历史性的,弃用render_to_response会强制重写大量代码,在小版本中是不礼貌的。但是in this django-developer thread 他们说可以将其包含在 2.0 的弃用时间表中。

    这是 Django 的核心开发人员之一Russell Keith-Magee 的引述。 Keith-Magee 回答了 Jacob Kaplan-Moss 发布的问题,另一位 Django 贡献者提出了弃用 render_to_response 的问题:

    我认为我们应该弃用 render_to_response() 以支持 render()。 render_to_response() 只是 render(request=None, ...),对吧?任何 保留两者的理由?没有什么特别的理由要保留这两者,除了弃用会带来的代码混乱。

    Keith-Magee 回答:

    这是我在 2.0 上弃用的问题 计划,但将每次使用 render_to_response() 迁移到 下一个 18 个月/2 个版本似乎是强制执行的极端措施 维护 render_to_response() 时的整个用户群不会 付出任何真正的努力。

    没有人讨论过这种弃用,但我想您的问题的答案是:没有技术原因,只是他们不打算在次要(至少没有主要)版本中强制更新所有代码库。

    【讨论】:

    • 这是一个比另一个更好的答案。征得您的许可,我计划对该主题进行更多研究,并在将其标记为正确之前编辑您的答案以包含引号和其他内容。这个链接有来自 django 的核心开发者之一的答案。谢谢你
    【解决方案2】:

    太长了;没读过

    When context processors are applied

    当您使用RequestContext 时,首先添加您直接提供的变量,然后是上下文处理器提供的任何变量。这意味着上下文处理器可能会覆盖您提供的变量,因此请注意避免与上下文处理器提供的变量名称重叠。


    让我们先看看render_to_responserender这两个方法是如何定义的。

    def render_to_response(*args, **kwargs):
        """
        Returns a HttpResponse whose content is filled with the result of calling
        django.template.loader.render_to_string() with the passed arguments.
        """
        httpresponse_kwargs = {'content_type': kwargs.pop('content_type', None)}
    
        return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)
    
    def render(request, *args, **kwargs):
        """
        Returns a HttpResponse whose content is filled with the result of calling
        django.template.loader.render_to_string() with the passed arguments.
        Uses a RequestContext by default.
        """
        httpresponse_kwargs = {
            'content_type': kwargs.pop('content_type', None),
            'status': kwargs.pop('status', None),
        }
    
        if 'context_instance' in kwargs:
            context_instance = kwargs.pop('context_instance')
            if kwargs.get('current_app', None):
                raise ValueError('If you provide a context_instance you must '
                                 'set its current_app before calling render()')
        else:
            current_app = kwargs.pop('current_app', None)
            context_instance = RequestContext(request, current_app=current_app)
    
        kwargs['context_instance'] = context_instance
    
        return HttpResponse(loader.render_to_string(*args, **kwargs),
                            **httpresponse_kwargs)
    

    难道没有更好的方法将 RequestContext 强制为默认值吗?

    注意部分Subclassing Context: RequestContext

    如果您使用 Django 的 render_to_response() 快捷方式来使用字典的内容填充模板,则默认情况下您的模板将被传递一个 Context 实例(而不是 RequestContext

    从上面的代码中,方法render_to_response 调用方法loader.render_to_string,其中context_instance 参数在this line 中被检查。

    方法render_to_string的代码清单

    def render_to_string(template_name, dictionary=None, context_instance=None,
                         dirs=None):
        """
        Loads the given template_name and renders it with the given dictionary as
        context. The template_name may be a string to load a single template using
        get_template, or it may be a tuple to use select_template to find one of
        the templates in the list. Returns a string.
        """
        dictionary = dictionary or {}
        if isinstance(template_name, (list, tuple)):
            t = select_template(template_name, dirs)
        else:
            t = get_template(template_name, dirs)
        if not context_instance:
            return t.render(Context(dictionary))
        # Add the dictionary to the context stack, ensuring it gets removed again
        # to keep the context_instance in the same state it started in.
        with context_instance.push(dictionary):
            return t.render(context_instance)
    

    我们不能用render做简单易用的装饰器吗?

    我们可以为此编写装饰器,但您的问题是主观的。它是否易于使用很难说。这很大程度上取决于


    有没有办法避免将请求作为参数传递?

    render() 与使用context_instance 参数调用render_to_response() 相同强制使用RequestContext

    class RequestContext 定义为 in this lineclass RequestContext 的代码清单

    class RequestContext(Context):
        """
        This subclass of template.Context automatically populates itself using
        the processors defined in TEMPLATE_CONTEXT_PROCESSORS.
        Additional processors can be specified as a list of callables
        using the "processors" keyword argument.
        """
        def __init__(self, request, dict_=None, processors=None, current_app=None,
                use_l10n=None, use_tz=None):
            Context.__init__(self, dict_, current_app=current_app,
                    use_l10n=use_l10n, use_tz=use_tz)
            if processors is None:
                processors = ()
            else:
                processors = tuple(processors)
            updates = dict()
            for processor in get_standard_processors() + processors:
                updates.update(processor(request))
            self.update(updates)
    

    如果您了解 Django 背后的代码实际上是如何工作的,那么最后一个问题不需要答案。

    【讨论】:

    • 虽然这确实在我的帖子中扩展了一点,但我不认为这是一个答案(还)。你只是在重复解释并向我展示源代码,这两个都是我自己阅读和检查的。这里没有什么可以回答我的大问题,即 为什么render_to_response 仍然存在(什么?如果你想使用上下文处理器保留的名称?来吧,这几乎不是理由完全)。我知道 RequestContext 需要实际请求作为其初始化的一部分,但我仍然不完全相信没有办法避免将其用作参数
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-03
    • 1970-01-01
    • 2012-04-08
    • 2017-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多