Pass variables to Tornado base templates - python

I have a base template base.html from which other templates inherit from.
After a user logs on I want to display their userID on navigation bar defined in base.html
So I have:
class CloseHandler(tornado.web.RequestHandler):
def get(self):
ui=db.users.find_one({"Username": ui0})
self.render("thanks.html" , ui1 = ui["Username"])
I also want to display the value of ui1 in the base template as: <p>{{ ui1 }}</p>
The only way round this is to move my navigation bar html code from base.html and insert it into every other template.
I however get this error:
NameError: global name 'ui1' is not defined
I've tried setting this as a global variable but it still gives the same error.
How could variables be used in different templates then?

I know this question is old, but I recommend creating a base class, that your handlers extend:
class BaseHandler(tornado.web.RequestHandler):. This will allow you to add functions available to all your handlers.
Next you can extend the tornado.web.RequestHandler.get_template_namespace() function, and add your global variables to the namespace:
# class BaseHandler
def get_template_namespace(self):
namespace = super(BaseHandler, self).get_template_namespace()
namespace.update({
'username': self.get_current_username() # or however you retrieve users
})
return namespace
Everything passed to the namespace is provided to self.render in all your handlers.
Now you can access {{ username }} in either base.html or the view extending it.

Related

How to create a global variable for render_template()?

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.

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"

How to access to get URL address by name in Django at model file (like {{ url 'urlname' }} at template)

Need to access URL by name at model, can't just hardcode it. Need it for error message for a new object creating. Any suggestions?
Update: Just need to put url to error message, not reverse
Your question is not totally clear, but I think you are asking about the reverse function.
You can define get_absolute_url method in your model and than access it in other model's methods. Check https://docs.djangoproject.com/en/2.1/ref/models/instances/#get-absolute-url
I suggest you use a template tag. You can build one for your model and avoid polluting the model about stuff not related to the domain level and keep the presentation level to the template.
Check the docs here on how add a templatetags your app.: https://docs.djangoproject.com/en/2.1/howto/custom-template-tags/
Here a snippet of code to use as starting point for your url generation
from django import template
register = template.Library()
#register.simple_tag(takes_context=True)
def url_for_object(context, object):
# you have both the context and the object available to
# generate your url here
url = ....
return url
In your template use
{% url_for_object my_object %}

tornado render argument in template

I feel like I hacked this into tornado and it is in poor form. The goal was to get an error message down into a template. This error message would only need to be within one handler (responsible for that same page).
The template line:
{% if errormsg is not None %}
<div class="alert-warning">{{ errormsg }}</div>
{% end %}
The relevant handler section:
if auth:
self.set_current_user(username)
self.redirect(self.get_argument("next",u"/"))
else:
self.errormsg = "Login Failed"
self.render("login.html", errormsg=self.errormsg)
At this point I was getting global namespace error messages on the page when errormsg was not set to something.
NameError: global name 'errormsg' is not defined
The workaround I found was to muck around with the global render function within my BaseHandler (I do not like this one bit):
def render(self, template, **kwargs):
if hasattr(self, 'errormsg'):
kwargs['errormsg'] = self.errormsg
else:
kwargs['errormsg'] = None
super(BaseHandler, self).render(template, **kwargs)
This basically adds the errormsg to every render now. Is there a correct way to do this that doesn't mess with the global render function?
Thanks!
Edit:
Because what I'm actually trying to do is pass different/multiple, non-standard kwargs parameters into inherited handlers, I actually really think I was looking for a better way to test, in this case errormsg, within the template context.
{% if 'errormsg' in globals() %}
This still feels pretty hacked into place since this issue is the first time globals actually showed up at all while working with tornado.
I do like extending render for setting kwargs default values for all inherited handlers (what it is actually for). I think this may also be similar to how self.current_user works.
Overriding render() is officially supported, but it's a bit cleaner to override get_template_namespace instead: http://www.tornadoweb.org/en/stable/web.html#tornado.web.RequestHandler.get_template_namespace
Or, if errormsg is an attribute of the RequestHandler, you can just access handler.errormsg in the template - the handler variable is always set to the current RequestHandler.

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