How to create a global variable for render_template()? - python

I have a simple task: to pass the same variable for different routes in the render_template() function. This value is in the base template and I need to pass it on every render_template() function. Can I set this value as a global so that I don't have to set it in every function for different routes?
#app.route('/hello')
def hello(name=None):
return render_template('hello.html', value=value)
#app.route('/bye')
def bye(name=None):
return render_template('bye.html', value=value)

To make variables available to templates without having to burden your routes with passing those variables, use Flask context processors. See https://flask.palletsprojects.com/en/2.1.x/templating/#context-processors for details an an example.
Here's one that I use to 'cache bust' CSS so that browsers won't accidentally use stale versions.
style_css_path = os.path.join(os.path.dirname(__file__), 'static', 'style.css')
style_css_mtime = int(os.stat(style_css_path).st_mtime)
#app.context_processor
def cache_busters():
return {
'style_css_mtime': style_css_mtime,
}
The base template can then do
<link rel="stylesheet"
href="{{ url_for('static', filename='style.css') }}?v={{ style_css_mtime }}" />
Any template that uses base.html inherits this behavior without routes that use that template having to pass style_css_time.

You could use a partial from functools like this:
from functools import partial
# Define a function that takes 2 parameters
def someFunc(a,b):
print(f'Called with a:{a} and b:{b}')
# Define a "partial" where the parameters are partially pre-filled in
p1 = partial(someFunc, b="I was added for free")
# Now call the already partially defined function "p1"
p1("Hello")
Result
Called with a:Hello and b:I was added for free

I found the correct solution to my question in the Flask documentation:
Context Processors
To inject new variables automatically into the context of a template, context processors exist in Flask. Context processors run before the template is rendered and have the ability to inject new values into the template context. A context processor is a function that returns a dictionary. The keys and values of this dictionary are then merged with the template context, for all templates in the app:
#app.context_processor
def inject_user():
return dict(user=g.user)
The context processor above makes a variable called user available in the template with the value of g.user. This example is not very interesting because g is available in templates anyways, but it gives an idea how this works.

Related

Flask Form Action is not referring to the variable

I have a form and am passing the variable as below using Jinja template
<form action = "/user_data/{{period}}" method="POST">
It is not redirecting required page /user_data/Oct-2022
But while just using {{period}} for testing in html page, variable is returning the result as Oct-2022. Not sure why the same variable is not getting passed in the form action.
Variable is printing as below in html page,
{{period}}
But it is not printing in the form,
<form action = "/user_data/{{period}}" method="POST">
This is the route method,
#app.route("/user_listing/<period>", methods = ['POST', 'GET'])
def user_data(period):
....
....
return render_template('user_data.html', period=period)
First we imported the Flask class. An instance of this class will be our WSGI application.
Next we create an instance of this class. The first argument is the name of the application’s module or package. If you are using a single module (as in this example), you should use name because depending on if it’s started as application or imported as module the name will be different ('main' versus the actual import name). This is needed so that Flask knows where to look for templates, static files, and so on. For more information have a look at the Flask documentation.
We then use the route() decorator to tell Flask what URL should trigger our function.
The function is given a name which is also used to generate URLs for that particular function, and returns the message we want to display in the user’s browser.

Include a simple function inside Django HTML template

I currently have a function called "copyright" (a dynamic copyright message) that I am trying to include into my base Django template, like below:
def copyright():
some code
some more code
print(finaloutput)
I have it sitting in my modules/utils.py which is in my assets directory which I have registered in my static directories.
I want to be able to call that function like {{ copyright }} straight in my top level base.html inside my main templates folder.
I have tried everything to ensure I am loading the staticfiles with no luck. Am I approaching this the wrong way?
Unfortunately almost everything you're doing here is wrong.
This has nothing to do with static files: as you said yourself, this is a dynamic function so isn't static by definition. Anyway, you can't put Python code in your assets directory. And finally, any function like this will always need to return the result, not print it.
What you need here is a template tag, which you put in your app's templatetags directory and register via the decorator:
#register.simple_tag
def copyright():
some code
some more code
return finaloutput
Then, load the tags in your template and call it as a tag, not a variable:
{% load utils %} # or whatever you called the file
...
{% copyright %}
See the template tags docs.
There are several ways to achieve your end goal, but nothing you are doing will get you there.
You can,
Use template tags.
Use context processors, in several different ways.
Use {{ view.function_name }} as-is in your templates if you are using class based generic views from Django.
Judging from how I think you have things set up, the fastest way could be to just pass in some context data in your views.
If you are using functional views, your code can look something like this:
def my_view(request):
def copyright():
return "copyright 2018"
return render('my_template.html', {'copyright': copyright})
If you are using class based generic views, you can simply modify your get_context_data.
class Home(TemplateView):
def get_context_data(self, *args, **kwargs):
ctx = super(TemplateView, self).get_context_data(self, *args, **kwargs)
ctx['copyright'] = self.copyright()
return ctx
def copyright(self):
return "copyright 2018"

