Django: Por que é RequestContext conjunto como context_instance?
-
06-07-2019 - |
Pergunta
Parece mais documentação recomenda:
template_values = {}
template_values["foo"] = "bar"
return render_to_response(path, template_values, context_instance=RequestContext(request)
Por que não usar:
template_values = RequestContext(request)
template_values["foo"] = "bar"
return render_to_response(path, template_values)
Solução
RequestContext
não herda de dict
, e como tal não é garantido para implementar todos os métodos de dict
(e não), e todas as funções que operam em dicts pode não funcionar, também. Por último, não há nenhuma razão para; é melhor considerá-lo um objeto opaco cuja implementação pode mudar. Usando um dict
para fornecer o contexto do modelo tem todos os benefícios e nenhum dos inconvenientes de RequestContext
.
Atualização
Para produzir menos código clichê, aqui estão duas funções utilitárias que eu uso. Eu colocá-los em um arquivo shortcuts.py na base do meu projeto.
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
Outras dicas
Em relação ao "código de caldeira-plate", isso já está embutido no Django. Basta usar o ponto de vista genérico:
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..})
sido batendo minha cabeça em Django clichê por um tempo agora. Django tem (pelo menos) três funções muito semelhantes para render molde, cada um com um grau variável de shortcutedness:
django.shortcuts.render_to_response
django.template.loader.render_to_string
django.views.generic.simple.direct_to_template
Parece que pelo menos dois deles (provavelmente render_to_response e direct_to_template) poderia ser reformulado em um único, menos boilerplatish, atalho.
django.views.generic.simple.direct_to_template
é quase bom o suficiente por conta própria, mas, infelizmente, coloca argumentos de palavra-chave em um dicionário params
, tornando-se incompatível com a maioria dos usos de render_to_response
(modelo de refatoração muitas vezes é necessário quando se muda de render_to_response
para direct_to_template
). render_to_response
, que vive ironicamente em django.shortcuts, dificilmente é um atalho bem pensada. Deve converter argumentos chave para parâmetros de modelo e que o argumento context_instance
deselegante é muito longo para tipo ... muitas vezes.
Eu tenho tentado um atalho mais úteis. Observe o uso de *request_and_template_and_params
para prevenir conflitos entre os nomes dos parâmetros do modelo e nomes de argumentos posicionais.
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)
Eu encontrei esta solução aqui e i modificate apenas um pouco desatualizada:
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
Na sequência do código "caldeira de placa", você poderia render a um modelo no seu urls.py
Por exemplo:
url(r'^about/$', direct_to_template, {'template': 'about.html',}),