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

yuv*_*uvi 22 django

考虑一下:

return render(request, 'index.html', {..context..})
return render_to_response('index.html', {..context..})
Run Code Online (Sandbox Code Playgroud)

一方面,render更清洁,更pythonic.另一方面,你使用request作为你的第一个参数,我觉得多余和混乱.所以我开始怀疑更大的差异......

根据文件:

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

所以区别仅在于使用RequestContext.那么RequestContext有什么重要意义呢?让我们看看文档:

一个特殊的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))
Run Code Online (Sandbox Code Playgroud)

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

想到的其他问题:

  1. 是不是有更好的方法来强制执行RequestContext默认值?
  2. 有没有办法避免request作为论点传递?这非常多余.我发现了一篇博客文章,展示了如何将render_to_response变成一个易于使用的装饰器.我们不能做类似的事render吗?
  3. 有没有想过这个问题(如果它是一个问题)?在将来的弃用时间表中我什么都看不到.我发现它特别令人困惑,考虑render专门用于解决render_to_response问题的 django 1.3 ,并且每个人都同意 你不应该使用 render_to_response

我知道它似乎有点偏离主题,但我希望得到的答案可以解释为什么render_to_response留下来和\或用例的例子,其中使用render_to_response将优先于render(如果有的话)

esa*_*uro 30

大多数应用程序都使用,render_to_response因为它从一开始就是Django 1.3的默认推荐选项.两者共存的原因是历史性的,弃用render_to_response将迫使大量代码被重写,这在次要版本中是不礼貌的.但是在这个django-developer线程中,他们说可以在2.0的弃用时间表中包含.

以下是Django核心开发人员之一Russell Keith-Magee的引用.Keith-Magee回答了Jacob Kaplan-Moss发布的问题,他是另一位提出贬值问题的Django贡献者render_to_response:

我认为我们应该弃用render_to_response()以支持render().render_to_response()只是渲染(request = None,...),对吗?有什么理由保持两者?没有什么特别的理由可以保留这两种方法,除了代价流失之外的贬值所需要的.

而Keith-Magee回答:

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

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


P̲̳*_*͓L̳ 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)
Run Code Online (Sandbox Code Playgroud)

是不是有更好的方法来强制RequestContext作为默认值?

请注意本节Subclassing Context: RequestContext

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

从上述方法的代码render_to_response调用该方法loader.render_to_string,其中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)
Run Code Online (Sandbox Code Playgroud)

我们不能简单地使用装饰器render吗?

我们可以为此编写装饰,但你的问题是主观的.如果它易于使用或不是很难说.这很大程度上取决于


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

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

class RequestContext在这一行中定义.代码清单class 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)
Run Code Online (Sandbox Code Playgroud)

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