django: ¿Por qué se establece RequestContext como context_instance?
-
06-07-2019 - |
Pregunta
Parece que la mayoría de la documentación recomienda:
template_values = {}
template_values["foo"] = "bar"
return render_to_response(path, template_values, context_instance=RequestContext(request)
¿Por qué no uso:
template_values = RequestContext(request)
template_values["foo"] = "bar"
return render_to_response(path, template_values)
Solución
RequestContext
no hereda de dict
, y como tal no se garantiza que implemente todos los métodos de dict
(y no 't), y cualquier función que opere en dicts puede que tampoco funcione. Por último, no hay razón para hacerlo; Es mejor considerarlo un objeto opaco cuya implementación puede cambiar. El uso de un dict
para proporcionar el contexto de la plantilla tiene todos los beneficios y ninguno de los inconvenientes de RequestContext
.
Actualizar
Para producir menos código repetitivo, aquí hay dos funciones de utilidad que uso. Los puse en un archivo shortcuts.py en la base de mi proyecto.
from django.template import RequestContext
def render_template(request, template, data=None):
"Wrapper around render_to_response that fills in context_instance for you."
response = render_to_response(template, data,
context_instance=RequestContext(request))
return response
def boilerplate_render(template):
"Factory function for creating simple views that only forward to a template"
def view(request, **kwargs):
response = render_template(request, template, kwargs)
return response
return view
Uso:
def my_view(request):
# Do stuff here...
return render_template(request, 'my_template.html', {'var1': 'value', etc..})
my_view2 = boilerplate_render('my_template2.html') # Takes no context parameters
Otros consejos
Con respecto al " código de placa de caldera " ;, esto ya está integrado en Django. Simplemente use la vista genérica:
from django.views.generic.simple import direct_to_template
def my_view(request):
# Do stuff here...
return direct_to_template(request, 'my_template.html', {'var1': 'value', etc..})
He estado golpeándome la cabeza en la placa repetitiva de Django por un tiempo. Django tiene (al menos) tres funciones muy similares para la representación de plantillas, cada una con un grado variable de atajo:
django.shortcuts.render_to_response
django.template.loader.render_to_string
django.views.generic.simple.direct_to_template
Parece que al menos dos de estos (probablemente render_to_response y direct_to_template) podrían refactorizarse en un solo atajo, menos repetitivo,
django.views.generic.simple.direct_to_template
es casi lo suficientemente bueno por sí solo, pero desafortunadamente pone argumentos de palabras clave en un dict params
, lo que lo hace incompatible con la mayoría de los usos de render_to_response
(la refactorización de plantilla a menudo es necesaria cuando se cambia de render_to_response
a direct_to_template
). render_to_response
, que irónicamente vive en django.shortcuts, no es un atajo bien pensado. Debería convertir los argumentos de palabras clave en parámetros de plantilla y ese argumento desgarbado context_instance
es demasiado largo para escribir ... a menudo.
He intentado un atajo más útil. Tenga en cuenta el uso de * request_and_template_and_params
para evitar conflictos entre nombres de parámetros de plantilla y nombres de argumentos posicionales.
def render(*request_and_template_and_params, **kwargs):
"""Shortcut for rendering a template with RequestContext
Takes two or three positional arguments: request, template_name, and
optionally a mapping of template parameters. All keyword arguments,
with the excepiton of 'mimetype' are added to the request context.
Returns a HttpResponse object.
"""
if len(request_and_template_and_params) == 2:
request, template_name = request_and_template_and_params
params = kwargs
else:
request, template_name, params = request_and_template_and_params
params = dict(params) # copy because we mutate it
params.update(kwargs)
httpresponse_kwargs = {'mimetype': params.pop('mimetype', None)}
context = RequestContext(request, params)
return HttpResponse(loader.render_to_string(
template_name, context_instance=context), **httpresponse_kwargs)
Acabo de encontrar esta solución aquí y Lo modifico solo un poco:
def render_to(template_name):
def renderer(func):
def wrapper(request, *args, **kw):
output = func(request, *args, **kw)
if not isinstance(output, dict):
return output
return render_to_response(template_name, output,
context_instance=RequestContext(request))
return wrapper
return renderer
@render_to('my_template.html')
def my_view(request):
# View code here...
return some_dict
Además de la "placa de caldera" código, puede renderizar a una plantilla en su urls.py
Por ejemplo:
url(r'^about/, direct_to_template, {'template': 'about.html',}),