Pass variables to Flask's render_template - python

I want to pass multiple variables from my Flask view to my Jinja template. Right now, I can only pass one. How do I pass multiple variable when rendering a template?
#app.route("/user/<user_id>/post/<post_id>", methods=["GET", "POST"])
def im_research(user_id, post_id):
user = mongo.db.Users.find_one_or_404({'ticker': user_id})
return render_template('post.html', user=user)

The render_template function takes any number of keyword arguments. Query for each of the things you need in the template, then pass the results of each query as another argument to render_template.
#app.route("/user/<user_id>/post/<post_id>")
def im_research(user_id, post_id):
user = get_user_by_id(id)
post = get_user_post_by_id(user, id)
return render_template("post.html", user=user, post=post)
Python also has a built-in locals() function that will return a dict of all locally defined variables. This is not recommended as it may pass too much and obscures what specifically is being passed.
#app.route("/user/<user_id>/post/<post_id>")
def im_research(user_id, post_id):
user = get_user_by_id(id)
post = get_user_post_by_id(user, id)
return render_template("post.html", **locals())

return render_template('im.html', user= None, content = xxx, timestamp = xxx)
You can pass as many variables as you need.
The api
excerpt:
flask.render_template(template_name_or_list, **context)
Renders a
template from the template folder with the given context.
Parameters: template_name_or_list – the name of the template to be
rendered, or an iterable with template names the first one existing
will be rendered context – the variables that should be available in
the context of the template.

It is also possible to pass a list to render_template's context variables, and refer to its elements with Jinja's syntax in HTML.
example.py
mylist = [user, content, timestamp]
return render_template('exemple.html', mylist=l)
exemple.html
...
<body>
{% for e in mylist %}
{{e}}
{% endfor %}
</body>
...

Related

Access a variable in HTML from a .py file [duplicate]

