Frozen-Flask, url_for() in Jinja2 and string concatenation during build - flask

When running Flask normally, everything described below works absolutely fine.
When running a build in Frozen-Flask however, I run into the following issue:
In my Jinja2 template I tried this at first, where I'm having to create the route strings of many url_for() functions from multiple sources:
{% macro my_macro(foo) %}
Link text
{% endmacro %}
Although this runs fine in Flask, when I do a build with Frozen-Flask I get the following error:
werkzeug.routing.BuildError: Could not build url for endpoint 'index_'. Did you mean...
As you can see, the value of foo is missing.
So I thought that's annoying, but maybe the string concatenation of 'index_' ~ foo happens after the url_for() is parsed. So to test my theory, I tried this instead:
{% macro my_macro(foo) %}
{% set route = 'index_' ~ foo %}
Link text
{% endmacro %}
But I get the exact same error. Exactly. So, as if it's setting the value of set route before concatenating the value of the foo variable onto the end of 'index_', and passing that incomplete value through to url_for().
However, if I substitute foo for 'foo' (so now foo is a string not a variable) then the concatenation works fine. So I can't concatenate string with string variables in Frozen-Flask?
Is there any way around this or is this maybe a possible bug in Frozen-Flask?
Update: It appears to be an issue with data coming from routes.py where I have return render_template('my_template.html', foo='bar'). This foo variable, although it is being passed through to the base template where in turn it is passed through to the macro (it can be output to prove the data present and correct) this data however cannot, it seems, be used to dynamically create a route for use by url_for().

i think will help you a simple line code
Link Text
considering foo as string only will be concatenate, no with string1+strin2, only using html printing.

Related

How to pass full data as it is without getting converted via GET?