Can't use .update() function on Django context in views?

I have a function that gets some base information in my views.py file, and I'm trying to update the context of each page using it by having it return a dictionary. However, using .update() on the context dictionary in the render() function doesn't seem to work.
Here's what I'm doing:
def getBaseInfo():
allPages = list(Page.objects.all())
primaryPages = allPages[:5]
secondaryPages = allPages[5:]
return {'p':primaryPages, 'p2':secondaryPages}
def index(request):
return render(request, 'pages/index.html', {}.update(getBaseInfo()))
However, nothing is sent to my templates. Thanks in advance!
Edit: I'm using Python 2.7.11
Firstly, if you wanted to use a base dictionary and add objects to that you should do so explicitly:
def index(request):
context = getBaseInfo()
context.update({'otherkey': 'othervalue'})
# or
context['otherkey'] = 'othervalue'
return(...)
However, there is no need to do this at all. Django already provides you a way of automatically providing shared context, and that is a context processor.
In fact your getBaseInfo() function is already almost a context processor - it just needs to accept the request parameter - so you just need to add it to the context_processors list in your TEMPLATES setting. Then all your templates will automatically get the values from that function.
You should do something like this:
def index(request):
allPages = list(Page.objects.all())
primaryPages = allPages[:5]
secondaryPages = allPages[5:]
return render(request, 'pages/index.html', {'p':primaryPages, 'p2':secondaryPages})
Other option should be to make getBaseInfo a #property for reusability and DRY purposes, or make the view class based template view and define reusable code as mixin. I prefer the latter, but it's entirely matter of personal choice.

Pass variables to all Jinja2 templates with Flask

I have a table in the navigation system of my webapp that will be populated with up-to-date information each time a page is rendered. How could I avoid putting the following code in each view?
def myview():
mydict = code_to_generate_dict()
return render_template('main_page.html',mydict=mydict)
mydict is used to populate the table. The table will show up on each page
You can use Flask's Context Processors to inject globals into your jinja templates
Here is an example:
#app.context_processor
def inject_dict_for_all_templates():
return dict(mydict=code_to_generate_dict())
To inject new variables automatically into the context of a template,
context processors exist in Flask. Context processors run before the
template is rendered and have the ability to inject new values into
the template context. A context processor is a function that returns a
dictionary. The keys and values of this dictionary are then merged
with the template context, for all templates in the app:
Write your own render method do keep yourself from repeating that code. Then call it whenever you need to render a template.
def render_with_dict(template):
mydict = code_to_generate_dict()
return render_template(template, mydict=mydict)
def myview():
return render_with_dict('main_page.html')

Inheriting context variables inside custom template tags

I have a django template with a context variable myVar, set in the view function.
This template also renders a custom simple template tag {% myTemplateTag %} that renders myTemplate.html
I want to use myVar inside the custom template tag that renders myTemplate.html.
Is there a way to inherit the context variables of my view function in the custom template tag? (without passing it explicitly as a parameter to the template tag)?
Using simple_tag
Using simple_tag, just set takes_context=True:
#register.simple_tag(takes_context=True)
def current_time(context, format_string):
timezone = context['timezone']
return your_get_current_time_method(timezone, format_string)
Using a custom template tag
Just use template.Variable.resolve(), ie.
foo = template.Variable('some_var').resolve(context)
See passing variables to the templatetag:
To use the Variable class, simply instantiate it with the name of the
variable to be resolved, and then call variable.resolve(context). So,
for example:
class FormatTimeNode(template.Node):
def __init__(self, date_to_be_formatted, format_string):
self.date_to_be_formatted = template.Variable(date_to_be_formatted)
self.format_string = format_string
def render(self, context):
try:
actual_date = self.date_to_be_formatted.resolve(context)
return actual_date.strftime(self.format_string)
except template.VariableDoesNotExist:
return ''
Variable resolution will throw a VariableDoesNotExist exception if it cannot resolve the string passed
to it in the current context of the page.
Might be useful too: setting a variable in the context.
Perhaps you could include the myTemplate.html file instead of rendering it with a special tag? Have you looked at the include tag? If you include myTemplate.html it will share the context with the one including it.

Categories

Resources