Django - 我为什么要使用render_to_response呢?

时间:2014-01-27 00:05:42

标签: django

考虑一下:

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

一方面,render更清洁,更py。另一方面,你使用request作为你的第一个参数,我觉得这个参数多余且令人困惑。所以我开始怀疑更大的差异......

根据the docs

  

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

所以区别仅在于使用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_response,而everyone agrees you shouldn't use render_to_response
  4. ,我发现这一点特别令人困惑

    我知道这似乎有点偏离主题,但我希望得到的答案可以解释为什么render_to_response留下来和\或使用render_to_response的用例的例子首选超过render(如果有的话)

2 个答案:

答案 0 :(得分:30)

大多数应用使用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发布的问题,Jacob Kaplan-Moss是另一位提出贬值问题的Django贡献者render_to_response

  

我认为我们应该弃用render_to_response()以支持render()。   render_to_response()只是渲染(request = None,...),对吗?任何   有理由保持两者?除了代价流失之外,没有特别的理由要保持这两种情况。

Keith-Magee回答:

  

这是我在2.0上弃用没问题的   安排,但迁移每次使用render_to_response()   接下来的18个月/ 2个版本似乎是一个强制执行的极端措施   维护render_to_response()时没有整个用户群   采取任何实际的努力。

没有人一直在讨论这种弃用,但我想你的问题的答案是:没有技术原因,只是他们的意图是不强制对次要(至少没有主要)版本的所有代码库进行更新。

答案 1 :(得分:8)

太久了;没看过

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)< / p>

从上面的代码render_to_response方法调用方法loader.render_to_stringthis line中选中了context_instance参数。

方法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()render_to_response()的调用相同,context_instance参数会强制使用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背后的代码实际上是如何工作的,那么最后一个问题不需要答案。

相关问题