Django: ¿por qué debería usar el render_to_response en absoluto?

considera esto:

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

Por un lado, render es más limpio y más pythonico. Por otro lado, utilizas la request como tu primer argumento que considero redundante y confuso. Entonces comencé a preguntarme sobre las diferencias más grandes …

De acuerdo con los documentos :

render () es lo mismo que una llamada a render_to_response () con un argumento context_instance que fuerza el uso de un RequestContext.

Entonces la diferencia está solo en usar RequestContext. Entonces, ¿qué es importante sobre RequestContext? Veamos los documentos de nuevo :

una clase de contexto especial […] actúa de forma ligeramente diferente que el django.template.Context normal. La primera diferencia es que toma una HttpRequest como primer argumento.

De acuerdo. Eso apenas importa en absoluto

La segunda diferencia es que rellena automáticamente el contexto con algunas variables, de acuerdo con su configuración TEMPLATE_CONTEXT_PROCESSORS […] Además de estas, RequestContext siempre usa django.core.context_processors.csrf […] deliberadamente está codificado en y no se puede desactivar con la configuración TEMPLATE_CONTEXT_PROCESSORS.

Entonces esta es la parte importante: asegurarse de que todos los procesadores de contexto funcionen correctamente, con énfasis en csrf. Entonces, para volver a mi primer ejemplo, estos son en realidad los mismos:

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

Ahora, el segundo ejemplo es obviamente mucho peor, todo parece lamentablemente complicado. Entonces mi gran pregunta es ¿Por qué usar render_to_response en absoluto? ¿Por qué no desaprobarlo?

Otras preguntas que te vienen a la mente:

  1. ¿No hay una forma mejor de aplicar RequestContext como el valor predeterminado?
  2. ¿Hay alguna forma de evitar pasar la request como argumento? Es terriblemente redundante. Encontré una publicación de blog que mostraba cómo hacer render_to_response en un decorador fácil de usar. ¿No podemos hacer algo similar con render ?
  3. ¿Hay algún pensamiento sobre este tema (si es un problema)? No veo nada de eso en la futura línea de tiempo de desaprobación . Encuentro especialmente confuso, considerando que el render produjo con django 1.3 específicamente para abordar los problemas con render_to_response , y que todos aceptan que no se debe usar render_to_response

Sé que parece un poco fuera de tema, pero espero obtener respuestas que expliquen por qué render_to_response está quedando y \ o ejemplos de casos de uso donde se render_to_response uso de render_to_response sobre el render (si hay alguno)

La mayoría de las aplicaciones usan render_to_response ya que era la opción predeterminada recomendada desde el principio hasta Django 1.3. El motivo de la coexistencia de ambos es histórico, render_to_response forzará la reescritura de una gran cantidad de código, que no es cortés en versiones menores. Sin embargo, en este hilo django-desarrollador dicen que sería posible incluir en la línea de tiempo de deprecation para 2.0.

Aquí está la cita de Russell Keith-Magee , uno de los desarrolladores principales de Django. Keith-Magee responde una pregunta publicada por Jacob Kaplan-Moss, otro contribuyente de Django que plantea la cuestión de desaprobar render_to_response :

Creo que debemos descartar render_to_response () a favor de render (). render_to_response () es solo render (request = None, …), ¿verdad? ¿Alguna razón para mantener ambos? No hay una razón particular para mantener a ambos alrededor, aparte del cambio de código que conllevaría la depreciación.

Y Keith-Magee responde:

Esto es algo que no tengo ningún problema para desaprobar en el cronogtwig 2.0, pero migrar cada uso de render_to_response () en los próximos 18 meses / 2 lanzamientos parece una medida extrema para hacer cumplir en toda la base de usuarios cuando el mantenimiento de render_to_response () no tomar un esfuerzo real.

Nadie ha estado discutiendo esa desaprobación, pero supongo que la respuesta a su pregunta es: no hay ninguna razón técnica, es solo su intención de no forzar una actualización en toda la base de código en una versión menor (al menos no importante).

Demasiado largo; no leí

When context processors are applied

Cuando utiliza RequestContext , las variables que proporciona directamente se agregan primero, seguido de las variables provistas por los procesadores de contexto. Esto significa que un procesador de contexto puede sobrescribir una variable que haya suministrado, por lo que debe evitar nombres de variables que se superpongan con los suministrados por los procesadores de contexto.


Veamos primero cómo se definen los métodos render_to_response y render .

 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) 

¿No hay una forma mejor de aplicar RequestContext como el valor predeterminado?

Nota en la sección Subclassing Context: RequestContext

Si está utilizando el render_to_response() Django para rellenar una plantilla con el contenido de un diccionario, su plantilla pasará una instancia Context por defecto (no un RequestContext )

Desde el código anterior, el método render_to_response llama al método loader.render_to_string donde el parámetro context_instance está marcado en esta línea .

Listado de código para el método 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) 

¿No podemos hacer un decorador fácil de usar con render ?

Podemos escribir decorador para esto, pero su pregunta es subjetiva. Si es fácil de usar o no, es difícil de decir. Depende mucho


¿Hay alguna forma de evitar pasar la solicitud como argumento?

render() es lo mismo que una llamada a render_to_response() con un argumento context_instance que fuerza el uso de un RequestContext .

class RequestContext se define en esta línea . Listado de código para la 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) 

La última pregunta no necesita una respuesta, si comprende cómo funciona el código detrás de Django.