I'm trying to manipulate my form's action via js with the following code:
form.action = "{% url 'search.html' phrase='developer' %}"
The problem is, it converts my data to weird signs instead of passing it as it is.
http://localhost:8000/%7B%%20url%20'search.html'%20phrase='developer'%20%%7D?
How can I avoid this convertion ?
The problem is, it converts my data to weird signs instead of passing it as it is.
No, it does not convert anything. It here simply uses {% url 'search.html' phrase='developer' %} as the real URL, and since a URL can not use {, %, etc. as characters, it uses percent encoding [wiki].
Indeed, if you use for example a tool like url-encode-decode, then you will see that it will decode this to {% url 'search.html' phrase='developer' %}.
The reason this happens is because you apparently do not render that part of the template. This is for example the case if you use a JavaScript file that you thus serve as a static file.
You thus should make sure that the {% url … %} part is located in the template: a file where the template engine will convert this to a URL, not in a (static) file where Django never passes this to the template engine.

How to add a dynamically concatenated file name for "include" tag in Selmer (Clojure)?

I'm new to Clojure. My issue is regarding selmer templating library.
What I want to do is apply a variable for following way. But its not working;
{% include {{right-page}} %} ------- X
(here right-page is a concatenated sting for a target file name)
Any targets for including in selmer must currently be known when selmer compiles the template, which it does without the passed in data. This means that, given the template:
template.html_template:
{% include right-page %}
and the clojure code:
(selmer/render-file template.html_template
{right-page "some/other/template/file.html_template})
You can expect an exception. As for a work around, you might consider
(selmer/render-file template.html_template
{right-page (selmer/render-file
"some/other/template/file.html_template {})})
or something similar.
You will, of course have to update template.html to include the already rendered text, and to disable escaping, like so:
template.html_template:
{{right-page|safe}}
If right-page is a valid string you're passing to the page, I think this will work for you
{% include right-page %}

How django's template tag "include" work with None

I'm using an include tag in my templates like this:
{% include fragment_variable %}
where fragment_variable is a context variable that might not exist. I wonder if it will blow up when fragment_variable is not in context variables or is None.
NOTE: actually I tested this code in two different environments (both using Django 1.7) and got two different results (one blew up with some stack trace for templates lookups and the other just failed silently). So I'm curious if there's a setting in django that controls how template rendering behaves when "include" tag can't find a valid template.
{% if fragment_variable %}
{% include fragment_variable %}
{% else %}
<!-- something else -->
{% endif %}
Edit:
Since you are using django version prior to 1.8, take a look at the setting TEMPLATE_STRING_IF_INVALID, it sets the default value for invalid variables.
Also take a look at How invalid variables are handled:
Generally, if a variable doesn’t exist, the template system inserts
the value of the engine’s string_if_invalid configuration option,
which is set to '' (the empty string) by default.
This behavior is slightly different for the if, for and regroup
template tags. If an invalid variable is provided to one of these
template tags, the variable will be interpreted as None. Filters are
always applied to invalid variables within these template tags.
For that matter, I still consider using if is the best exercise.

Template Contexts not recognized from external file (Django)

So, I've been editing a website and have many JavaScript functions that utilize the Contexts that the views.py file passes to the page. Until now, these functions have been contained in the base.html file and so have been loaded onto every page directly. However, to make things cleaner, I copy and pasted all the functions to an external .js file. Now, rather than use the contexts, the functions consider them to be literal strings.
Example:
$('#title').text('{{ event.name }}');
The above line will actually set the text of the element to say "{{ event.name }}" rather than the name of the event. Any ideas on how to fix this? I really don't want to keep these functions in the base file where they can be seen by anyone who inspects the page source.
It doesn't matter if you put your javascript functions in an external file or in your base.html it would still get exposed to the user. Only a minification of the file would actually help to trick the user from seeing the actual values but with javascript all your code is public.
Why you're having this problem is because when you rendered the javascript inline (in your base.html) you had access to the template context.
This is no longer the case and the Django template engine doesn't interpolate your {{ event.name }} anymore.
The problem you're facing as well is a good one. You should never mix and match javascript with Djangos template language or any template language for that matter and the only way of fixing it is to
a) start pulling the values from the DOM ie. render a proper DOM
b) to start to fetch the values from the server, traditionally using AJAX.
And the smallest example that I can muster at the moment is below:
Your view:
def my_django_view(request):
return HttpResponse(json.dumps({'meaningoflife':42}), mimetype='application/json')
Your HTML
<input type="hidden" id="myMeaning" value="{{ meaningoflife }}" />
Your javascript
var meaning = document.querySelector('#myMeaning').value;
alert(meaning); //should alert 42.
In your view you return some form of render_to_response which takes a template argument and a context argument. What the render_to_response function does is read your template, and replace all {{ placeholders }} with the values passed via the context dictionary.
Templates are essentially a complex version of this
"""
<h1>{{ person.name }}</h1>
<p>{{ person.phone_number }}</p>
""".format(person)
The problem is the templating engine does not know files specified by a scripts src attribute is actually a Django template. To fix this don't use the script src attribute. Instead do something like this.
<!--base.html-->
<h1>Site Title</h1>
<p>Some content</p>
<script>
{% include 'jsfile.js' %}
</script>
Using the include statement should do the trick.

Django tag better way to resolve string with variable

I have a tag that has a variable that is a string with an embeded variable. Is there a better way to evaluate it than:
{% custom_extends "this_{{is.a.test}}" %}
-- backend
string_with_variable = "this_{{is.a.test}}"
result = Template(string_with_variable).render(context)
This works, but i wasn't sure if there was any lower level function that does the same.
I guess I'm a little dense this morning. Is the problem getting some_custom to accept a param that has an embedded variable reference in it? Or is it that you want the param to some_custom to be resolved before it is passed (which is a more general situation)?
If it's the latter case, checkout the Expr templatetag. With that you can do something like:
{% expr "this_"+is.a.test as some_string %}
{% some_custom some_string param %}
Update for comment:
Since this is for {% extends %}, which, as you correctly point out, needs to be the very first line in the file, simply set a variable in your view, e.g. my_custom_template = "this_"+is.a.test+".html" and pass it in with the context. Then in your template you can say {% custom_extends my_custom_template %} and you're good to go.
Of course, this assumes that your custom_extends tag does variable resolution like the normal extends tag does, but that's an easy thing to add to your code. See django/template/loader_tags.py, ExtendsNode.get_parent() for how the core code does it.
The answer is no. As of right now if you want to resolve/render a string you need to instantiate a Template and call render with your context.
result = Template("this_{{is.a.test}}").render(context)