I'm hoping to use a context processor or middleware to modify the values of the dictionary passed to render_to_response prior to the actual rendering. I have a messaging schema I'm trying to implement that would populate a message list based on the existence of a type of user that I'd like to search the context for prior to the rendering of the template.
Example:
def myview(...):
...
return render_to_response('template.html',
{'variable': variable},
)
and I'd like to be able to add additional information to the context on the existence of 'variable'.
How can I access 'variable' after my view defines it but before it gets to the template so that I can further modify the context?
use TemplateResponse:
from django.template.response import TemplateResponse
def myview(...):
...
return TemplateResponse(request, 'template.html',
{'variable': variable},
)
def my_view_wrapper(...):
response = my_view(...)
variable = response.context_data['variable']
if variable == 'foo':
response.context_data['variable_is_foo'] = True
return response
This is easy. If you have supplied just a little bit more code in your example the answer might have bit you.
# first build your context, including all of the context_processors in your settings.py
context = RequestContext(request, <some dict values>)
# do something with your Context here
return render_to_response('template.html', context)
Update to comment:
The result of a render_to_response() is an HTTPResponse object containing a template rendered against a Context. That object does not (to my knowledge) have a context associated with it. I suppose you could save the result of render_to_response() in a variable and then access the Context you passed it, but I'm not sure what problem you are trying to solve.
Did you modify the Context during rendering? If so you may find that the information is not there any longer because the Context has a scope stack which is pushed/popped during template processing.
You can create a dictonary for the context:
def myview(...):
c = dict()
c["variable"] = value
...
do some stuff
...
return render_to_response('template.html',c)
Maybe the RequestContext is the thing you are looking for.
Related
I have the following question for you. I want to know the best and elegant way to reuse some variable results obtained in a view in another one.
I'm trying to explain me better with an example.
I'have 2 differente app, app A and app B.
In app A views.py I have a lot of code to process data from the models with a creation of a lot of new variables.
Now, in app B I have the necessity to reuse some variables obtained in views.py app A, but I wonna write again the same code to get them.
Is there a way to achive my goal?
EDIT
Following the #sandeshdaundkar's suggestions I could overcome my problem creating a new function and call it in my views.py of each app.
I'm trying to achive this result but I'm not good at python's function and how call it inside my views.py.
I have created the following function in my_app/utility.py:
def my_func():
defaults = list(0 for m in range(13))
iva_debito = dict()
for year, month, totale in(Ricavi.objects.values_list( 'data_contabile__year', 'data_contabile__month').
annotate(totale=ExpressionWrapper(Sum(F('quantita') * F('ricavo')*(F('iva'))),
output_field=FloatField())).values_list('data_contabile__year', 'data_contabile__month', 'totale')):
if id not in iva_debito.keys():
iva_debito[id]=list(defaults)
index=month
iva_debito[id][index]=totale
iva_debito_totale={'IVA a Debito Totale': [sum(t) for t in zip(*iva_debito.values())],}
context= {
'iva_debito_totale':iva_debito_totale,
}
return context
And here my my_app/views.py:
...
from .utility import my_func
def iva(request):
data = my_func()
iva_debito_totale=data['iva_debito_totale']
context= {
'iva_debito_totale': iva_debito_totale,
}
return render(request, 'iva/iva.html', context)
I have solved it with the solution above.
def func_name():
# do calculation,
return context_for_view_one, obj_to_reuse
def view_one(request):
context, iva = func_name()
return render(context=context) # context to be used in view a
def view_two(request):
context, iva = func_name()
return render(context=iva) # iva to be used in view b
def iva(request):
data = func_name()
iva_debito_totale = data['iva_debito_totale']
return render(request, 'template.html', context={'totale': iva_debito_totale})
I hope this gives you an idea, we return 2 objects from common function. One which is to be used in view_one and others to be used in view_two. You can try something similiar
I ran into this problem while trying to capture POST data.
In Django 1.X, I structured my views like this:
def view_name(request, template_name='template.html'):
variable1 = data
variable2 = moreData
return render_to_response(template_name, locals(), context_instance=RequestContext(request))
Now, I see that render_to_response() has been deprecated, but I'm unsure how to port the code with all of the locals() calls.
Do I have to convert all of my views by building a dict with all desired variables?
Is there another way to port this to keep the locals() incorporation?
Thanks!
You can call this with:
def view_name(request, template_name='template.html'):
variable1 = data
variable2 = moreData
# …
return render(request, template_name, locals())
That being said, please do not use locals(). It makes it very unclear what exactly you pass to the template. Furthermore you often will pass more to the template than you want to. Finally most IDEs will say a variable is not used, and thus you might remove it, but it is in fact used in the template.
I'm trying to override my block template as described here:
https://github.com/wagtail/wagtail/issues/3857
I added a BooleanBlock inside the class and tried to use that value to change the template but I get an error "no attribute found".
class Features_Block(StructBlock):
title = CharBlock()
description = TextBlock(required=False)
use_other_template = BooleanBlock(default=False, required=False)
class Meta:
icon = 'list-ul'
def get_template(self, context=None):
if self.use_other_template:
return 'other_template.html'
return 'original_template.html'
I have found this thread which might be the answer but I don't understand how to implement it for my case:
https://github.com/wagtail/wagtail/issues/4387
The get_template method doesn't receive the block's value as a parameter, so there's no reliable way to vary the chosen template according to that value. You might be able to dig around in the calling template's context to retrieve the block value, as in Matt's answer, but this means the internals of Features_Block will be tied to the use of particular variable names in the calling template, which is a bad thing for reusable code.
(Accessing self.use_other_template doesn't work because self, the Features_Block object, doesn't hold on to the block value as a property of itself - it only serves as a translator between different representations. So, it knows how to render a given dictionary of data as HTML, but that dictionary of data is not something that 'belongs' to the Features_Block.)
get_template is called from the block's render method, which does receive the block value, so overriding render will allow you to vary the template based on the block value:
from django.template.loader import render_to_string
from django.utils.safestring import mark_safe
class Features_Block(StructBlock):
# ...
def render(self, value, context=None):
if value['use_other_template']:
template = 'other_template.html'
else:
template = 'original_template.html'
if context is None:
new_context = self.get_context(value)
else:
new_context = self.get_context(value, parent_context=dict(context))
return mark_safe(render_to_string(template, new_context))
Check the context that's passed to get_template.
class Features_Block(StructBlock):
title = CharBlock()
description = TextBlock(required=False)
use_other_template = BooleanBlock(default=False, required=False)
class Meta:
icon = 'list-ul'
def get_template(self, context=None):
if context and context['block'].value['use_other_template']:
return 'other_template.html'
return 'original_template.html'
Having two views
views.py
def followup(request):
''''''
marklist = report_template(request)
return render(request, 'incident/followup.html',{'somevar':somevar})
def report_template(request):
'''''
report=Report.objects.filter(report=report_id)
''''''
return render(request, 'incident/print.html',
{'report':report})
I am calling one method inside another method.Calling report_template method into followup method.followup method also have variable to render in template.
How to pass the variable of report_template method to followup method and make it display in template.
Thanks
One way to achieve this would be to create a helper method that returns the report or the context needed by both the methods. The issue here is you are returning a HTTPResponse object, and it is cleanest to use helper method here:
def get_report(request):
report=Report.objects.filter(report=report_id)
#do more processing here.
#returning a dict is probably safest here, because, in the calling method, `.get()` would not throw an error if key is not present.
return {'report': report, 'somevar': somevar}
def followup(request):
marklist = get_report(request).get('somevar')
return render(request, 'incident/followup.html',{'somevar':marklist})
def report_template(request):
report = get_report(request).get('report')
return render(request, 'incident/print.html',
{'report':report})
You can not do that with views, you have to look up for templatetags, which is a better way to do so in Django (a view accepts a Request argument and returns an HttpResponse variable).
See https://docs.djangoproject.com/en/dev/howto/custom-template-tags/.
Using templatetags makes your code reusable, by factoring what you do in views.
What is the best practice for writing a thread-safe context processor in Django?
Say, I want to pass some variables to templates, which
are set in the corresponding views, and could be different for
different view-template pairs.
One solution would be to manually pass each variable in the context:
return render_to_response('template.html', {'var1':var1,... 'var10':var10},
context_instance=RequestContext(request))
To keep it DRY, however, I would rather use a context processor. But I
worry about thread safety as it seems to require a global store.
Here is my solution using a context processor, which ties each
variable to the request. Thanks for your comments and suggestions.
In context_processor.py:
store = {}
def add_context(request, key, value):
if request not in store:
store[request] = {}
store[request][key] = value
return
def misc_context_processor(request):
return store.pop(request,{})
In views.py:
import context_processor
def view(request):
...
if x == y:
context_processor.add_context(request,'var1','value1')
else:
context_processor.add_context(request,'var2','value2')
...
return render_to_response('template.html', {},
context_instance=RequestContext(request))
In settings.py:
TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.request',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
...,
'appname.context_processor.misc_context_processor',
)
context_processors are for context variables you want set up in every view to be available for every template. If you have view specific context, that rightfully belongs in the view. If you're trying to push the construction of view specific context dictionaries off to a context_processor then your really creating an unnecessary headache and a landmine if anyone else ever has to touch your code. Use the tools for what they are meant to be used for.
Additionally it's a lot easier to write and read:
context = {
'var1': value1,
'var2': value2,
}
than it is to try to figure out what this is doing:
context_processor.add_context(request, 'var1', value1)
context_processor.add_context(request, 'var2', value2)
Or maybe what your want is like this:
def view(request):
context = {}
...
if x == y:
context['var1'] = value1
else:
context['var2'] = value2
...
return render_to_response('template.html', context,
context_instance=RequestContext(request))
Or maybe even use context.update({ 'var1': value1 })
I'm missing how the second one is more DRY. Considering you're going to have to do that in every view that needs those variables anyway...
If you have repeatable context generation use class based views to abstract that out in a reasonable fashion. If you really just have 10variables and each template only needs some of them (but they vary from template to template) then just simply make all of them available to all templates. As long as the generation isn't expensive this works great, and keep in mind that querysets are lazy so if you never evaluate them they never hit the db