base.html is used as the base template for all other pages. base.html has the navigation bar and in the navigation bar, I want to show the number of messages the user received. Thus, I need to have a variable like {{number_of_messages}} in the base.html.
However, how should I pass this variable to it? Every template extends base.html and is rendered by a function. I don't think returning number_of_messages in all functions is a good way. Is there better way to implement this? How can I pass this variable to all templates?
You can use tags.
#myproject/myproject/templatetags/tags.py
from django import template
register = template.Library()
#register.simple_tag
def number_of_messages(request):
return _number
In your Base.html
{% load tags %}
{% number_of_messages request %}
Have a look at:
https://docs.djangoproject.com/en/dev/ref/templates/api/#django.template.RequestContext
As long as:
you use the render shortcut in your view (or otherwise take care to use a RequestContext to render your response)
have django.contrib.auth.context_processors.auth in your TEMPLATE_CONTEXT_PROCESSORS setting (as it is by default)
...then you have the current request's User (or AnonymousUser) instance available in your template as {{ user }} ...I am guessing from there you may be able to access the number of messages directly?
Or perhaps you are using Django's messages framework?
This comes with it's own context processor which (as long as you use render or RequestContext) will make a {{ messages }} var (containing the messages for current user) available in your templates. For 'number of messages' you can do {{ messages|length }}
If none of these built-in options provide what you need you can either:
make your own template context processor which will run for every request and make additional variables available to all templates (when rendered with a RequestContext)
make your own template tag which can be used only where needed... of course if this is used in your base.html and all templates inherit from base.html then it's still going to run for every page.
I find the simplest steps to passing variables to your base templates in django is to add a context_processor.py file like so:
In your app create context_processors.py and declare your variables e.g.:
# context_processors.py
def message_processor(request):
if request.user.is_authenticated:
no_msgs = request.user.profile.msgs
else:
no_msgs = 0
return {
'messages' : no_msgs
}
Then register your process or under TEMPLATES in your settings.py file:
TEMPLATES = [
{
...
'context_processors': [
...
# custom
'appname.context_processors.message_processor',
],
},
},
]
And then you will be able to get that variable anywhere in your app as:
{{ messages }}
If you want the variable in really all the views, then a custom template context processor is probably the best option.
https://docs.djangoproject.com/en/dev/ref/templates/api/#subclassing-context-requestcontext
If you want the variable only in some of the views, then you can make those views call a common function that populates the common variables, something like this:
def some_view(request):
params = _common_params(request)
params.update({
# params specific to .some_view
})
return render_to_response('path/to/template, params)
or create a custom decorator like this:
from functools import wraps
def render_with_params():
def _inner(view_method):
def _decorator(request, *args, **kwargs):
params = _common_params(request)
(template_path, view_params) = view_method(request, *args, **kwargs)
params.update(view_params)
return render_to_response(template_path, params, context_instance=RequestContext(request))
return wraps(view_method)(_decorator)
return _inner
#render_with_params()
def some_view(request):
params = { ... }
return ('path/to/template', params)

Django: custom template tag which takes 2 variables

I want to have a custom template tag which takes two variables as arguments. This is what I have in my template:
{% load accountSum %}
{% accountSum 'account_id' 'account_type' %}
I have read that you need to load the context of these variables but I have not found a working way. So my question is, how do I define the custom template tag in templatetags/accountSum.py?
This is what I have so far:
from django import template
register = template.Library()
def accountSum(context, account_id, account_type):
account_id = context[account_id]
account_type = context[account_type]
# do something with the data
# return the modified data
register.simple_tag(takes_context=True)(accountSum)
You have misunderstood the usage of template tags, I have read that you need to load the context of these variables... context is only required if you need to access/modify the existing context, not if you only need to return the calculated value from the provided arguments.
So, in your case, what you only need is this:
#register.simple_tag
def accountSum(account_id, account_type):
# your calculation here...
return # your return value here
Django document has a more detailed explanation and example that you can follow -- Simple tags
Or, if your intention is to take the context value account_id and account_type and return a modified value on each call, you can simply omit taking the arguments, and simply do this:
#register.simple_tag(take_context=True)
def accountSum(context):
account_id = context['account_id']
account_type = context['account_type']
# do your calculation here...
return # your modified value
Then you can simply call {% accountSum %} in your template.
Or, if you want to dynamically take context content as arguments:
#register.simple_tag(take_context=True)
def accountSum(context, arg1, arg2):
arg1 = context[arg1]
arg2 = context[arg2]
# calculation here...
return # modified value...
And passing arguments in template using string like:
{% accountSum 'account_id' 'account_type' %}
I hope this helps you understand how to use template tags in your case.
updated
What I meant is this (as you don't need to access the context, what you really need is taking arguments just like usual):
#register.simple_tag
def accountSum(arg1, arg2):
# your calculation here...
return # your return value here
and use this in your template:
{% accountSum account.account_id account.account_type %}

Passing Arguments to ModelView edit template in flask-admin

I am trying to learn more about Flask by building a CMS. I am using flask-admin to add the posts, images etc.
I have managed to override textarea with ckeditor. But I want to pass the paths of the images in the static folder to ckeditor image plugin.
I can't figure out how to pass parameters to my edit.html template.
Here's the code:
class TestAdmin(ModelView):
form_overrides = dict(text=forms.CustomTextAreaField)
create_template = 'edit.html'
edit_template = 'edit.html'
From the documentation of flask-admin I have found that _template_args can used to pass parameters to the template. But I can't figure out how.
What is the exact way to do that?
You have to override the views to change _template_args.
class TestAdmin(ModelView):
form_overrides = dict(text=forms.CustomTextAreaField)
create_template = 'edit.html'
edit_template = 'edit.html'
#expose('/edit/', methods=('GET', 'POST'))
def edit_view(self):
self._template_args['foo'] = 'bar'
return super(TestAdmin, self).edit_view()
If you want to pass some global value to templates, you can use a context_processor (http://flask.pocoo.org/docs/templating/#context-processors).
#app.context_processor
def inject_paths():
# you will be able to access {{ path1 }} and {{ path2 }} in templates
return dict(path1='x', path2='y')
To anyone finding this in 2023+ – you can do it now by overriding _get_list_extra_args method:
class YourView(ModelView):
list_template = "custom_template.html"
def _get_list_extra_args(self):
view_args = super()._get_list_extra_args()
view_args.extra_args["foo"] = "bar"
return view_args
Here we can control extra_args dict. Flask-Admin's index_view() passes it straight to the template as is, so you can modify it and use it in custom_template.html:
<div>
{{ extra_args.foo }} {# will render "bar" #}
</div>

Passing variables to template based on db

I am trying to add a feature to my app that would allow me to enable/disable the "Call Me" button based on whether or not I am at [home|the office]. I created a model in the database called setting, it looks like this:
class setting(models.Model):
key = models.CharField(max_length=200)
value = models.CharField(max_length=200)
Pretty simple. There is currently one row, available, the value of it is the string True. I want to be able to transparently pass variables to the templates like this:
{% if available %}
<!-- Display button -->
{% else %}
<!-- Display grayed out button -->
{% endif %}
Now, I could add logic to every view that would check the database, and pass the variable to the template, but I am trying to stay DRY.
What is the best way to do this?
UPDATE
I created a context processor, and added it's path to the TEMPLATE_CONTEXT_PROCESSORS, but it is not being passed to the template
def available(request):
available = Setting.objects.get(key="available")
if open.value == "True":
return {"available":True}
else:
return {}
UPDATE TWO
If you are using the shortcut render_to_response, you need to pass an instance of RequestContext to the function.
from the django documentation:
If you're using Django's render_to_response() shortcut to populate a template with the contents of a dictionary, your template will be passed a Context instance by default (not a RequestContext). To use a RequestContext in your template rendering, pass an optional third argument to render_to_response(): a RequestContext instance. Your code might look like this:
def some_view(request):
# ...
return render_to_response('my_template.html',
my_data_dictionary,
context_instance=RequestContext(request))
Many thanks for all the help!
Write a custom context processor.

how to pass id from url to post_save_redirect in urls.py

I have several objects in the database. Url to edit an object using the generic view looks like site.com/cases/edit/123/ where 123 is an id of the particular object. Consider the cases/url.py contents:
url(r'edit/(?P<object_id>\d{1,5})/$', update_object, { ... 'post_save_redirect': ???}, name = 'cases_edit'),
where update_object is a generic view. How to construct the post_save_redirect to point to site.com/cases/edit/123/. My problem is, that I don't know how to pass the id of the object to redirect function. I tried something like:
'post_save_redirect': 'edit/(?P<object_id>\d{1,5})/'
'post_save_redirect': 'edit/' + str(object_id) + '/'
but obviously none of these work. reverse function was suggested, but how to pass the particular id?
'post_save_redirect': reverse('cases_edit', kwargs = {'object_id': ???})
{% url %} in the temple also requires passing the id of the particular object. The id can be passed via extra_context:
extra_context = {'object_id': ???}
In all the cases the problem is to get object_id from the url.
regards
chriss
In short what you need to do is wrap the update_object function.
def update_object_wrapper(request, object_id, *args, **kwargs):
redirect_to = reverse('your object edit url name', object_id)
return update_object(request, object_id, post_save_redirect=redirect_to, *args, **kwargs)
First, read up on the reverse function.
Second, read up on the {% url %} tag.
You use the reverse function in a view to generate the expected redirect location.
Also, you should be using the {% url %} tag in your templates.
Right from the docs at: https://docs.djangoproject.com/en/dev/ref/generic-views/#django-views-generic-create-update-create-object
post_save_redirect may contain dictionary string formatting, which will be interpolated against the object's field attributes. For example, you could use post_save_redirect="/polls/%(slug)s/".

Categories