{{ }} is not getting parsed by pyjade as expected with django - django

I have line of pyjade
a.js-track(data-track-data="{\"Job ID\":\"{{ job_details|get_or_na:'id' }}\",\"Job Title\":\"{{ job_details|get_or_na:'title' }}\",\"Company Name\":\"{{ job_details|get_or_na:'organization'|get_or_na:'name' }}\"}", data-track-dynamic-attrs="[\"Stakeholder\"]",href="{% url 'job_detail' job_details.title|slugify job_details.id %}")
which is being rendered as
<a href="/job/operations-manager/b1ac846e-6834-40c4-8bcf-122c093820b1/" data-track-data="{"Job ID":"{{ job_details|get_or_na:'id' }}","Job Title":"{{ job_details|get_or_na:'title' }}","Company Name":"{{ job_details|get_or_na:'organization'|get_or_na:'name' }}"}" data-track-dynamic-attrs="["Stakeholder"]" class="js-track">
I expect it to {{ }} being replaced by intended values rather than being rendered with html.
I am using 4.0.0 version of pyjade here as templating language.

Try to use #{value}
And for the conditions try to create a variable before the line so you can have more control
- var condition = inline_condition
p= condition

Related

Django ignore TemplateSyntaxError. Vue Syntax

I'm building a pwa on top of django.
In the pwa.html I use valid vue syntax:
{{ counter() }}
or
{{ el| removehtml() | truncate(40) }}
Works flawless in a non Django project.
I get an TemplateSyntaxError on runserver, how can I ignore this, cause this is valid for vue syntax.
I found 2 solutions:
either in vue with delimiters:
el: '#app',
delimiters: ['[[', ']]'],
data: {
message: ...
}
...
than in template [[ vuefunc() ]] instead of default {{ vuefunct() }}
or with django verbatim
{% verbatim %}
{{ vuefunct() }}
{% endverbatim %}
Please note that Django does not use Jinja. It has its own template syntax, explained here in the documentation.
If you have any exposure to other text-based template languages, such
as Smarty or Jinja2, you should feel right at home with Django’s
templates.
The syntax may look like Jinja, but the functions could be different.

WTForms use quotes in Jinja2

I've got the following WTForms class:
from flask_wtf import FlaskForm
from wtforms import SelectField
class MonitorLevel(FlaskForm):
monitor = SelectField('Monitor', choices=MONITOR_CHOICES)
Which can be rendered using the following jinja2-code:
{{ form.monitor() }}
However, I want to execute a JS-script when the value changes, so I've added the following:
{{ form.monitor(**{'onchange': 'sendForm();'}) }}
Which works fine, but now I want to pass a variable (which is a string), as an argument:
{{ form.monitor(**{'onchange': 'sendForm("{}");'.format(variable)}) }}
However, this renders as:
<select id="monitor" name="monitor" onchange="sendForm("name");">...</select>
So, I tried to escape this using the safe function, but this doesn't work. I've also tried to escape the quote by: \", but that doesn't work as well.
Any ideas of adding a quote in the value of the dict?
Thanks in advance,
From the WTForms documentation https://wtforms.readthedocs.io/en/2.3.x/widgets/#widget-building-utilities :
WTForms uses MarkupSafe to escape unsafe HTML characters before rendering. You can mark a string using markupsafe.Markup to indicate that it should not be escaped.
Without using markupsafe.Markup I had the same error:
{{ input_field(**{'#click': '"show=true"'})|safe }}
gives
<input #click=""show=true"">
instead of
<input #click="'show=true'">
Using the markupsafe module inside the Jinja2 template:
{{ input_field(**{'#click': markupsafe.Markup("show=true")})|safe }}
does the job:
<input #click="show=true">
Be careful: WTForm encloses the string in the double quotes ", so you need to take a usual care about the " inside your string.
BAD WAY
{{ input_field(**{'#click': markupsafe.Markup('console.log("show=true")')})|safe }}
will result in
<input #click="console.log("show=true")">
which is wrong (one string is not inside the other).
GOOD WAY
{{ input_field(**{'#click': markupsafe.Markup("console.log('show=true')")})|safe }}
will give
<input #click="console.log('show=true')"
This behavior is normal, WTForms use escape(s, quote=True) to render HTML attributes values (escape documentation)
You can look function def html_params(**kwargs): on Github directly fore more informations.
Basically you don't have to change your code because :
Javascript still works like a charm, your browser transforms HTML entities on the fly (sendForm() is run onchange).
onchange="sendForm("name");" is NOT valid HTML attribute if you print it without escape(s, quote=True).

How can I access items within a ndb query object clientside?

I'm working with appengine, django and webapp2 and am sending a query object clientside such that
{{ exercise_steps }}
returns
Query(kind='ExStep')
and
{{ exercise_steps.count }}
returns 4
I'm trying to chuck the variable exercise_steps into some javascript code and need to iterate through the items in a javascript (not a django) loop but I cannot seem to access the items.
I've tried {{ exercise_steps|0 }}, {{ exercise_steps[0] }}, {{ exercise_steps.0 }} but it returns nothing. I know I can do this with a django loop but is there a way I can access the objects within the query with a javascript loop using something like
for (var i = 0; i < {{exercise_steps.count}}; i++) {
console.log({{ exercise_steps.i.location }})
}
You can't mix client side code and template code... by the time the javascript runs, your python code is already executed. You are not sending a python object to the javascript - it's executed when the HTML is generated.
You need to recreate array in JS, or have an ajax call return an array from python.
var steps = [
{% for step in exercise_steps %}
{{ step.location }}{% if not forloop.last %},{% endif %}
{% endfor %}]; // now your python iterable is a JS array.

Django: Allow user to submit valid HTML in form field

With Django, is it possible for users to submit HTML in a form field, save it, and then render the HTML in the template?
An example is a user adding a link within a textfield that should then be rendered as an a tag within the rest of the text.
The user would input something like :
this is a site called SO.
The SO link would be a link instead of rendering it as text.
Django escapes by default. You can mark a string as safe via a filter or tag to prevent the auto escaping behavior.
{{ my_text_with_html|safe }}
{% autoescape off %}
{{ my_test_with_html }}
{% endautoescape %}
If you accept user inputted html, you'll want to sanitize it so they can't write scripts and such.. for that, just search python html sanitizing and apply it before sending the data to the template.
Python HTML sanitizer / scrubber / filter
You can tell Django the HTML is safe by marking it with the appropriate filter:
{{ variable|safe }}
You can also use the autoescape tag to disable the autoescaping:
{% autoescape off %}
{{ variable }}
{% endautoescape %}
However, in case you are enabling this feature for other (unknown) users, I highly recommend using something else, since HTML can be quite a pain to properly sanitize from Javascript or other HTML-things you don't want (e.g., on*-arguments etc). Django actually ships with basic support for some markup languages you can provide to your users. I guess markdown is being the most popular.

Django - use template tag and 'with'?

I have a custom template tag:
def uploads_for_user(user):
uploads = Uploads.objects.filter(uploaded_by=user, problem_upload=False)
num_uploads = uploads.count()
return num_uploads
and I'd like to do something like this, so I can pluralize properly:
{% with uploads_for_user leader as upload_count %}
{{ upload_count }} upload{{ upload_count|pluralize }}
{% endwith %}
However, uploads_for_user leader doesn't work in this context, because the 'with' tag expects a single value - Django returns:
TemplateSyntaxError at /upload/
u'with' expected format is 'value as name'
Any idea how I can get round this?
You could turn it into a filter:
{% with user|uploads_for as upload_count %}
While a filter would still work, the current answer to this question would be to use assignment tags, introduced in Django 1.4.
So the solution would be very similar to your original attempt:
{% uploads_for_user leader as upload_count %}
{{ upload_count }} upload{{ upload_count|pluralize }}
Update: As per the docs assignment tags are deprecated since Django 1.9 (simple_tag can now store results in a template variable and should be used instead)
In Django 1.9 django.template.Library.assignment_tag() is depricated:
simple_tag can now store results in a template variable and should be used instead.
So, now simple tag we can use like a:
It’s possible to store the tag results in a template variable rather
than directly outputting it. This is done by using the as argument
followed by the variable name. Doing so enables you to output the
content yourself where you see fit:
{% get_current_time "%Y-%m-%d %I:%M %p" as the_time %}
<p>The time is {{ the_time }}.</p>